From 5b8b27b1bfa7dbe70b9d2a20c35d759633dfef42 Mon Sep 17 00:00:00 2001 From: trydofor Date: Mon, 24 Jun 2024 16:51:50 +0800 Subject: [PATCH 01/51] =?UTF-8?q?=E2=9C=A8=20tinytask=20runs=20eval=20not?= =?UTF-8?q?=20expression=20#261?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- observe/docs | 2 +- observe/mirana | 2 +- .../tiny/task/schedule/conf/TaskerProp.java | 2 +- .../service/impl/TinyTaskExecServiceImpl.java | 26 +++--- .../wings-tinytask-define-79.properties | 2 +- .../wings/silencer/modulate/RuntimeMode.java | 79 +++++++++---------- .../bean/SilencerCurseConfiguration.java | 3 +- .../silencer/modulate/RuntimeModeTest.java | 32 +++++++- 8 files changed, 85 insertions(+), 63 deletions(-) diff --git a/observe/docs b/observe/docs index c30360bc3..0b40402e7 160000 --- a/observe/docs +++ b/observe/docs @@ -1 +1 @@ -Subproject commit c30360bc3a91f2e1fb12c621add778d3c70f61c1 +Subproject commit 0b40402e75ddfbce7a20b92c8bb310c518819a0e diff --git a/observe/mirana b/observe/mirana index 4468526da..699fc3723 160000 --- a/observe/mirana +++ b/observe/mirana @@ -1 +1 @@ -Subproject commit 4468526dab95bb10df5bcabded576aeae224acd0 +Subproject commit 699fc372399272fb68014c27028013841f1f83d6 diff --git a/radiant/tiny-task/src/main/java/pro/fessional/wings/tiny/task/schedule/conf/TaskerProp.java b/radiant/tiny-task/src/main/java/pro/fessional/wings/tiny/task/schedule/conf/TaskerProp.java index 0edfd40c3..4ef31c3eb 100644 --- a/radiant/tiny-task/src/main/java/pro/fessional/wings/tiny/task/schedule/conf/TaskerProp.java +++ b/radiant/tiny-task/src/main/java/pro/fessional/wings/tiny/task/schedule/conf/TaskerProp.java @@ -60,7 +60,7 @@ public boolean notTaskerApps() { } /** - * RunMode(product|test|develop|local), Comma separated, ignore case, default all, + * RunMode(product|test|develop|local), `!test`,`-test` means not test, Comma separated, ignore case, default all, * use Default config if null or empty. * * @see pro.fessional.wings.silencer.modulate.RunMode diff --git a/radiant/tiny-task/src/main/java/pro/fessional/wings/tiny/task/service/impl/TinyTaskExecServiceImpl.java b/radiant/tiny-task/src/main/java/pro/fessional/wings/tiny/task/service/impl/TinyTaskExecServiceImpl.java index 8168df3f4..071e42007 100644 --- a/radiant/tiny-task/src/main/java/pro/fessional/wings/tiny/task/service/impl/TinyTaskExecServiceImpl.java +++ b/radiant/tiny-task/src/main/java/pro/fessional/wings/tiny/task/service/impl/TinyTaskExecServiceImpl.java @@ -204,9 +204,10 @@ private boolean relaunch(long id) { return false; } - if (notEnable(td.getEnabled(), id) - || notApps(td.getTaskerApps(), id) - || notRuns(td.getTaskerRuns(), id)) { + final String key = td.getPropkey(); + if (notEnable(td.getEnabled(), id, key) + || notApps(td.getTaskerApps(), id, key) + || notRuns(td.getTaskerRuns(), id, key)) { return false; } @@ -216,7 +217,6 @@ private boolean relaunch(long id) { // temp save before schedule to avoid kill saveNextExec(next, td); - final String key = td.getPropkey(); final boolean fast = BoxedCastUtil.orTrue(td.getTaskerFast()); final var taskScheduler = fast ? TaskSchedulerHelper.Fast() : TaskSchedulerHelper.Scheduled(); @@ -246,7 +246,7 @@ private boolean relaunch(long id) { final String taskerInfo = key + " launch"; final String noticeConf = td.getNoticeConf(); - String exitMsg = "relaunch task id=" + id; + String exitMsg = "relaunch task key=" + key; NoticeExec notice = null; Set ntcWhen = Collections.emptySet(); try { @@ -305,35 +305,35 @@ private boolean relaunch(long id) { } // - private boolean notEnable(Boolean b, long id) { + private boolean notEnable(Boolean b, long id, String key) { if (BoxedCastUtil.orTrue(b)) { return false; } - log.info("skip task for not enabled, id={}", id); + log.info("skip task for not enabled, id={}, prop={}", id, key); return true; } - private boolean notApps(String apps, long id) { + private boolean notApps(String apps, long id, String key) { if (StringUtils.isEmpty(apps)) return false; for (String s : arrayOrNull(apps, true)) { if (s.trim().equals(appName)) return false; } - log.info("skip task for not apps={}, cur={}, id={}", apps, appName, id); + log.info("skip task for not apps={}, cur={}, id={}, prop={}", apps, appName, id, key); return true; } - private boolean notRuns(String runs, long id) { + private boolean notRuns(String runs, long id, String key) { if (StringUtils.isEmpty(runs)) return false; final RunMode rmd = RuntimeMode.getRunMode(); if (rmd == RunMode.Nothing) { - log.info("skip task for not runs={}, cur is null, id={}", runs, id); + log.info("skip task for not runs={}, cur is Nothing, id={}, prop={}", runs, id, key); return true; } - if (!RuntimeMode.hasRunMode(arrayOrNull(runs, true))) { - log.info("skip task for not runs={}, cur={}, id={}", runs, rmd, id); + if (!RuntimeMode.voteRunMode(runs)) { + log.info("skip task for not runs={}, cur={}, id={}, prop={}", runs, rmd, id, key); return true; } diff --git a/radiant/tiny-task/src/main/resources/wings-conf/wings-tinytask-define-79.properties b/radiant/tiny-task/src/main/resources/wings-conf/wings-tinytask-define-79.properties index 4260a14d9..90dfd3fa5 100644 --- a/radiant/tiny-task/src/main/resources/wings-conf/wings-tinytask-define-79.properties +++ b/radiant/tiny-task/src/main/resources/wings-conf/wings-tinytask-define-79.properties @@ -27,7 +27,7 @@ ## use Default config if null or empty. wings.tiny.task.define[default].tasker-apps=${spring.application.name} -## RunMode(product|test|develop|local), Comma separated, ignore case, default all, +## RunMode(product|test|develop|local), `!test`,`-test` means not test, Comma separated, ignore case, default all, ## use Default config if null or empty. wings.tiny.task.define[default].tasker-runs= diff --git a/wings/silencer-curse/src/main/java/pro/fessional/wings/silencer/modulate/RuntimeMode.java b/wings/silencer-curse/src/main/java/pro/fessional/wings/silencer/modulate/RuntimeMode.java index a0464340b..a0e8fce89 100644 --- a/wings/silencer-curse/src/main/java/pro/fessional/wings/silencer/modulate/RuntimeMode.java +++ b/wings/silencer-curse/src/main/java/pro/fessional/wings/silencer/modulate/RuntimeMode.java @@ -2,7 +2,9 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import pro.fessional.mirana.cond.StaticFlag; +import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.atomic.AtomicReference; /** @@ -11,32 +13,23 @@ */ public class RuntimeMode { - private static final AtomicReference unitTest = new AtomicReference<>(null); + private static volatile @NotNull RunMode runMode = RunMode.Nothing; + private static volatile @NotNull ApiMode apiMode = ApiMode.Nothing; - protected RuntimeMode(@Nullable RunMode run, @Nullable ApiMode api) { - if (run != null) runMode = run; - if (api != null) apiMode = api; - } + private static final ConcurrentHashMap runVote = new ConcurrentHashMap<>(); + private static final ConcurrentHashMap apiVote = new ConcurrentHashMap<>(); - public static boolean isUnitTest() { - Boolean b = unitTest.get(); - if (b == null) { - b = false; - for (StackTraceElement el : new RuntimeException().getStackTrace()) { - if (el.getClassName().startsWith("org.junit.")) { - b = true; - break; - } - } - unitTest.set(b); + protected RuntimeMode(@Nullable RunMode run, @Nullable ApiMode api) { + if (run != null) { + runMode = run; + runVote.clear(); + } + if (api != null) { + apiMode = api; + apiVote.clear(); } - return b; } - @NotNull - private static RunMode runMode = RunMode.Nothing; - - @NotNull public static RunMode getRunMode() { return runMode; @@ -56,7 +49,7 @@ public static boolean hasRunMode(RunMode... modes) { public static boolean isRunMode(CharSequence mode) { if (mode == null) return false; - return contains(mode.toString(), runMode.name()); + return StaticFlag.vote(runMode.name(), mode.toString()) > 0; } public static boolean hasRunMode(CharSequence... modes) { @@ -66,8 +59,9 @@ public static boolean hasRunMode(CharSequence... modes) { return false; } - @NotNull - private static ApiMode apiMode = ApiMode.Nothing; + public static boolean voteRunMode(String votes) { + return runVote.computeIfAbsent(votes, k -> StaticFlag.hasVote(runMode.name(), k)); + } @NotNull public static ApiMode getApiMode() { @@ -88,7 +82,7 @@ public static boolean hasApiMode(ApiMode... modes) { public static boolean isApiMode(CharSequence mode) { if (mode == null) return false; - return contains(mode.toString(), apiMode.name()); + return StaticFlag.vote(apiMode.name(), mode.toString()) > 0; } public static boolean hasApiMode(CharSequence... modes) { @@ -98,22 +92,27 @@ public static boolean hasApiMode(CharSequence... modes) { return false; } - private static boolean contains(String tstr, String ostr) { - final int tlen = tstr.length(); - int toff = 0; - for (int i = 0; i < tlen; i++) { - if (Character.isJavaIdentifierPart(tstr.charAt(i))) { - toff = i; - break; - } - } + public static boolean voteApiMode(String votes) { + return apiVote.computeIfAbsent(votes, k -> StaticFlag.hasVote(apiMode.name(), k)); + } - final int olen = ostr.length(); - if (tstr.regionMatches(true, toff, ostr, 0, olen)) { - final int idx = toff + olen; - return idx == tlen || !Character.isJavaIdentifierPart(tstr.charAt(idx)); - } + // // - return false; + private static final AtomicReference unitTest = new AtomicReference<>(null); + + public static boolean isUnitTest() { + Boolean b = unitTest.get(); + if (b == null) { + b = false; + for (StackTraceElement el : new RuntimeException().getStackTrace()) { + if (el.getClassName().startsWith("org.junit.")) { + b = true; + break; + } + } + unitTest.set(b); + } + return b; } + } diff --git a/wings/silencer-curse/src/main/java/pro/fessional/wings/silencer/spring/bean/SilencerCurseConfiguration.java b/wings/silencer-curse/src/main/java/pro/fessional/wings/silencer/spring/bean/SilencerCurseConfiguration.java index f4fb28ec9..594467e19 100644 --- a/wings/silencer-curse/src/main/java/pro/fessional/wings/silencer/spring/bean/SilencerCurseConfiguration.java +++ b/wings/silencer-curse/src/main/java/pro/fessional/wings/silencer/spring/bean/SilencerCurseConfiguration.java @@ -155,8 +155,7 @@ else if (exists.contains(name)) { @Bean @ConditionalWingsEnabled public RuntimeMode runtimeMode(SilencerRuntimeProp prop) { - - log.info("Silencer spring-auto runtimeMode"); + log.info("Silencer spring-auto RuntimeMode, runMode=" + prop.getRunMode() + ", apiMode=" + prop.getApiMode()); return new RuntimeMode(prop.getRunMode(), prop.getApiMode()) {}; } } diff --git a/wings/silencer-curse/src/test/java/pro/fessional/wings/silencer/modulate/RuntimeModeTest.java b/wings/silencer-curse/src/test/java/pro/fessional/wings/silencer/modulate/RuntimeModeTest.java index 9618fb663..1aa96b871 100644 --- a/wings/silencer-curse/src/test/java/pro/fessional/wings/silencer/modulate/RuntimeModeTest.java +++ b/wings/silencer-curse/src/test/java/pro/fessional/wings/silencer/modulate/RuntimeModeTest.java @@ -15,8 +15,7 @@ public class RuntimeModeTest { @Test @TmsLink("C11011") void isRunMode() { - final RunMode rm = RuntimeMode.getRunMode(); - Assertions.assertEquals(RunMode.Local, rm); + Assertions.assertEquals(RunMode.Local, RuntimeMode.getRunMode()); Assertions.assertFalse(RuntimeMode.isRunMode("")); Assertions.assertFalse(RuntimeMode.isRunMode("localx")); Assertions.assertTrue(RuntimeMode.isRunMode("local")); @@ -24,17 +23,42 @@ void isRunMode() { Assertions.assertTrue(RuntimeMode.isRunMode(" local ")); Assertions.assertTrue(RuntimeMode.isRunMode(" local, ")); Assertions.assertTrue(RuntimeMode.isRunMode(" local, ")); + + Assertions.assertTrue(RuntimeMode.voteRunMode(" local, ")); + Assertions.assertTrue(RuntimeMode.voteRunMode(" !develop, ")); + Assertions.assertTrue(RuntimeMode.voteRunMode(" !develop,!test, ")); + Assertions.assertFalse(RuntimeMode.voteRunMode(" !local, ")); + + new RuntimeMode(RunMode.Test, null) {}; + Assertions.assertEquals(RunMode.Test, RuntimeMode.getRunMode()); + Assertions.assertFalse(RuntimeMode.isRunMode("")); + Assertions.assertFalse(RuntimeMode.isRunMode("testx")); + Assertions.assertTrue(RuntimeMode.isRunMode("test")); + Assertions.assertTrue(RuntimeMode.isRunMode("test ")); + Assertions.assertTrue(RuntimeMode.isRunMode(" test ")); + Assertions.assertTrue(RuntimeMode.isRunMode(" test, ")); + Assertions.assertTrue(RuntimeMode.isRunMode(" test, ")); + + Assertions.assertFalse(RuntimeMode.voteRunMode("")); + Assertions.assertTrue(RuntimeMode.voteRunMode(" test, ")); + Assertions.assertTrue(RuntimeMode.voteRunMode(" !local, ")); + Assertions.assertFalse(RuntimeMode.voteRunMode(" !develop, !test, ")); + Assertions.assertFalse(RuntimeMode.voteRunMode(" !test, ")); } @Test @TmsLink("C11012") void isApiMode() { - final ApiMode am = RuntimeMode.getApiMode(); - Assertions.assertEquals(ApiMode.Nothing, am); + Assertions.assertEquals(ApiMode.Nothing, RuntimeMode.getApiMode()); Assertions.assertTrue(RuntimeMode.isApiMode("nothing")); Assertions.assertTrue(RuntimeMode.isApiMode("nothing ")); Assertions.assertTrue(RuntimeMode.isApiMode(" nothing ")); Assertions.assertTrue(RuntimeMode.isApiMode(" nothing, ")); Assertions.assertTrue(RuntimeMode.isApiMode(" nothing, ")); + + Assertions.assertTrue(RuntimeMode.voteApiMode(" nothing, ")); + Assertions.assertTrue(RuntimeMode.voteApiMode(" !online, ")); + Assertions.assertTrue(RuntimeMode.voteApiMode(" !online,!sandbox ")); + Assertions.assertFalse(RuntimeMode.voteApiMode(" !nothing ")); } } From f5e2bc1313912954840d65ed856eb57266c5cf2b Mon Sep 17 00:00:00 2001 From: trydofor Date: Mon, 24 Jun 2024 21:07:35 +0800 Subject: [PATCH 02/51] =?UTF-8?q?=F0=9F=A6=81=20May=20the=20False=20be=20w?= =?UTF-8?q?ith=20you?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- changelog.md | 4 ++-- readme-zh.md | 2 +- readme.md | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/changelog.md b/changelog.md index 01afd6cf1..40308cd6f 100644 --- a/changelog.md +++ b/changelog.md @@ -8,7 +8,7 @@ Help Yourself [Commits] and [History] Notable [Changes] in [WingsDoc] -[History]: https://github.com/trydofor/pro.fessional.wings/tags -[Commits]: https://github.com/trydofor/pro.fessional.wings/commits/develop +[History]: https://github.com/trydofor/professional-wings/tags +[Commits]: https://github.com/trydofor/professional-wings/commits/develop [Changes]: https://wings.fessional.pro/9-example/9a.wings-change/ [WingsDoc]: https://wings.fessional.pro/ diff --git a/readme-zh.md b/readme-zh.md index 22d52d301..d0b1c9f9b 100644 --- a/readme-zh.md +++ b/readme-zh.md @@ -37,7 +37,7 @@ ```bash ## ① 获取源码,成功后进入项目目录 git clone --depth 1 https://github.com/\ -trydofor/pro.fessional.wings.git +trydofor/professional-wings.git ## ② 安装依赖,可跳过,支持java8编译 # asdf shell java temurin-8.0.412+8 git submodule update --remote --init diff --git a/readme.md b/readme.md index c4a808482..82abec8f4 100644 --- a/readme.md +++ b/readme.md @@ -37,7 +37,7 @@ ```bash ## (1) get source code git clone --depth 1 https://github.com/\ -trydofor/pro.fessional.wings.git +trydofor/professional-wings.git ## (2) install dependency using java8 # asdf shell java temurin-8.0.412+8 git submodule update --remote --init From 909a38529a63b5b6a20b4a355642765fc805646f Mon Sep 17 00:00:00 2001 From: trydofor Date: Tue, 25 Jun 2024 14:31:55 +0800 Subject: [PATCH 03/51] =?UTF-8?q?=E2=9C=A8=20conf=5Fruntime=20size=20and?= =?UTF-8?q?=20enable=20#262?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- observe/docs | 2 +- .../autogen/tables/WinMailSenderTable.java | 4 +- .../07-mail/2020-10-27v01-tiny_mail.sql | 4 +- .../2021-10-26u02-task-tune.sql | 0 .../2021-10-26v02-task-tune.sql | 0 .../06-task/2020-10-26v01-tiny_task.sql | 4 +- .../faceless/jooqgen/WingsJavaGenerator.java | 10 ++ .../wings/faceless/flywave/WingsRevision.java | 5 +- .../2021-12-20v01-journal-trg-insert.sql | 2 +- .../00-init/2019-05-12v01-version-journal.sql | 12 +- .../01-light/2019-05-20v01-light-commit.sql | 4 +- .../master/2022-0601v01-test.sql | 8 +- .../perm/impl/WarlockPermServiceImpl.java | 13 +- .../perm/impl/WarlockRoleServiceImpl.java | 13 +- .../autogen/tables/SysConstantEnumTable.java | 3 +- .../autogen/tables/SysStandardI18nTable.java | 3 +- .../autogen/tables/WinConfRuntimeTable.java | 28 ++-- .../autogen/tables/WinPermEntryTable.java | 4 +- .../autogen/tables/WinRoleEntryTable.java | 4 +- .../autogen/tables/WinRoleGrantTable.java | 3 +- .../autogen/tables/WinUserAuthnTable.java | 4 +- .../autogen/tables/WinUserBasisTable.java | 4 +- .../autogen/tables/WinUserGrantTable.java | 3 +- .../autogen/tables/WinUserLoginTable.java | 3 +- .../tables/daos/WinConfRuntimeDao.java | 21 ++- .../tables/interfaces/IWinConfRuntime.java | 12 +- .../autogen/tables/pojos/WinConfRuntime.java | 93 +++++++++++++ .../tables/records/WinConfRuntimeRecord.java | 123 ++++++++++++------ .../service/conf/RuntimeConfService.java | 105 +++++++++------ .../conf/impl/RuntimeConfServiceImpl.java | 53 +++++--- .../04-conf-size/2021-10-26u03-conf-size.sql | 5 + .../04-conf-size/2021-10-26v03-conf-size.sql | 5 + .../05-conf/2020-10-25v01-conf_runtime.sql | 13 +- .../service/conf/RuntimeConfServiceTest.java | 19 ++- 34 files changed, 409 insertions(+), 180 deletions(-) rename radiant/tiny-task/src/main/resources/wings-flywave/branch/somefix/{03-v32-130 => 03-task-tune}/2021-10-26u02-task-tune.sql (100%) rename radiant/tiny-task/src/main/resources/wings-flywave/branch/somefix/{03-v32-130 => 03-task-tune}/2021-10-26v02-task-tune.sql (100%) create mode 100644 wings/warlock/src/main/resources/wings-flywave/branch/somefix/04-conf-size/2021-10-26u03-conf-size.sql create mode 100644 wings/warlock/src/main/resources/wings-flywave/branch/somefix/04-conf-size/2021-10-26v03-conf-size.sql diff --git a/observe/docs b/observe/docs index 0b40402e7..6d6c110a6 160000 --- a/observe/docs +++ b/observe/docs @@ -1 +1 @@ -Subproject commit 0b40402e75ddfbce7a20b92c8bb310c518819a0e +Subproject commit 6d6c110a640c4bbfc56b19fd7b177f690d758afc diff --git a/radiant/tiny-mail/src/main/java-gen/pro/fessional/wings/tiny/mail/database/autogen/tables/WinMailSenderTable.java b/radiant/tiny-mail/src/main/java-gen/pro/fessional/wings/tiny/mail/database/autogen/tables/WinMailSenderTable.java index 8b9948194..186013336 100644 --- a/radiant/tiny-mail/src/main/java-gen/pro/fessional/wings/tiny/mail/database/autogen/tables/WinMailSenderTable.java +++ b/radiant/tiny-mail/src/main/java-gen/pro/fessional/wings/tiny/mail/database/autogen/tables/WinMailSenderTable.java @@ -36,7 +36,7 @@ @Generated( value = { "https://www.jooq.org", - "jOOQ version:3.18.7", + "jOOQ version:3.18.9", "schema version:2020102701" }, comments = "This class is generated by jOOQ" @@ -311,7 +311,6 @@ public WinMailSenderTable rename(Table name) { public String getSeqName() { return "win_mail_sender"; } - /** * alias asW3 @@ -321,7 +320,6 @@ public String getSeqName() { public WinMailSenderTable getAliasTable() { return asW3; } - /** * The colDel delete_dt condition diff --git a/radiant/tiny-mail/src/main/resources/wings-flywave/master/07-mail/2020-10-27v01-tiny_mail.sql b/radiant/tiny-mail/src/main/resources/wings-flywave/master/07-mail/2020-10-27v01-tiny_mail.sql index b7cfb5b77..6b560734a 100644 --- a/radiant/tiny-mail/src/main/resources/wings-flywave/master/07-mail/2020-10-27v01-tiny_mail.sql +++ b/radiant/tiny-mail/src/main/resources/wings-flywave/master/07-mail/2020-10-27v01-tiny_mail.sql @@ -13,13 +13,13 @@ CREATE TABLE `win_mail_sender` ( `mail_bcc` VARCHAR(500) NOT NULL DEFAULT '' COMMENT 'mail bcc, comma-separated', `mail_reply` VARCHAR(200) NOT NULL DEFAULT '' COMMENT 'mail reply', `mail_subj` VARCHAR(400) NOT NULL DEFAULT '' COMMENT 'mail subject', - `mail_text` TEXT NULL DEFAULT NULL COMMENT 'mail content', + `mail_text` TEXT NULL COMMENT 'mail content', `mail_html` TINYINT(1) NOT NULL DEFAULT '1' COMMENT 'whether HTML email', `mail_file` VARCHAR(9000) NOT NULL DEFAULT '' COMMENT 'attachment name and path map, json format', `mail_mark` VARCHAR(200) NOT NULL DEFAULT '' COMMENT 'space-separated business key', `mail_date` DATETIME(3) NOT NULL DEFAULT '1000-01-01' COMMENT 'scheduled mail send (sys)', `last_send` DATETIME(3) NOT NULL DEFAULT '1000-01-01' COMMENT 'previous send (sys)', - `last_fail` TEXT NULL DEFAULT NULL COMMENT 'previous fail info', + `last_fail` TEXT NULL COMMENT 'previous fail info', `last_done` DATETIME(3) NOT NULL DEFAULT '1000-01-01' COMMENT 'previous success (sys)', `last_cost` INT(11) NOT NULL DEFAULT '0' COMMENT 'mills of previous send cost', `next_send` DATETIME(3) NOT NULL DEFAULT '1000-01-01' COMMENT 'next send datetime (sys)', diff --git a/radiant/tiny-task/src/main/resources/wings-flywave/branch/somefix/03-v32-130/2021-10-26u02-task-tune.sql b/radiant/tiny-task/src/main/resources/wings-flywave/branch/somefix/03-task-tune/2021-10-26u02-task-tune.sql similarity index 100% rename from radiant/tiny-task/src/main/resources/wings-flywave/branch/somefix/03-v32-130/2021-10-26u02-task-tune.sql rename to radiant/tiny-task/src/main/resources/wings-flywave/branch/somefix/03-task-tune/2021-10-26u02-task-tune.sql diff --git a/radiant/tiny-task/src/main/resources/wings-flywave/branch/somefix/03-v32-130/2021-10-26v02-task-tune.sql b/radiant/tiny-task/src/main/resources/wings-flywave/branch/somefix/03-task-tune/2021-10-26v02-task-tune.sql similarity index 100% rename from radiant/tiny-task/src/main/resources/wings-flywave/branch/somefix/03-v32-130/2021-10-26v02-task-tune.sql rename to radiant/tiny-task/src/main/resources/wings-flywave/branch/somefix/03-task-tune/2021-10-26v02-task-tune.sql diff --git a/radiant/tiny-task/src/main/resources/wings-flywave/master/06-task/2020-10-26v01-tiny_task.sql b/radiant/tiny-task/src/main/resources/wings-flywave/master/06-task/2020-10-26v01-tiny_task.sql index 06e0dce68..63a43c4a3 100644 --- a/radiant/tiny-task/src/main/resources/wings-flywave/master/06-task/2020-10-26v01-tiny_task.sql +++ b/radiant/tiny-task/src/main/resources/wings-flywave/master/06-task/2020-10-26v01-tiny_task.sql @@ -9,7 +9,7 @@ CREATE TABLE `win_task_define` ( `autorun` TINYINT(1) NOT NULL DEFAULT '1' COMMENT 'whether to auto register and start', `version` INT(11) NOT NULL DEFAULT '0' COMMENT 'version number, higher overrides lower one', `tasker_bean` VARCHAR(300) NOT NULL DEFAULT '' COMMENT 'beans annotated by TinyTasker, formatted as Class#method', - `tasker_para` TEXT NULL DEFAULT NULL COMMENT 'parameters of the task, object array in json format', + `tasker_para` TEXT NULL COMMENT 'parameters of the task, object array in json format', `tasker_name` VARCHAR(200) NOT NULL DEFAULT '' COMMENT 'task name, used for notice and log, shortClassName#method', `tasker_fast` TINYINT(1) NOT NULL DEFAULT '1' COMMENT 'whether light task, fast execution, completed in seconds', `tasker_apps` VARCHAR(500) NOT NULL DEFAULT '' COMMENT 'belong to applications, comma-separated, default spring.application.name', @@ -52,7 +52,7 @@ CREATE TABLE `win_task_result` ( `task_key` VARCHAR(200) NOT NULL DEFAULT '' COMMENT 'conf file key, auto-generated', `task_app` VARCHAR(300) NOT NULL DEFAULT '' COMMENT 'belong to applications, comma-separated', `task_pid` INT(11) NOT NULL DEFAULT '0' COMMENT 'belong to jvm pid', - `exit_data` TEXT NULL DEFAULT NULL COMMENT 'return (json) or exception (stacktrace)', + `exit_data` TEXT NULL COMMENT 'return (json) or exception (stacktrace)', `exit_fail` TINYINT(1) NOT NULL DEFAULT '0' COMMENT 'whether fail', `time_exec` DATETIME(3) NOT NULL DEFAULT '1000-01-01' COMMENT 'datetime of exec (sys)', `time_exit` DATETIME(3) NOT NULL DEFAULT '1000-01-01' COMMENT 'datetime of done/fail (sys)', diff --git a/wings/faceless-codegen/src/main/java/pro/fessional/wings/faceless/jooqgen/WingsJavaGenerator.java b/wings/faceless-codegen/src/main/java/pro/fessional/wings/faceless/jooqgen/WingsJavaGenerator.java index deb75adab..ff67a767a 100644 --- a/wings/faceless-codegen/src/main/java/pro/fessional/wings/faceless/jooqgen/WingsJavaGenerator.java +++ b/wings/faceless-codegen/src/main/java/pro/fessional/wings/faceless/jooqgen/WingsJavaGenerator.java @@ -8,6 +8,8 @@ import org.jooq.impl.DAOImpl; import org.jooq.meta.CatalogDefinition; import org.jooq.meta.ColumnDefinition; +import org.jooq.meta.DataTypeDefinition; +import org.jooq.meta.Database; import org.jooq.meta.Definition; import org.jooq.meta.SchemaDefinition; import org.jooq.meta.TableDefinition; @@ -64,6 +66,13 @@ public class WingsJavaGenerator extends JavaGenerator { private GeneratorStrategy proxyStrategy = null; + @Override + protected String getJavaTypeReference(Database db, DataTypeDefinition type, JavaWriter out) { + return super.getJavaTypeReference(db, type, out); + // https://github.com/jOOQ/jOOQ/issues/16853 + // columnTypeRef = columnTypeRef.replace("_utf8mb4\\'\\'","('')"); + } + @Override public GeneratorStrategy getStrategy() { final GeneratorStrategy wrapper = super.getStrategy(); @@ -249,6 +258,7 @@ else if (colType.contains("int")) { // 🦁<<< } + @Override // Confirm the replacement code and diff it public void generateDao(TableDefinition table, JavaWriter out) { super.generateDao(table, out); diff --git a/wings/faceless-flywave/src/main/java/pro/fessional/wings/faceless/flywave/WingsRevision.java b/wings/faceless-flywave/src/main/java/pro/fessional/wings/faceless/flywave/WingsRevision.java index ee85643d4..77ac1407a 100644 --- a/wings/faceless-flywave/src/main/java/pro/fessional/wings/faceless/flywave/WingsRevision.java +++ b/wings/faceless-flywave/src/main/java/pro/fessional/wings/faceless/flywave/WingsRevision.java @@ -13,15 +13,18 @@ public enum WingsRevision implements RevisionRegister { V00_19_0512_02_Fix227(2019_0512_02L, "fix v227", "branch/somefix/01-v227-fix", "wings/faceless-flywave/src/main/resources/wings-flywave"), V01_19_0520_01_IdLog(2019_0520_01L, "lightId and journal", "master/01-light", "wings/faceless/src/main/resources/wings-flywave"), V01_19_0521_01_EnumI18n(2019_0521_01L, "enum and i18n", "branch/feature/01-enum-i18n", "wings/faceless/src/main/resources/wings-flywave"), + V03_20_1023_01_AuthEnum(2020_1023_01L, "auth enum", "master/03-enum", "wings/warlock/src/main/resources/wings-flywave"), V04_20_1024_01_UserLogin(2020_1024_01L, "user auth login", "master/04-auth", "wings/warlock/src/main/resources/wings-flywave"), V04_20_1024_02_RolePermit(2020_1024_02L, "user role permit", "master/04-auth", "wings/warlock/src/main/resources/wings-flywave"), V05_20_1025_01_ConfRuntime(2020_1025_01L, "runtime config", "master/05-conf", "wings/warlock/src/main/resources/wings-flywave"), V06_20_1026_01_TinyTask(2020_1026_01L, "tiny task", "master/06-task", "radiant/tiny-task/src/main/resources/wings-flywave"), V07_20_1027_01_TinyMail(2020_1027_01L, "tiny mail", "master/07-mail", "radiant/tiny-mail/src/main/resources/wings-flywave"), + V01_21_0918_01_FixAuthn(2021_0918_01L, "fix authn", "branch/somefix/01-authn-fix", "wings/warlock/src/main/resources/wings-flywave"), V02_21_1220_01_Fix242(2021_1220_01L, "fix v242.201", "branch/somefix/02-v242-201", "wings/faceless-flywave/src/main/resources/wings-flywave"), - V03_21_1026_02_Fix32130(2021_1026_02L, "fix v3.2.130", "branch/somefix/03-v32-130", "radiant/tiny-task/src/main/resources/wings-flywave"), + V03_21_1026_02_FixTaskTune(2021_1026_02L, "fix task tune", "branch/somefix/03-task-tune", "radiant/tiny-task/src/main/resources/wings-flywave"), + V01_21_1026_03_FixConfSize(2021_1026_03L, "fix conf size", "branch/somefix/04-conf-size", "wings/warlock/src/main/resources/wings-flywave"), V90_22_0601_01_TestSchema(2022_0601_01L, "test v1 schema", "master", "wings/testing-faceless/src/main/resources/wings-flywave/"), V90_22_0601_02_TestRecord(2022_0601_02L, "test v2 record", "master", "wings/testing-faceless/src/main/resources/wings-flywave/"), diff --git a/wings/faceless-flywave/src/main/resources/wings-flywave/branch/somefix/02-v242-201/2021-12-20v01-journal-trg-insert.sql b/wings/faceless-flywave/src/main/resources/wings-flywave/branch/somefix/02-v242-201/2021-12-20v01-journal-trg-insert.sql index 3258eb571..222a0017c 100644 --- a/wings/faceless-flywave/src/main/resources/wings-flywave/branch/somefix/02-v242-201/2021-12-20v01-journal-trg-insert.sql +++ b/wings/faceless-flywave/src/main/resources/wings-flywave/branch/somefix/02-v242-201/2021-12-20v01-journal-trg-insert.sql @@ -2,4 +2,4 @@ ALTER TABLE `sys_schema_journal` ADD COLUMN `ddl_instbl` TEXT NOT NULL COMMENT 'trace DDL of insert' AFTER `commit_id`, ADD COLUMN `ddl_instrg` TEXT NOT NULL COMMENT 'trigger DDL of insert' AFTER `ddl_instbl`, - ADD COLUMN `log_insert` DATETIME(3) NOT NULL DEFAULT '1000-01-01 00:00:00.000' COMMENT 'applied datetime of insert' AFTER `ddl_deltrg`; + ADD COLUMN `log_insert` DATETIME(3) NOT NULL DEFAULT '1000-01-01' COMMENT 'applied datetime of insert' AFTER `ddl_deltrg`; diff --git a/wings/faceless-flywave/src/main/resources/wings-flywave/master/00-init/2019-05-12v01-version-journal.sql b/wings/faceless-flywave/src/main/resources/wings-flywave/master/00-init/2019-05-12v01-version-journal.sql index e2dcc405b..00a55956f 100644 --- a/wings/faceless-flywave/src/main/resources/wings-flywave/master/00-init/2019-05-12v01-version-journal.sql +++ b/wings/faceless-flywave/src/main/resources/wings-flywave/master/00-init/2019-05-12v01-version-journal.sql @@ -4,9 +4,9 @@ CREATE TABLE `sys_schema_version` ( `revision` BIGINT(20) NOT NULL COMMENT 'version + build', `create_dt` DATETIME(3) NOT NULL DEFAULT NOW(3) COMMENT 'created datetime', - `modify_dt` DATETIME(3) NOT NULL DEFAULT '1000-01-01 00:00:00.000' ON UPDATE NOW(3) COMMENT 'modified datetime', + `modify_dt` DATETIME(3) NOT NULL DEFAULT '1000-01-01' ON UPDATE NOW(3) COMMENT 'modified datetime', `commit_id` BIGINT(20) NOT NULL COMMENT 'commit id', - `apply_dt` DATETIME(3) NOT NULL DEFAULT '1000-01-01 00:00:00.000' COMMENT 'applied datetime', + `apply_dt` DATETIME(3) NOT NULL DEFAULT '1000-01-01' COMMENT 'applied datetime', `comments` VARCHAR(500) NOT NULL DEFAULT '' COMMENT 'sql path', `upto_sql` TEXT NOT NULL COMMENT 'upgrade script', `undo_sql` TEXT NOT NULL COMMENT 'downgrade script', @@ -17,7 +17,7 @@ CREATE TABLE `sys_schema_version` ( CREATE TABLE `sys_schema_journal` ( `table_name` VARCHAR(100) NOT NULL COMMENT 'plain table name', `create_dt` DATETIME(3) NOT NULL DEFAULT NOW(3) COMMENT 'created datetime', - `modify_dt` DATETIME(3) NOT NULL DEFAULT '1000-01-01 00:00:00.000' ON UPDATE NOW(3) COMMENT 'modified datetime', + `modify_dt` DATETIME(3) NOT NULL DEFAULT '1000-01-01' ON UPDATE NOW(3) COMMENT 'modified datetime', `commit_id` BIGINT(20) NOT NULL COMMENT 'commit id', `ddl_instbl` TEXT NOT NULL COMMENT 'trace DDL of insert', `ddl_instrg` TEXT NOT NULL COMMENT 'trigger DDL of insert', @@ -25,9 +25,9 @@ CREATE TABLE `sys_schema_journal` ( `ddl_updtrg` TEXT NOT NULL COMMENT 'trigger DDL of update', `ddl_deltbl` TEXT NOT NULL COMMENT 'trace DDL of delete', `ddl_deltrg` TEXT NOT NULL COMMENT 'trigger DDL of delete', - `log_insert` DATETIME(3) NOT NULL DEFAULT '1000-01-01 00:00:00.000' COMMENT 'applied datetime of insert', - `log_update` DATETIME(3) NOT NULL DEFAULT '1000-01-01 00:00:00.000' COMMENT 'applied datetime of update', - `log_delete` DATETIME(3) NOT NULL DEFAULT '1000-01-01 00:00:00.000' COMMENT 'applied datetime of delete', + `log_insert` DATETIME(3) NOT NULL DEFAULT '1000-01-01' COMMENT 'applied datetime of insert', + `log_update` DATETIME(3) NOT NULL DEFAULT '1000-01-01' COMMENT 'applied datetime of update', + `log_delete` DATETIME(3) NOT NULL DEFAULT '1000-01-01' COMMENT 'applied datetime of delete', PRIMARY KEY (`table_name`) USING BTREE ) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COMMENT ='102/Table Trigger'; diff --git a/wings/faceless/src/main/resources/wings-flywave/master/01-light/2019-05-20v01-light-commit.sql b/wings/faceless/src/main/resources/wings-flywave/master/01-light/2019-05-20v01-light-commit.sql index e8dda7ad1..cceb2eb66 100644 --- a/wings/faceless/src/main/resources/wings-flywave/master/01-light/2019-05-20v01-light-commit.sql +++ b/wings/faceless/src/main/resources/wings-flywave/master/01-light/2019-05-20v01-light-commit.sql @@ -13,8 +13,8 @@ CREATE TABLE `sys_commit_journal` ( `create_dt` DATETIME(3) NOT NULL DEFAULT NOW(3) COMMENT 'created datetime', `event_name` VARCHAR(200) NOT NULL COMMENT 'event name', `target_key` VARCHAR(200) NOT NULL DEFAULT '' COMMENT 'target data', - `login_info` TEXT COMMENT 'login info: agent, terminal', - `other_info` TEXT COMMENT 'other info: biz index data', + `login_info` TEXT NULL COMMENT 'login info: agent, terminal', + `other_info` TEXT NULL COMMENT 'other info: biz index data', PRIMARY KEY (`id`) ) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COMMENT ='104/Data Changeset'; diff --git a/wings/testing-faceless/src/main/resources/wings-flywave/master/2022-0601v01-test.sql b/wings/testing-faceless/src/main/resources/wings-flywave/master/2022-0601v01-test.sql index e2e7f359f..6c144bb2a 100644 --- a/wings/testing-faceless/src/main/resources/wings-flywave/master/2022-0601v01-test.sql +++ b/wings/testing-faceless/src/main/resources/wings-flywave/master/2022-0601v01-test.sql @@ -5,8 +5,8 @@ CREATE TABLE `tst_sharding` ( `modify_dt` DATETIME(3) NOT NULL DEFAULT '1000-01-01' ON UPDATE NOW(3) COMMENT 'modified datetime', `delete_dt` DATETIME(3) NOT NULL DEFAULT '1000-01-01' COMMENT 'logic deleted datetime', `commit_id` BIGINT(20) NOT NULL COMMENT 'commit id', - `login_info` TEXT COMMENT 'login info: agent, terminal', - `other_info` TEXT COMMENT 'other info: biz index data', + `login_info` TEXT NULL COMMENT 'login info: agent, terminal', + `other_info` TEXT NULL COMMENT 'other info: biz index data', `language` INT(11) NOT NULL DEFAULT 1020111 COMMENT 'StandardLanguage', PRIMARY KEY (`id`) ) ENGINE = InnoDB @@ -18,8 +18,8 @@ CREATE TABLE `tst_sharding_postfix` ( `modify_dt` DATETIME(3) NOT NULL DEFAULT '1000-01-01' ON UPDATE NOW(3) COMMENT 'modified datetime', `delete_dt` DATETIME(3) NOT NULL DEFAULT '1000-01-01' COMMENT 'logic deleted datetime', `commit_id` BIGINT(20) NOT NULL COMMENT 'commit id', - `login_info` TEXT COMMENT 'login info: agent, terminal', - `other_info` TEXT COMMENT 'other info: biz index data', + `login_info` TEXT NULL COMMENT 'login info: agent, terminal', + `other_info` TEXT NULL COMMENT 'other info: biz index data', `language` INT(11) NOT NULL DEFAULT 1020111 COMMENT 'StandardLanguage', PRIMARY KEY (`id`) ) ENGINE = InnoDB diff --git a/wings/warlock-bond/src/main/java/pro/fessional/wings/warlock/service/perm/impl/WarlockPermServiceImpl.java b/wings/warlock-bond/src/main/java/pro/fessional/wings/warlock/service/perm/impl/WarlockPermServiceImpl.java index a215eefba..353514113 100644 --- a/wings/warlock-bond/src/main/java/pro/fessional/wings/warlock/service/perm/impl/WarlockPermServiceImpl.java +++ b/wings/warlock-bond/src/main/java/pro/fessional/wings/warlock/service/perm/impl/WarlockPermServiceImpl.java @@ -25,7 +25,6 @@ import java.util.ArrayList; import java.util.Collection; import java.util.Collections; -import java.util.HashMap; import java.util.List; import java.util.Map; @@ -130,11 +129,9 @@ public void create(@NotNull String scopes, @NotNull Collection acts) { winPermEntryDao.insert(pos); }); - wingsTableCudHandler.handle(this.getClass(), Cud.Create, t, () -> { - Map> field = new HashMap<>(); - field.put(t.Id.getName(), pos.stream().map(WinPermEntry::getId).toList()); - return field; - }); + wingsTableCudHandler.handle(this.getClass(), Cud.Create, t, field -> + field.put(t.Id.getName(), pos.stream().map(WinPermEntry::getId).toList()) + ); } public void modify(long permId, @NotNull String remark) { @@ -153,7 +150,9 @@ public void modify(long permId, @NotNull String remark) { }); if (rct > 0) { - wingsTableCudHandler.handle(this.getClass(), Cud.Update, t, field -> field.put(t.Id.getName(), List.of(permId))); + wingsTableCudHandler.handle(this.getClass(), Cud.Update, t, field -> + field.put(t.Id.getName(), List.of(permId)) + ); } } } diff --git a/wings/warlock-bond/src/main/java/pro/fessional/wings/warlock/service/perm/impl/WarlockRoleServiceImpl.java b/wings/warlock-bond/src/main/java/pro/fessional/wings/warlock/service/perm/impl/WarlockRoleServiceImpl.java index 87dc7c7e6..ec9ac5d3e 100644 --- a/wings/warlock-bond/src/main/java/pro/fessional/wings/warlock/service/perm/impl/WarlockRoleServiceImpl.java +++ b/wings/warlock-bond/src/main/java/pro/fessional/wings/warlock/service/perm/impl/WarlockRoleServiceImpl.java @@ -27,7 +27,6 @@ import pro.fessional.wings.warlock.service.perm.WarlockRoleService; import java.util.Collections; -import java.util.HashMap; import java.util.List; import java.util.Map; @@ -140,11 +139,9 @@ public long create(@NotNull String name, String remark) { return id; }); - wingsTableCudHandler.handle(this.getClass(), Cud.Create, t, () -> { - Map> field = new HashMap<>(); - field.put(t.Id.getName(), List.of(rid)); - return field; - }); + wingsTableCudHandler.handle(this.getClass(), Cud.Create, t, field -> + field.put(t.Id.getName(), List.of(rid)) + ); return rid; } @@ -165,7 +162,9 @@ public void modify(long roleId, String remark) { }); if (rct > 0) { - wingsTableCudHandler.handle(this.getClass(), Cud.Update, t, field -> field.put(t.Id.getName(), List.of(roleId))); + wingsTableCudHandler.handle(this.getClass(), Cud.Update, t, field -> + field.put(t.Id.getName(), List.of(roleId)) + ); } } } diff --git a/wings/warlock/src/main/java-gen/pro/fessional/wings/warlock/database/autogen/tables/SysConstantEnumTable.java b/wings/warlock/src/main/java-gen/pro/fessional/wings/warlock/database/autogen/tables/SysConstantEnumTable.java index 6cad9f45b..4af3c04e3 100644 --- a/wings/warlock/src/main/java-gen/pro/fessional/wings/warlock/database/autogen/tables/SysConstantEnumTable.java +++ b/wings/warlock/src/main/java-gen/pro/fessional/wings/warlock/database/autogen/tables/SysConstantEnumTable.java @@ -34,7 +34,7 @@ @Generated( value = { "https://www.jooq.org", - "jOOQ version:3.18.7", + "jOOQ version:3.18.9", "schema version:2020102701" }, comments = "This class is generated by jOOQ" @@ -184,7 +184,6 @@ public SelectField mapping(Function5 SelectField mapping(Class toType, Function5 from) { return convertFrom(toType, Records.mapping(from)); } - /** * alias asK5 diff --git a/wings/warlock/src/main/java-gen/pro/fessional/wings/warlock/database/autogen/tables/SysStandardI18nTable.java b/wings/warlock/src/main/java-gen/pro/fessional/wings/warlock/database/autogen/tables/SysStandardI18nTable.java index 74ff36310..b363bf12e 100644 --- a/wings/warlock/src/main/java-gen/pro/fessional/wings/warlock/database/autogen/tables/SysStandardI18nTable.java +++ b/wings/warlock/src/main/java-gen/pro/fessional/wings/warlock/database/autogen/tables/SysStandardI18nTable.java @@ -34,7 +34,7 @@ @Generated( value = { "https://www.jooq.org", - "jOOQ version:3.18.7", + "jOOQ version:3.18.9", "schema version:2020102701" }, comments = "This class is generated by jOOQ" @@ -184,7 +184,6 @@ public SelectField mapping(Function5 SelectField mapping(Class toType, Function5 from) { return convertFrom(toType, Records.mapping(from)); } - /** * alias asM5 diff --git a/wings/warlock/src/main/java-gen/pro/fessional/wings/warlock/database/autogen/tables/WinConfRuntimeTable.java b/wings/warlock/src/main/java-gen/pro/fessional/wings/warlock/database/autogen/tables/WinConfRuntimeTable.java index ac90edf85..23fb70b8d 100644 --- a/wings/warlock/src/main/java-gen/pro/fessional/wings/warlock/database/autogen/tables/WinConfRuntimeTable.java +++ b/wings/warlock/src/main/java-gen/pro/fessional/wings/warlock/database/autogen/tables/WinConfRuntimeTable.java @@ -6,10 +6,10 @@ import org.jetbrains.annotations.NotNull; import org.jooq.Field; -import org.jooq.Function6; +import org.jooq.Function7; import org.jooq.Name; import org.jooq.Records; -import org.jooq.Row6; +import org.jooq.Row7; import org.jooq.Schema; import org.jooq.SelectField; import org.jooq.Table; @@ -34,7 +34,7 @@ @Generated( value = { "https://www.jooq.org", - "jOOQ version:3.18.7", + "jOOQ version:3.18.9", "schema version:2020102701" }, comments = "This class is generated by jOOQ" @@ -63,20 +63,25 @@ public Class getRecordType() { */ public final TableField Key = createField(DSL.name("key"), SQLDataType.VARCHAR(200).nullable(false), this, ""); + /** + * The column win_conf_runtime.enabled. + */ + public final TableField Enabled = createField(DSL.name("enabled"), SQLDataType.BOOLEAN.nullable(false).defaultValue(DSL.inline("1", SQLDataType.BOOLEAN)), this, ""); + /** * The column win_conf_runtime.current. */ - public final TableField Current = createField(DSL.name("current"), SQLDataType.VARCHAR(5000).nullable(false).defaultValue(DSL.inline("", SQLDataType.VARCHAR)), this, ""); + public final TableField Current = createField(DSL.name("current"), SQLDataType.CLOB.nullable(false), this, ""); /** * The column win_conf_runtime.previous. */ - public final TableField Previous = createField(DSL.name("previous"), SQLDataType.VARCHAR(5000).nullable(false).defaultValue(DSL.inline("", SQLDataType.VARCHAR)), this, ""); + public final TableField Previous = createField(DSL.name("previous"), SQLDataType.CLOB.nullable(false), this, ""); /** * The column win_conf_runtime.initial. */ - public final TableField Initial = createField(DSL.name("initial"), SQLDataType.VARCHAR(5000).nullable(false).defaultValue(DSL.inline("", SQLDataType.VARCHAR)), this, ""); + public final TableField Initial = createField(DSL.name("initial"), SQLDataType.CLOB.nullable(false), this, ""); /** * The column win_conf_runtime.comment. @@ -167,18 +172,18 @@ public WinConfRuntimeTable rename(Table name) { } // ------------------------------------------------------------------------- - // Row6 type methods + // Row7 type methods // ------------------------------------------------------------------------- @Override - public Row6 fieldsRow() { - return (Row6) super.fieldsRow(); + public Row7 fieldsRow() { + return (Row7) super.fieldsRow(); } /** * Convenience mapping calling {@link SelectField#convertFrom(Function)}. */ - public SelectField mapping(Function6 from) { + public SelectField mapping(Function7 from) { return convertFrom(Records.mapping(from)); } @@ -186,10 +191,9 @@ public SelectField mapping(Function6 SelectField mapping(Class toType, Function6 from) { + public SelectField mapping(Class toType, Function7 from) { return convertFrom(toType, Records.mapping(from)); } - /** * alias asS4 diff --git a/wings/warlock/src/main/java-gen/pro/fessional/wings/warlock/database/autogen/tables/WinPermEntryTable.java b/wings/warlock/src/main/java-gen/pro/fessional/wings/warlock/database/autogen/tables/WinPermEntryTable.java index 03cd5d144..c0ef876f7 100644 --- a/wings/warlock/src/main/java-gen/pro/fessional/wings/warlock/database/autogen/tables/WinPermEntryTable.java +++ b/wings/warlock/src/main/java-gen/pro/fessional/wings/warlock/database/autogen/tables/WinPermEntryTable.java @@ -41,7 +41,7 @@ @Generated( value = { "https://www.jooq.org", - "jOOQ version:3.18.7", + "jOOQ version:3.18.9", "schema version:2020102701" }, comments = "This class is generated by jOOQ" @@ -215,7 +215,6 @@ public SelectField mapping(Class toType, Function8delete_dt condition diff --git a/wings/warlock/src/main/java-gen/pro/fessional/wings/warlock/database/autogen/tables/WinRoleEntryTable.java b/wings/warlock/src/main/java-gen/pro/fessional/wings/warlock/database/autogen/tables/WinRoleEntryTable.java index ce9b3a3d6..d539a7680 100644 --- a/wings/warlock/src/main/java-gen/pro/fessional/wings/warlock/database/autogen/tables/WinRoleEntryTable.java +++ b/wings/warlock/src/main/java-gen/pro/fessional/wings/warlock/database/autogen/tables/WinRoleEntryTable.java @@ -40,7 +40,7 @@ @Generated( value = { "https://www.jooq.org", - "jOOQ version:3.18.7", + "jOOQ version:3.18.9", "schema version:2020102701" }, comments = "This class is generated by jOOQ" @@ -209,7 +209,6 @@ public SelectField mapping(Class toType, Function7delete_dt condition diff --git a/wings/warlock/src/main/java-gen/pro/fessional/wings/warlock/database/autogen/tables/WinRoleGrantTable.java b/wings/warlock/src/main/java-gen/pro/fessional/wings/warlock/database/autogen/tables/WinRoleGrantTable.java index 360b4935a..07466e7fe 100644 --- a/wings/warlock/src/main/java-gen/pro/fessional/wings/warlock/database/autogen/tables/WinRoleGrantTable.java +++ b/wings/warlock/src/main/java-gen/pro/fessional/wings/warlock/database/autogen/tables/WinRoleGrantTable.java @@ -36,7 +36,7 @@ @Generated( value = { "https://www.jooq.org", - "jOOQ version:3.18.7", + "jOOQ version:3.18.9", "schema version:2020102701" }, comments = "This class is generated by jOOQ" @@ -186,7 +186,6 @@ public SelectField mapping(Function5 SelectField mapping(Class toType, Function5 from) { return convertFrom(toType, Records.mapping(from)); } - /** * alias asE2 diff --git a/wings/warlock/src/main/java-gen/pro/fessional/wings/warlock/database/autogen/tables/WinUserAuthnTable.java b/wings/warlock/src/main/java-gen/pro/fessional/wings/warlock/database/autogen/tables/WinUserAuthnTable.java index a7e5dbc29..dada855af 100644 --- a/wings/warlock/src/main/java-gen/pro/fessional/wings/warlock/database/autogen/tables/WinUserAuthnTable.java +++ b/wings/warlock/src/main/java-gen/pro/fessional/wings/warlock/database/autogen/tables/WinUserAuthnTable.java @@ -41,7 +41,7 @@ @Generated( value = { "https://www.jooq.org", - "jOOQ version:3.18.7", + "jOOQ version:3.18.9", "schema version:2020102701" }, comments = "This class is generated by jOOQ" @@ -245,7 +245,6 @@ public SelectField mapping(Class toType, Function14delete_dt condition diff --git a/wings/warlock/src/main/java-gen/pro/fessional/wings/warlock/database/autogen/tables/WinUserBasisTable.java b/wings/warlock/src/main/java-gen/pro/fessional/wings/warlock/database/autogen/tables/WinUserBasisTable.java index b819af618..6a8b7cf49 100644 --- a/wings/warlock/src/main/java-gen/pro/fessional/wings/warlock/database/autogen/tables/WinUserBasisTable.java +++ b/wings/warlock/src/main/java-gen/pro/fessional/wings/warlock/database/autogen/tables/WinUserBasisTable.java @@ -47,7 +47,7 @@ @Generated( value = { "https://www.jooq.org", - "jOOQ version:3.18.7", + "jOOQ version:3.18.9", "schema version:2020102701" }, comments = "This class is generated by jOOQ" @@ -246,7 +246,6 @@ public SelectField mapping(Class toType, Function13delete_dt condition diff --git a/wings/warlock/src/main/java-gen/pro/fessional/wings/warlock/database/autogen/tables/WinUserGrantTable.java b/wings/warlock/src/main/java-gen/pro/fessional/wings/warlock/database/autogen/tables/WinUserGrantTable.java index 4572d988e..aae4d52e4 100644 --- a/wings/warlock/src/main/java-gen/pro/fessional/wings/warlock/database/autogen/tables/WinUserGrantTable.java +++ b/wings/warlock/src/main/java-gen/pro/fessional/wings/warlock/database/autogen/tables/WinUserGrantTable.java @@ -36,7 +36,7 @@ @Generated( value = { "https://www.jooq.org", - "jOOQ version:3.18.7", + "jOOQ version:3.18.9", "schema version:2020102701" }, comments = "This class is generated by jOOQ" @@ -186,7 +186,6 @@ public SelectField mapping(Function5 SelectField mapping(Class toType, Function5 from) { return convertFrom(toType, Records.mapping(from)); } - /** * alias asR2 diff --git a/wings/warlock/src/main/java-gen/pro/fessional/wings/warlock/database/autogen/tables/WinUserLoginTable.java b/wings/warlock/src/main/java-gen/pro/fessional/wings/warlock/database/autogen/tables/WinUserLoginTable.java index 689e547e6..af289fb4e 100644 --- a/wings/warlock/src/main/java-gen/pro/fessional/wings/warlock/database/autogen/tables/WinUserLoginTable.java +++ b/wings/warlock/src/main/java-gen/pro/fessional/wings/warlock/database/autogen/tables/WinUserLoginTable.java @@ -36,7 +36,7 @@ @Generated( value = { "https://www.jooq.org", - "jOOQ version:3.18.7", + "jOOQ version:3.18.9", "schema version:2020102701" }, comments = "This class is generated by jOOQ" @@ -210,7 +210,6 @@ public SelectField mapping(Class toType, Function8 fetchOptionalByKey(String value) { return fetchOptional(WinConfRuntimeTable.WinConfRuntime.Key, value); } + /** + * Fetch records that have enabled BETWEEN lowerInclusive AND + * upperInclusive + */ + public List fetchRangeOfEnabled(Boolean lowerInclusive, Boolean upperInclusive) { + return fetchRange(WinConfRuntimeTable.WinConfRuntime.Enabled, lowerInclusive, upperInclusive); + } + + /** + * Fetch records that have enabled IN (values) + */ + public List fetchByEnabled(Boolean... values) { + return fetch(WinConfRuntimeTable.WinConfRuntime.Enabled, values); + } + + public List fetchByEnabled(Collection values) { + return fetch(WinConfRuntimeTable.WinConfRuntime.Enabled, values); + } + /** * Fetch records that have current BETWEEN lowerInclusive AND * upperInclusive diff --git a/wings/warlock/src/main/java-gen/pro/fessional/wings/warlock/database/autogen/tables/interfaces/IWinConfRuntime.java b/wings/warlock/src/main/java-gen/pro/fessional/wings/warlock/database/autogen/tables/interfaces/IWinConfRuntime.java index 64be01a2e..350fd1cc6 100644 --- a/wings/warlock/src/main/java-gen/pro/fessional/wings/warlock/database/autogen/tables/interfaces/IWinConfRuntime.java +++ b/wings/warlock/src/main/java-gen/pro/fessional/wings/warlock/database/autogen/tables/interfaces/IWinConfRuntime.java @@ -14,7 +14,7 @@ @Generated( value = { "https://www.jooq.org", - "jOOQ version:3.18.7", + "jOOQ version:3.18.9", "schema version:2020102701" }, comments = "This class is generated by jOOQ" @@ -32,6 +32,16 @@ public interface IWinConfRuntime extends Serializable { */ public String getKey(); + /** + * Setter for win_conf_runtime.enabled. + */ + public void setEnabled(Boolean value); + + /** + * Getter for win_conf_runtime.enabled. + */ + public Boolean getEnabled(); + /** * Setter for win_conf_runtime.current. */ diff --git a/wings/warlock/src/main/java-gen/pro/fessional/wings/warlock/database/autogen/tables/pojos/WinConfRuntime.java b/wings/warlock/src/main/java-gen/pro/fessional/wings/warlock/database/autogen/tables/pojos/WinConfRuntime.java index b5b410b84..f837e92d6 100644 --- a/wings/warlock/src/main/java-gen/pro/fessional/wings/warlock/database/autogen/tables/pojos/WinConfRuntime.java +++ b/wings/warlock/src/main/java-gen/pro/fessional/wings/warlock/database/autogen/tables/pojos/WinConfRuntime.java @@ -30,6 +30,7 @@ public class WinConfRuntime implements IWinConfRuntime { private static final long serialVersionUID = 1L; private String key; + private Boolean enabled; private String current; private String previous; private String initial; @@ -40,6 +41,7 @@ public WinConfRuntime() {} public WinConfRuntime(IWinConfRuntime value) { this.key = value.getKey(); + this.enabled = value.getEnabled(); this.current = value.getCurrent(); this.previous = value.getPrevious(); this.initial = value.getInitial(); @@ -49,6 +51,7 @@ public WinConfRuntime(IWinConfRuntime value) { public WinConfRuntime( String key, + Boolean enabled, String current, String previous, String initial, @@ -56,6 +59,7 @@ public WinConfRuntime( String handler ) { this.key = key; + this.enabled = enabled; this.current = current; this.previous = previous; this.initial = initial; @@ -143,6 +147,86 @@ public void setKeyIf(UnaryOperator key) { } + /** + * Getter for win_conf_runtime.enabled. + */ + @Override + public Boolean getEnabled() { + return this.enabled; + } + + /** + * Setter for win_conf_runtime.enabled. + */ + @Override + public void setEnabled(Boolean enabled) { + this.enabled = enabled; + } + + @Transient + public void setEnabledIf(Boolean enabled, boolean bool) { + if (bool) { + this.enabled = enabled; + } + } + + @Transient + public void setEnabledIf(Supplier enabled, boolean bool) { + if (bool) { + this.enabled = enabled.get(); + } + } + + @Transient + public void setEnabledIf(Boolean enabled, Predicate bool) { + if (bool.test(enabled)) { + this.enabled = enabled; + } + } + + @Transient + public void setEnabledIf(Boolean enabled, Predicate bool, Supplier... enableds) { + if (bool.test(enabled)) { + this.enabled = enabled; + return; + } + for (Supplier supplier : enableds) { + enabled = supplier.get(); + if (bool.test(enabled)) { + this.enabled = enabled; + return; + } + } + } + + @Transient + public void setEnabledIfNot(Boolean enabled, Predicate bool) { + if (!bool.test(enabled)) { + this.enabled = enabled; + } + } + + @Transient + public void setEnabledIfNot(Boolean enabled, Predicate bool, Supplier... enableds) { + if (!bool.test(enabled)) { + this.enabled = enabled; + return; + } + for (Supplier supplier : enableds) { + enabled = supplier.get(); + if (!bool.test(enabled)) { + this.enabled = enabled; + return; + } + } + } + + @Transient + public void setEnabledIf(UnaryOperator enabled) { + this.enabled = enabled.apply(this.enabled); + } + + /** * Getter for win_conf_runtime.current. */ @@ -558,6 +642,12 @@ public boolean equals(Object obj) { } else if (!this.key.equals(other.key)) return false; + if (this.enabled == null) { + if (other.enabled != null) + return false; + } + else if (!this.enabled.equals(other.enabled)) + return false; if (this.current == null) { if (other.current != null) return false; @@ -596,6 +686,7 @@ public int hashCode() { final int prime = 31; int result = 1; result = prime * result + ((this.key == null) ? 0 : this.key.hashCode()); + result = prime * result + ((this.enabled == null) ? 0 : this.enabled.hashCode()); result = prime * result + ((this.current == null) ? 0 : this.current.hashCode()); result = prime * result + ((this.previous == null) ? 0 : this.previous.hashCode()); result = prime * result + ((this.initial == null) ? 0 : this.initial.hashCode()); @@ -609,6 +700,7 @@ public String toString() { StringBuilder sb = new StringBuilder("WinConfRuntime ("); sb.append(key); + sb.append(", ").append(enabled); sb.append(", ").append(current); sb.append(", ").append(previous); sb.append(", ").append(initial); @@ -626,6 +718,7 @@ public String toString() { @Override public void from(IWinConfRuntime from) { setKey(from.getKey()); + setEnabled(from.getEnabled()); setCurrent(from.getCurrent()); setPrevious(from.getPrevious()); setInitial(from.getInitial()); diff --git a/wings/warlock/src/main/java-gen/pro/fessional/wings/warlock/database/autogen/tables/records/WinConfRuntimeRecord.java b/wings/warlock/src/main/java-gen/pro/fessional/wings/warlock/database/autogen/tables/records/WinConfRuntimeRecord.java index 9ac81fcd8..d1bc6e3ca 100644 --- a/wings/warlock/src/main/java-gen/pro/fessional/wings/warlock/database/autogen/tables/records/WinConfRuntimeRecord.java +++ b/wings/warlock/src/main/java-gen/pro/fessional/wings/warlock/database/autogen/tables/records/WinConfRuntimeRecord.java @@ -6,8 +6,8 @@ import org.jooq.Field; import org.jooq.Record1; -import org.jooq.Record6; -import org.jooq.Row6; +import org.jooq.Record7; +import org.jooq.Row7; import org.jooq.impl.UpdatableRecordImpl; import pro.fessional.wings.warlock.database.autogen.tables.WinConfRuntimeTable; import pro.fessional.wings.warlock.database.autogen.tables.interfaces.IWinConfRuntime; @@ -22,13 +22,13 @@ @Generated( value = { "https://www.jooq.org", - "jOOQ version:3.18.7", + "jOOQ version:3.18.9", "schema version:2020102701" }, comments = "This class is generated by jOOQ" ) @SuppressWarnings({ "all", "unchecked", "rawtypes", "this-escape" }) -public class WinConfRuntimeRecord extends UpdatableRecordImpl implements Record6, IWinConfRuntime { +public class WinConfRuntimeRecord extends UpdatableRecordImpl implements Record7, IWinConfRuntime { private static final long serialVersionUID = 1L; @@ -48,12 +48,28 @@ public String getKey() { return (String) get(0); } + /** + * Setter for win_conf_runtime.enabled. + */ + @Override + public void setEnabled(Boolean value) { + set(1, value); + } + + /** + * Getter for win_conf_runtime.enabled. + */ + @Override + public Boolean getEnabled() { + return (Boolean) get(1); + } + /** * Setter for win_conf_runtime.current. */ @Override public void setCurrent(String value) { - set(1, value); + set(2, value); } /** @@ -61,7 +77,7 @@ public void setCurrent(String value) { */ @Override public String getCurrent() { - return (String) get(1); + return (String) get(2); } /** @@ -69,7 +85,7 @@ public String getCurrent() { */ @Override public void setPrevious(String value) { - set(2, value); + set(3, value); } /** @@ -77,7 +93,7 @@ public void setPrevious(String value) { */ @Override public String getPrevious() { - return (String) get(2); + return (String) get(3); } /** @@ -85,7 +101,7 @@ public String getPrevious() { */ @Override public void setInitial(String value) { - set(3, value); + set(4, value); } /** @@ -93,7 +109,7 @@ public void setInitial(String value) { */ @Override public String getInitial() { - return (String) get(3); + return (String) get(4); } /** @@ -101,7 +117,7 @@ public String getInitial() { */ @Override public void setComment(String value) { - set(4, value); + set(5, value); } /** @@ -109,7 +125,7 @@ public void setComment(String value) { */ @Override public String getComment() { - return (String) get(4); + return (String) get(5); } /** @@ -117,7 +133,7 @@ public String getComment() { */ @Override public void setHandler(String value) { - set(5, value); + set(6, value); } /** @@ -125,7 +141,7 @@ public void setHandler(String value) { */ @Override public String getHandler() { - return (String) get(5); + return (String) get(6); } // ------------------------------------------------------------------------- @@ -138,17 +154,17 @@ public Record1 key() { } // ------------------------------------------------------------------------- - // Record6 type implementation + // Record7 type implementation // ------------------------------------------------------------------------- @Override - public Row6 fieldsRow() { - return (Row6) super.fieldsRow(); + public Row7 fieldsRow() { + return (Row7) super.fieldsRow(); } @Override - public Row6 valuesRow() { - return (Row6) super.valuesRow(); + public Row7 valuesRow() { + return (Row7) super.valuesRow(); } @Override @@ -157,27 +173,32 @@ public Field field1() { } @Override - public Field field2() { - return WinConfRuntimeTable.WinConfRuntime.Current; + public Field field2() { + return WinConfRuntimeTable.WinConfRuntime.Enabled; } @Override public Field field3() { - return WinConfRuntimeTable.WinConfRuntime.Previous; + return WinConfRuntimeTable.WinConfRuntime.Current; } @Override public Field field4() { - return WinConfRuntimeTable.WinConfRuntime.Initial; + return WinConfRuntimeTable.WinConfRuntime.Previous; } @Override public Field field5() { - return WinConfRuntimeTable.WinConfRuntime.Comment; + return WinConfRuntimeTable.WinConfRuntime.Initial; } @Override public Field field6() { + return WinConfRuntimeTable.WinConfRuntime.Comment; + } + + @Override + public Field field7() { return WinConfRuntimeTable.WinConfRuntime.Handler; } @@ -187,27 +208,32 @@ public String component1() { } @Override - public String component2() { - return getCurrent(); + public Boolean component2() { + return getEnabled(); } @Override public String component3() { - return getPrevious(); + return getCurrent(); } @Override public String component4() { - return getInitial(); + return getPrevious(); } @Override public String component5() { - return getComment(); + return getInitial(); } @Override public String component6() { + return getComment(); + } + + @Override + public String component7() { return getHandler(); } @@ -217,27 +243,32 @@ public String value1() { } @Override - public String value2() { - return getCurrent(); + public Boolean value2() { + return getEnabled(); } @Override public String value3() { - return getPrevious(); + return getCurrent(); } @Override public String value4() { - return getInitial(); + return getPrevious(); } @Override public String value5() { - return getComment(); + return getInitial(); } @Override public String value6() { + return getComment(); + } + + @Override + public String value7() { return getHandler(); } @@ -248,43 +279,50 @@ public WinConfRuntimeRecord value1(String value) { } @Override - public WinConfRuntimeRecord value2(String value) { - setCurrent(value); + public WinConfRuntimeRecord value2(Boolean value) { + setEnabled(value); return this; } @Override public WinConfRuntimeRecord value3(String value) { - setPrevious(value); + setCurrent(value); return this; } @Override public WinConfRuntimeRecord value4(String value) { - setInitial(value); + setPrevious(value); return this; } @Override public WinConfRuntimeRecord value5(String value) { - setComment(value); + setInitial(value); return this; } @Override public WinConfRuntimeRecord value6(String value) { + setComment(value); + return this; + } + + @Override + public WinConfRuntimeRecord value7(String value) { setHandler(value); return this; } @Override - public WinConfRuntimeRecord values(String value1, String value2, String value3, String value4, String value5, String value6) { + public WinConfRuntimeRecord values(String value1, Boolean value2, String value3, String value4, String value5, String value6, String value7) { value1(value1); value2(value2); value3(value3); value4(value4); value5(value5); value6(value6); + value7(value7); return this; } @@ -295,6 +333,7 @@ public WinConfRuntimeRecord values(String value1, String value2, String value3, @Override public void from(IWinConfRuntime from) { setKey(from.getKey()); + setEnabled(from.getEnabled()); setCurrent(from.getCurrent()); setPrevious(from.getPrevious()); setInitial(from.getInitial()); @@ -323,10 +362,11 @@ public WinConfRuntimeRecord() { /** * Create a detached, initialised WinConfRuntimeRecord */ - public WinConfRuntimeRecord(String key, String current, String previous, String initial, String comment, String handler) { + public WinConfRuntimeRecord(String key, Boolean enabled, String current, String previous, String initial, String comment, String handler) { super(WinConfRuntimeTable.WinConfRuntime); setKey(key); + setEnabled(enabled); setCurrent(current); setPrevious(previous); setInitial(initial); @@ -343,6 +383,7 @@ public WinConfRuntimeRecord(WinConfRuntime value) { if (value != null) { setKey(value.getKey()); + setEnabled(value.getEnabled()); setCurrent(value.getCurrent()); setPrevious(value.getPrevious()); setInitial(value.getInitial()); diff --git a/wings/warlock/src/main/java/pro/fessional/wings/warlock/service/conf/RuntimeConfService.java b/wings/warlock/src/main/java/pro/fessional/wings/warlock/service/conf/RuntimeConfService.java index 072a848b2..56bddefff 100644 --- a/wings/warlock/src/main/java/pro/fessional/wings/warlock/service/conf/RuntimeConfService.java +++ b/wings/warlock/src/main/java/pro/fessional/wings/warlock/service/conf/RuntimeConfService.java @@ -1,5 +1,6 @@ package pro.fessional.wings.warlock.service.conf; +import org.jetbrains.annotations.NotNull; import org.springframework.core.convert.TypeDescriptor; import pro.fessional.mirana.cast.EnumConvertor; import pro.fessional.wings.silencer.enhance.TypeSugar; @@ -15,41 +16,41 @@ */ public interface RuntimeConfService { - default String getString(String key) { + default String getString(@NotNull String key) { return getObject(key, TypeSugar.StringDescriptor); } - default String getString(Class key) { + default String getString(@NotNull Class key) { return getString(key.getName()); } - default String getString(Enum key) { + default String getString(@NotNull Enum key) { return getString(EnumConvertor.enum2Str(key)); } - default int getInt(String key, int els) { + default int getInt(@NotNull String key, int els) { final Integer obj = getSimple(key, Integer.class); return obj == null ? els : obj; } - default int getInt(Class key, int els) { + default int getInt(@NotNull Class key, int els) { return getInt(key.getName(), els); } - default int getInt(Enum key, int els) { + default int getInt(@NotNull Enum key, int els) { return getInt(EnumConvertor.enum2Str(key), els); } - default boolean getBoolean(String key, boolean els) { + default boolean getBoolean(@NotNull String key, boolean els) { final Boolean obj = getSimple(key, Boolean.class); return obj == null ? els : obj; } - default boolean getBoolean(Class key, boolean els) { + default boolean getBoolean(@NotNull Class key, boolean els) { return getBoolean(key.getName(), els); } - default boolean getBoolean(Enum key, boolean els) { + default boolean getBoolean(@NotNull Enum key, boolean els) { return getBoolean(EnumConvertor.enum2Str(key), els); } @@ -58,63 +59,69 @@ default long getLong(String key, long els) { return obj == null ? els : obj; } - default long getLong(Class key, long els) { + default long getLong(@NotNull Class key, long els) { return getLong(key.getName(), els); } - default long getLong(Enum key, long els) { + default long getLong(@NotNull Enum key, long els) { return getLong(EnumConvertor.enum2Str(key), els); } - default T getSimple(String key, Class vt) { - return getObject(key, TypeSugar.describe(vt)); + default T getSimple(@NotNull String key, @NotNull Class type) { + return getObject(key, TypeSugar.describe(type)); } - default T getSimple(Class key, Class vt) { - return getSimple(key.getName(), vt); + default T getSimple(@NotNull Class key, @NotNull Class type) { + return getSimple(key.getName(), type); } - default T getSimple(Enum key, Class vt) { - return getSimple(EnumConvertor.enum2Str(key), vt); + default T getSimple(@NotNull Enum key, @NotNull Class type) { + return getSimple(EnumConvertor.enum2Str(key), type); } - default > T getEnum(Class key) { + default > T getEnum(@NotNull Class key) { return getSimple(key.getName(), key); } - default > List getEnums(Class key) { + default > List getEnums(@NotNull Class key) { return getList(key.getName(), key); } - default List getList(String key, Class vt) { - return getObject(key, TypeSugar.describe(List.class, vt)); + @NotNull + default List getList(@NotNull String key, @NotNull Class type) { + return getObject(key, TypeSugar.describe(List.class, type)); } - default List getList(Class key, Class vt) { - return getList(key.getName(), vt); + @NotNull + default List getList(@NotNull Class key, @NotNull Class type) { + return getList(key.getName(), type); } - default List getList(Enum key, Class vt) { - return getList(EnumConvertor.enum2Str(key), vt); + @NotNull + default List getList(@NotNull Enum key, @NotNull Class type) { + return getList(EnumConvertor.enum2Str(key), type); } - default Map getMap(String key, Class kt, Class vt) { - return getObject(key, TypeSugar.describe(Map.class, kt, vt)); + @NotNull + default Map getMap(@NotNull String key, @NotNull Class keyType, @NotNull Class valueType) { + return getObject(key, TypeSugar.describe(Map.class, keyType, valueType)); } - default Map getMap(Class key, Class kt, Class vt) { - return getMap(key.getName(), kt, vt); + @NotNull + default Map getMap(@NotNull Class key, @NotNull Class keyType, @NotNull Class valueType) { + return getMap(key.getName(), keyType, valueType); } - default Map getMap(Enum key, Class kt, Class vt) { - return getMap(EnumConvertor.enum2Str(key), kt, vt); + @NotNull + default Map getMap(@NotNull Enum key, @NotNull Class keyType, @NotNull Class valueType) { + return getMap(EnumConvertor.enum2Str(key), keyType, valueType); } - default T getObject(Class key, TypeDescriptor type) { + default T getObject(@NotNull Class key, @NotNull TypeDescriptor type) { return getObject(key.getName(), type); } - default T getObject(Enum key, TypeDescriptor type) { + default T getObject(@NotNull Enum key, @NotNull TypeDescriptor type) { return getObject(EnumConvertor.enum2Str(key), type); } @@ -126,7 +133,7 @@ default T getObject(Enum key, TypeDescriptor type) { * @param Type of value * @return value */ - T getObject(String key, TypeDescriptor type); + T getObject(@NotNull String key, @NotNull TypeDescriptor type); /** @@ -135,13 +142,13 @@ default T getObject(Enum key, TypeDescriptor type) { * @param key key * @param value config */ - void setObject(String key, Object value); + void setObject(@NotNull String key, @NotNull Object value); - default void setObject(Class key, Object value) { + default void setObject(@NotNull Class key, @NotNull Object value) { setObject(key.getName(), value); } - default void setObject(Enum key, Object value) { + default void setObject(@NotNull Enum key, @NotNull Object value) { setObject(EnumConvertor.enum2Str(key), value); } @@ -154,13 +161,13 @@ default void setObject(Enum key, Object value) { * @param handler type handler name * @return whether handled */ - boolean newObject(String key, Object value, String comment, String handler); + boolean newObject(@NotNull String key, @NotNull Object value, String comment, @NotNull String handler); - default boolean newObject(Class key, Object value, String comment, String handler) { + default boolean newObject(@NotNull Class key, @NotNull Object value, String comment, @NotNull String handler) { return newObject(key.getName(), value, comment, handler); } - default boolean newObject(Enum key, Object value, String comment, String handler) { + default boolean newObject(@NotNull Enum key, @NotNull Object value, String comment, @NotNull String handler) { return newObject(EnumConvertor.enum2Str(key), value, comment, handler); } @@ -171,14 +178,26 @@ default boolean newObject(Enum key, Object value, String comment, String hand * @param value config value * @param comment config comment */ - boolean newObject(String key, Object value, String comment); + boolean newObject(@NotNull String key, @NotNull Object value, String comment); - default boolean newObject(Class key, Object value, String comment) { + default boolean newObject(@NotNull Class key, @NotNull Object value, String comment) { return newObject(key.getName(), value, comment); } - default boolean newObject(Enum key, Object value, String comment) { + default boolean newObject(@NotNull Enum key, @NotNull Object value, String comment) { return newObject(EnumConvertor.enum2Str(key), value, comment); } + /** + * enable/disable the config, success or throw an error. + */ + boolean enable(@NotNull String key, boolean enable); + + default boolean enable(@NotNull Class key, boolean enable) { + return enable(key.getName(), enable); + } + + default boolean enable(@NotNull Enum key, boolean enable) { + return enable(EnumConvertor.enum2Str(key), enable); + } } diff --git a/wings/warlock/src/main/java/pro/fessional/wings/warlock/service/conf/impl/RuntimeConfServiceImpl.java b/wings/warlock/src/main/java/pro/fessional/wings/warlock/service/conf/impl/RuntimeConfServiceImpl.java index 4227f7803..a5f7dcf9f 100644 --- a/wings/warlock/src/main/java/pro/fessional/wings/warlock/service/conf/impl/RuntimeConfServiceImpl.java +++ b/wings/warlock/src/main/java/pro/fessional/wings/warlock/service/conf/impl/RuntimeConfServiceImpl.java @@ -3,6 +3,7 @@ import lombok.Setter; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; +import org.jetbrains.annotations.NotNull; import org.jooq.Record2; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.cache.annotation.CacheConfig; @@ -25,7 +26,6 @@ import pro.fessional.wings.warlock.service.conf.RuntimeConfService; import java.util.ArrayList; -import java.util.HashMap; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; @@ -56,12 +56,12 @@ public class RuntimeConfServiceImpl extends ThisLazy imp private final Map handlerMap = new LinkedHashMap<>(); - public void putHandler(String type, ConversionService handler) { + public void putHandler(@NotNull String type, @NotNull ConversionService handler) { handlerMap.put(type, handler); } @Override - public T getObject(String key, TypeDescriptor type) { + public T getObject(@NotNull String key, @NotNull TypeDescriptor type) { // dot not @Cacheable it but thisLazy, because, // (1) calling method inside make cache invalid // (2) recursive calling @@ -70,13 +70,14 @@ public T getObject(String key, TypeDescriptor type) { } @Override - public void setObject(String key, Object value) { + public void setObject(@NotNull String key, @NotNull Object value) { final WinConfRuntimeTable t = winConfRuntimeDao.getTable(); final String handler = winConfRuntimeDao.fetchOne(String.class, t, t.Key.eq(key), t.Handler); ConversionService service = handlerMap.get(handler); final String str = service.convert(value, String.class); AssertArgs.notNull(str, "can not covert value to string, key={}", key); + final int rc = winConfRuntimeDao .ctx() .update(t) @@ -86,25 +87,26 @@ public void setObject(String key, Object value) { .execute(); if (rc > 0) { - wingsTableCudHandler.handle(this.getClass(), Cud.Update, t, () -> { - Map> field = new HashMap<>(); + wingsTableCudHandler.handle(this.getClass(), Cud.Update, t, field -> { field.put(t.Key.getName(), List.of(key)); field.put(t.Current.getName(), List.of(str)); - return field; }); } } @Override - public boolean newObject(String key, Object value, String comment, String handler) { - if (key == null || key.isEmpty() || value == null || handler == null) return false; + public boolean newObject(@NotNull String key, @NotNull Object value, String comment, @NotNull String handler) { + AssertArgs.notEmpty(key, "empty key"); + ConversionService service = handlerMap.get(handler); if (service == null || !service.canConvert(value.getClass(), String.class)) return false; final String str = service.convert(value, String.class); AssertArgs.notNull(str, "can not covert value to string, key={}", key); + final WinConfRuntime pojo = new WinConfRuntime(); pojo.setKey(key); + pojo.setEnabled(true); pojo.setCurrent(str); pojo.setPrevious(Null.Str); pojo.setInitial(str); @@ -112,16 +114,14 @@ public boolean newObject(String key, Object value, String comment, String handle pojo.setHandler(handler); final int rc = winConfRuntimeDao.insertInto(pojo, false); - log.debug("rc={}, key={}, han={}, val={}", rc, key, handler, str); + log.info("newObject rc={}, key={}, han={}, val={}", rc, key, handler, str); if (rc > 0) { Cud type = rc == 1 ? Cud.Create : Cud.Update; final WinConfRuntimeTable t = winConfRuntimeDao.getTable(); - wingsTableCudHandler.handle(this.getClass(), type, t, () -> { - Map> field = new HashMap<>(); + wingsTableCudHandler.handle(this.getClass(), type, t, field -> { field.put(t.Key.getName(), List.of(key)); field.put(t.Current.getName(), List.of(str)); - return field; }); } @@ -129,7 +129,7 @@ public boolean newObject(String key, Object value, String comment, String handle } @Override - public boolean newObject(String key, Object value, String comment) { + public boolean newObject(@NotNull String key, @NotNull Object value, String comment) { for (String handler : new ArrayList<>(handlerMap.keySet())) { if (newObject(key, value, comment, handler)) { return true; @@ -138,9 +138,31 @@ public boolean newObject(String key, Object value, String comment) { return false; } + @Override + public boolean enable(@NotNull String key, boolean enable) { + WinConfRuntimeTable t = winConfRuntimeDao.getTable(); + final int rc = winConfRuntimeDao + .ctx() + .update(t) + .set(t.Enabled, enable) + .where(t.Key.eq(key)) + .execute(); + + log.info("enable rc={}, key={}, enable={}", rc, key, enable); + + if (rc > 0) { + wingsTableCudHandler.handle(this.getClass(), Cud.Update, t, field -> { + field.put(t.Key.getName(), List.of(key)); + field.put(t.Enabled.getName(), List.of(enable)); + }); + } + + return rc >= 1; + } + @Cacheable @SuppressWarnings("unchecked") - public T getObjectCache(String key, TypeDescriptor type) { + public T getObjectCache(@NotNull String key, @NotNull TypeDescriptor type) { if (winConfRuntimeDao.notTableExist()) { log.warn("winConfRuntimeDao.notTableExist, key={}", key); return null; @@ -152,6 +174,7 @@ public T getObjectCache(String key, TypeDescriptor type) { .select(t.Current, t.Handler) .from(t) .where(t.Key.eq(key)) + .and(t.Enabled.eq(true)) .fetchOne(); if (r2 != null) { diff --git a/wings/warlock/src/main/resources/wings-flywave/branch/somefix/04-conf-size/2021-10-26u03-conf-size.sql b/wings/warlock/src/main/resources/wings-flywave/branch/somefix/04-conf-size/2021-10-26u03-conf-size.sql new file mode 100644 index 000000000..e164af59b --- /dev/null +++ b/wings/warlock/src/main/resources/wings-flywave/branch/somefix/04-conf-size/2021-10-26u03-conf-size.sql @@ -0,0 +1,5 @@ +ALTER TABLE `win_conf_runtime` + DROP COLUMN `enabled`, + CHANGE COLUMN `current` `current` VARCHAR(5000) NOT NULL DEFAULT '' COMMENT 'current value', + CHANGE COLUMN `previous` `previous` VARCHAR(5000) NOT NULL DEFAULT '' COMMENT 'previous value', + CHANGE COLUMN `initial` `initial` VARCHAR(5000) NOT NULL DEFAULT '' COMMENT 'initial value'; diff --git a/wings/warlock/src/main/resources/wings-flywave/branch/somefix/04-conf-size/2021-10-26v03-conf-size.sql b/wings/warlock/src/main/resources/wings-flywave/branch/somefix/04-conf-size/2021-10-26v03-conf-size.sql new file mode 100644 index 000000000..35ec303fb --- /dev/null +++ b/wings/warlock/src/main/resources/wings-flywave/branch/somefix/04-conf-size/2021-10-26v03-conf-size.sql @@ -0,0 +1,5 @@ +ALTER TABLE `win_conf_runtime` + ADD COLUMN `enabled` TINYINT(1) NOT NULL DEFAULT '1' COMMENT 'enabled' AFTER `key`, + CHANGE COLUMN `current` `current` TEXT NOT NULL COMMENT 'current value', + CHANGE COLUMN `previous` `previous` TEXT NOT NULL COMMENT 'previous value', + CHANGE COLUMN `initial` `initial` TEXT NOT NULL COMMENT 'initial value'; diff --git a/wings/warlock/src/main/resources/wings-flywave/master/05-conf/2020-10-25v01-conf_runtime.sql b/wings/warlock/src/main/resources/wings-flywave/master/05-conf/2020-10-25v01-conf_runtime.sql index d83835795..c9c7ff178 100644 --- a/wings/warlock/src/main/resources/wings-flywave/master/05-conf/2020-10-25v01-conf_runtime.sql +++ b/wings/warlock/src/main/resources/wings-flywave/master/05-conf/2020-10-25v01-conf_runtime.sql @@ -1,10 +1,11 @@ CREATE TABLE `win_conf_runtime` ( - `key` VARCHAR(200) NOT NULL COMMENT 'conf key:Enum|Class|String', - `current` VARCHAR(5000) NOT NULL DEFAULT '' COMMENT 'current value', - `previous` VARCHAR(5000) NOT NULL DEFAULT '' COMMENT 'previous value', - `initial` VARCHAR(5000) NOT NULL DEFAULT '' COMMENT 'initial value', - `comment` VARCHAR(500) NOT NULL DEFAULT '' COMMENT 'comment', - `handler` VARCHAR(200) NOT NULL DEFAULT 'prop' COMMENT 'data handling:prop|json', + `key` VARCHAR(200) NOT NULL COMMENT 'conf key:Enum|Class|String', + `enabled` TINYINT(1) NOT NULL DEFAULT '1' COMMENT 'enabled', + `current` TEXT NOT NULL COMMENT 'current value', + `previous` TEXT NOT NULL COMMENT 'previous value', + `initial` TEXT NOT NULL COMMENT 'initial value', + `comment` VARCHAR(500) NOT NULL DEFAULT '' COMMENT 'comment', + `handler` VARCHAR(200) NOT NULL DEFAULT 'prop' COMMENT 'data handling:prop|json', PRIMARY KEY (`key`) ) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COMMENT ='110/Runtime Config'; diff --git a/wings/warlock/src/test/java/pro/fessional/wings/warlock/service/conf/RuntimeConfServiceTest.java b/wings/warlock/src/test/java/pro/fessional/wings/warlock/service/conf/RuntimeConfServiceTest.java index f7e9139bd..2bdb5799f 100644 --- a/wings/warlock/src/test/java/pro/fessional/wings/warlock/service/conf/RuntimeConfServiceTest.java +++ b/wings/warlock/src/test/java/pro/fessional/wings/warlock/service/conf/RuntimeConfServiceTest.java @@ -33,13 +33,13 @@ * @since 2022-03-09 */ @SpringBootTest(properties = { - "logging.level.root=DEBUG", // AssertionLogger - "wings.faceless.jooq.cud.table[win_conf_runtime]=key,current,handler", + "logging.level.root=DEBUG", // AssertionLogger + "wings.faceless.jooq.cud.table[win_conf_runtime]=key,current,handler", }) @DependsOnDatabaseInitialization class RuntimeConfServiceTest { - @Setter(onMethod_ = {@Autowired}) + @Setter(onMethod_ = { @Autowired }) private RuntimeConfService runtimeConfService; @Test @@ -53,6 +53,8 @@ void testSimple() { assertSimple(ZonedDateTime.class, ZonedDateTime.of(ldt, ZoneId.of("Asia/Shanghai"))); assertSimple(Long.class, 1023L); assertSimple(Integer.class, 10); + + assertEnable(Integer.class); // final Map> mgr = WingsCacheHelper.getManager(RuntimeConfServiceImpl.class); Assertions.assertEquals(1, mgr.size()); @@ -73,6 +75,17 @@ private void assertSimple(Class clz, T obj) { Assertions.assertEquals(obj, obj1); } + private void assertEnable(Class clz) { + runtimeConfService.enable(clz, false); + Sleep.ignoreInterrupt(1000); // wait for event sync + final T obj1 = runtimeConfService.getSimple(clz, clz); + Assertions.assertNull(obj1); + runtimeConfService.enable(clz, true); + Sleep.ignoreInterrupt(1000); // wait for event sync + final T obj2 = runtimeConfService.getSimple(clz, clz); + Assertions.assertNotNull(obj2); + } + @Test @TmsLink("C14009") void testCollection() { From d4bfb5c9ef3a593b17a5eabcacd30dc3f0a6afb6 Mon Sep 17 00:00:00 2001 From: trydofor Date: Wed, 26 Jun 2024 13:12:58 +0800 Subject: [PATCH 04/51] =?UTF-8?q?=E2=9C=A8=20CacheTemplate=20to=20programm?= =?UTF-8?q?atic=20cache=20#264?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../slardar/cache/SimpleCacheTemplate.java | 279 ++++++++++++++++++ .../wings/slardar/cache/WingsCacheHelper.java | 110 ++++--- .../app/service/TestCachingService.java | 4 +- .../spring/WingsCacheInterceptorTest.java | 53 +++- .../service/conf/RuntimeConfServiceTest.java | 18 +- 5 files changed, 410 insertions(+), 54 deletions(-) create mode 100644 wings/slardar/src/main/java/pro/fessional/wings/slardar/cache/SimpleCacheTemplate.java diff --git a/wings/slardar/src/main/java/pro/fessional/wings/slardar/cache/SimpleCacheTemplate.java b/wings/slardar/src/main/java/pro/fessional/wings/slardar/cache/SimpleCacheTemplate.java new file mode 100644 index 000000000..68c2c0a7c --- /dev/null +++ b/wings/slardar/src/main/java/pro/fessional/wings/slardar/cache/SimpleCacheTemplate.java @@ -0,0 +1,279 @@ +package pro.fessional.wings.slardar.cache; + +import lombok.Getter; +import org.jetbrains.annotations.Contract; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.springframework.beans.factory.BeanFactory; +import org.springframework.cache.Cache; +import org.springframework.cache.CacheManager; +import org.springframework.cache.interceptor.SimpleKeyGenerator; +import org.springframework.core.convert.converter.Converter; +import pro.fessional.mirana.best.AssertArgs; +import pro.fessional.wings.silencer.spring.help.ApplicationContextHelper; + +import java.util.function.Supplier; + +/** + * only support raw and method argument key. + * NOT support SpEL or KeyGenerator + *

+ * should declare it as a final field to enhance performance, + * then use it after application context has started + * + * @author trydofor + * @since 2024-06-25 + */ +public class SimpleCacheTemplate { + + private final String manager; + private final String[] names; + private final Cache[] caches; + private volatile int status; // -1:uninit, 0:lazy-inited, 1: fixed + + @Getter + private volatile Converter encoder = null; + @Getter + private volatile Converter decoder = null; + @Getter + private volatile BeanFactory beanFactory = null; + + public SimpleCacheTemplate(@NotNull String manager, @NotNull String... caches) { + this.manager = manager; + this.names = caches; + this.caches = new Cache[caches.length]; + this.status = -1; + } + + public SimpleCacheTemplate(@NotNull Cache... caches) { + this.manager = null; + this.names = null; + this.caches = caches; + this.status = 1; + } + + /** + * encode Value to Cache, default null + */ + @Contract("_->this") + public SimpleCacheTemplate setEncoder(@Nullable Converter encoder) { + this.encoder = encoder; + return this; + } + + /** + * decode Value from Cache, default null + */ + @Contract("_->this") + public SimpleCacheTemplate setDecoder(@Nullable Converter decoder) { + this.decoder = decoder; + return this; + } + + /** + * set the application context to re-init Cache by CacheManager bean. + * mostly for unit test to avoid multiple application context. + */ + @Contract("_->this") + public SimpleCacheTemplate setBeanFactory(BeanFactory beanFactory) { + this.beanFactory = beanFactory; + this.status = -1; + return this; + } + // //////// + + /** + * get and decode Value from cache by argument key + */ + public T getArgKey(@NotNull Object... args) { + return getRawKey(rawKey(args)); + } + + /** + * get and decode Value from cache by raw key + */ + public T getRawKey(@NotNull Object key) { + for (Cache cache : getCaches()) { + Cache.ValueWrapper vw = cache.get(key); + if (vw != null && vw.get() != null) { + return decode(vw.get()); + } + } + return null; + } + + /** + * get and decode Value from cache by argument key, put the non-null value if no cache found. + */ + public T getArgKey(@NotNull Supplier value, @NotNull Object... args) { + return getRawKey(value, rawKey(args)); + } + + /** + * get and decode Value from cache by raw key, put the non-null value if no cache found. + */ + public T getRawKey(@NotNull Supplier value, @NotNull Object key) { + for (Cache cache : getCaches()) { + Cache.ValueWrapper vw = cache.get(key); + if (vw != null && vw.get() != null) { + return decode(vw.get()); + } + } + + T v = value.get(); + if (v != null) { + putRawKey(v, key); + } + return v; + } + + /** + * get, decode and convert Value from cache by argument key, put the non-null value if no cache found. + */ + public U getArgKey(@NotNull Converter converter, @NotNull Object... args) { + return getRawKey(converter, rawKey(args)); + } + + /** + * get, decode and convert Value from cache by raw key, put the non-null value if no cache found. + */ + public U getRawKey(@NotNull Converter converter, @NotNull Object key) { + T t = getRawKey(key); + return converter.convert(t); + } + + /** + * get, decode and convert Value from cache by argument key, put the non-null value if no cache found. + */ + public U getArgKey(@NotNull Converter converter, @NotNull Supplier value, @NotNull Object... args) { + return getRawKey(converter, value, rawKey(args)); + } + + /** + * get, decode and convert Value from cache by raw key, put the non-null value if no cache found. + */ + public U getRawKey(@NotNull Converter converter, @NotNull Supplier value, @NotNull Object key) { + T t = getRawKey(value, key); + return converter.convert(t); + } + + // //////// + + public void putArgKey(@NotNull T value, @NotNull Object... args) { + putRawKey(value, rawKey(args)); + } + + public void putRawKey(@NotNull T value, @NotNull Object key) { + final Object obj = encode(value); + for (Cache cache : getCaches()) { + cache.put(key, obj); + } + } + + /** + * encode and put value to cache, return the decoded existing Value + * + * @see Cache#putIfAbsent(Object, Object) + */ + public T putArgKeyIfPresent(@NotNull T value, @NotNull Object... args) { + return putRawKeyIfPresent(value, rawKey(args)); + } + + /** + * encode and put value to cache, return the decoded existing Value + * + * @see Cache#putIfAbsent(Object, Object) + */ + public T putRawKeyIfPresent(@NotNull T value, @NotNull Object key) { + final Object obj = encode(value); + Cache.ValueWrapper vw = null; + for (Cache cache : getCaches()) { + vw = cache.putIfAbsent(key, obj); + } + return vw == null ? null : decode(vw.get()); + } + + /** + * encode and put value to cache, return the decoded and converted existing Value + * + * @see Cache#putIfAbsent(Object, Object) + */ + public U putArgKeyIfPresent(@NotNull Converter converter, @NotNull T value, @NotNull Object... args) { + return putRawKeyIfPresent(converter, value, rawKey(args)); + } + + /** + * encode and put value to cache, return the decoded and converted existing Value + * + * @see Cache#putIfAbsent(Object, Object) + */ + public U putRawKeyIfPresent(@NotNull Converter converter, @NotNull T value, @NotNull Object key) { + T t = putRawKeyIfPresent(value, key); + return converter.convert(t); + } + + // //////// + + public void evictArgKey(@NotNull Object... args) { + evictRawKey(rawKey(args)); + } + + public void evictRawKey(@NotNull Object key) { + for (Cache cache : getCaches()) { + cache.evict(key); + } + } + + public void evictAll() { + for (Cache cache : getCaches()) { + cache.clear(); + } + } + + public Cache[] getCaches() { + if (status == -1) { + synchronized (caches) { + if (status == -1) { + AssertArgs.notNull(manager, "empty manager={}", manager); + CacheManager cacheManager = beanFactory == null + ? ApplicationContextHelper.getBean(manager) + : beanFactory.getBean(manager, CacheManager.class); + + AssertArgs.notNull(cacheManager, "cacheManager not found, manager={}", manager); + AssertArgs.notNull(names, "cache is null"); + for (int i = 0; i < names.length; i++) { + caches[i] = cacheManager.getCache(names[i]); + AssertArgs.notNull(caches[i], "cache not found,name={}, manager={}", names[i], manager); + } + } + status = 0; + } + } + + return caches; + } + + /** + * decode value from cache, force to cast type if the decoder is null + */ + @SuppressWarnings("unchecked") + public T decode(Object obj) { + return decoder == null ? (T) obj : decoder.convert(obj); + } + + /** + * encode value to cache if the encoder not null + */ + public Object encode(T obj) { + return encoder == null ? obj : encoder.convert(obj); + } + + /** + * generate raw key by args/parmas + * + * @see SimpleKeyGenerator#generateKey(Object...) + */ + public Object rawKey(Object... args) { + return SimpleKeyGenerator.generateKey(args); + } +} diff --git a/wings/slardar/src/main/java/pro/fessional/wings/slardar/cache/WingsCacheHelper.java b/wings/slardar/src/main/java/pro/fessional/wings/slardar/cache/WingsCacheHelper.java index 20bcfb769..7362e3110 100644 --- a/wings/slardar/src/main/java/pro/fessional/wings/slardar/cache/WingsCacheHelper.java +++ b/wings/slardar/src/main/java/pro/fessional/wings/slardar/cache/WingsCacheHelper.java @@ -27,25 +27,25 @@ @Slf4j public class WingsCacheHelper { - private static final Map managers = new ConcurrentHashMap<>(); - private static final Map> namings = new ConcurrentHashMap<>(); - private static CacheManager memory; - private static CacheManager server; + private static final Map NameManager = new ConcurrentHashMap<>(); + private static final Map> ManagerName = new ConcurrentHashMap<>(); + private static CacheManager MemoryManager; + private static CacheManager ServerManager; @Nullable public static CacheManager getCacheManager(String name) { if (WingsCache.Manager.Memory.equalsIgnoreCase(name)) { - return memory; + return MemoryManager; } if (WingsCache.Manager.Server.equalsIgnoreCase(name)) { - return server; + return ServerManager; } - return managers.get(name); + return NameManager.get(name); } public static Set getManagerNames(CacheManager manage) { if (manage == null) return emptySet(); - return namings.getOrDefault(manage, emptySet()); + return ManagerName.getOrDefault(manage, emptySet()); } @Nullable @@ -56,14 +56,14 @@ public static Cache getCache(String manager, String cache) { @NotNull public static Cache getMemoryCache(String name) { - final Cache cache = memory.getCache(name); + final Cache cache = MemoryManager.getCache(name); AssertState.notNull(cache, "memory cache is null, name={}", name); return cache; } @NotNull public static Cache getServerCache(String name) { - final Cache cache = server.getCache(name); + final Cache cache = ServerManager.getCache(name); AssertState.notNull(cache, "server cache is null, name={}", name); return cache; } @@ -72,62 +72,72 @@ public static Cache getServerCache(String name) { * Set CacheManager name and its Resolver */ public static void putManagers(Map mngs) { - managers.putAll(mngs); + NameManager.putAll(mngs); - memory = managers.get(WingsCache.Manager.Memory); - server = managers.get(WingsCache.Manager.Server); + MemoryManager = NameManager.get(WingsCache.Manager.Memory); + ServerManager = NameManager.get(WingsCache.Manager.Server); - namings.clear(); - for (Map.Entry en : managers.entrySet()) { - namings.computeIfAbsent(en.getValue(), k -> new HashSet<>()).add(en.getKey()); + ManagerName.clear(); + for (Map.Entry en : NameManager.entrySet()) { + ManagerName.computeIfAbsent(en.getValue(), k -> new HashSet<>()) + .add(en.getKey()); } } @NotNull public static CacheManager getMemory() { - AssertState.notNull(memory, "Memory CacheManager is null"); - return memory; + AssertState.notNull(MemoryManager, "Memory CacheManager is null"); + return MemoryManager; } @NotNull public static CacheManager getServer() { - AssertState.notNull(server, "Server CacheManager is null"); - return server; + AssertState.notNull(ServerManager, "Server CacheManager is null"); + return ServerManager; } /// - private static final Map, Map> classes = new ConcurrentHashMap<>(); + private static final Map, Map> ClassCacheMeta = new ConcurrentHashMap<>(); public static class Meta { - private final Map> metaMap = new HashMap<>(); - private final Map> objManager = new HashMap<>(); - private final Map> objCache = new HashMap<>(); + private final Map> MngRlvCache = new HashMap<>(); + + private final Map> managerName = new HashMap<>(); // lazy + private final Map> managerCache = new HashMap<>(); // lazy public void initOperation(String cr, String cm, Set cs) { if (!cr.isEmpty()) { - metaMap.computeIfAbsent(cr, k -> new HashSet<>()).addAll(cs); + MngRlvCache.computeIfAbsent(cr, k -> new HashSet<>()).addAll(cs); } if (!cm.isEmpty()) { - metaMap.computeIfAbsent(cm, k -> new HashSet<>()).addAll(cs); + MngRlvCache.computeIfAbsent(cm, k -> new HashSet<>()).addAll(cs); } } + /** + * CacheManager and its names + */ public Map> getManagers() { - if (metaMap.isEmpty()) return objManager; - if (objManager.isEmpty()) { - for (String nm : metaMap.keySet()) { + if (MngRlvCache.isEmpty()) return managerName; + + if (managerName.isEmpty()) { + for (String nm : MngRlvCache.keySet()) { final CacheManager m = getCacheManager(nm); AssertState.notNull(m, "no CacheManager for {}", nm); - objManager.put(m, getManagerNames(m)); + managerName.put(m, getManagerNames(m)); } } - return objManager; + return managerName; } + /** + * manager/resolver and its Caches + */ public Map> getCaches() { - if (metaMap.isEmpty()) return objCache; - if (objCache.isEmpty()) { - for (Map.Entry> en : metaMap.entrySet()) { + if (MngRlvCache.isEmpty()) return managerCache; + + if (managerCache.isEmpty()) { + for (Map.Entry> en : MngRlvCache.entrySet()) { String k = en.getKey(); final CacheManager m = getCacheManager(k); AssertState.notNull(m, "no CacheManager for {}", k); @@ -135,49 +145,67 @@ public Map> getCaches() { for (String c : en.getValue()) { st.add(m.getCache(c)); } - objCache.put(k, st); + managerCache.put(k, st); } } - return objCache; + return managerCache; } } + /** + * manager/resolver name and its caches name + */ @NotNull public static Map> getCacheMeta(Class clz) { return getCacheMeta(clz, Null.Str); } + /** + * manager/resolver name and its caches name + */ @NotNull public static Map> getCacheMeta(Class claz, String method) { - final Map map = classes.get(claz); + final Map map = ClassCacheMeta.get(claz); if (map == null) return emptyMap(); if (method == null) method = Null.Str; final Meta mt = map.get(method); - return mt == null ? emptyMap() : mt.metaMap; + return mt == null ? emptyMap() : mt.MngRlvCache; } + /** + * CacheManager and its names + */ @NotNull public static Map> getManager(Class clz) { return getManager(clz, Null.Str); } + /** + * CacheManager and its names + */ @NotNull public static Map> getManager(Class claz, String method) { - final Map map = classes.get(claz); + final Map map = ClassCacheMeta.get(claz); if (map == null) return emptyMap(); if (method == null) method = Null.Str; final Meta mt = map.get(method); return mt == null ? emptyMap() : mt.getManagers(); } + /** + * manager/resolver and its Caches + */ @NotNull public static Map> getCaches(Class clz) { return getCaches(clz, Null.Str); } + /** + * manager/resolver and its Caches + */ @NotNull public static Map> getCaches(Class claz, String method) { - final Map map = classes.get(claz); + final Map map = ClassCacheMeta.get(claz); if (map == null) return emptyMap(); if (method == null) method = Null.Str; final Meta mt = map.get(method); @@ -186,7 +214,7 @@ public static Map> getCaches(Class claz, String method) { public static void setOperation(Method method, Collection opr) { if (opr == null || opr.isEmpty()) return; - final Map entry = classes.computeIfAbsent(method.getDeclaringClass(), k -> new ConcurrentHashMap<>()); + final Map entry = ClassCacheMeta.computeIfAbsent(method.getDeclaringClass(), k -> new ConcurrentHashMap<>()); final Meta top = entry.computeIfAbsent(Null.Str, k -> new Meta()); final Meta mod = entry.computeIfAbsent(method.getName(), k -> new Meta()); diff --git a/wings/slardar/src/test/java/pro/fessional/wings/slardar/app/service/TestCachingService.java b/wings/slardar/src/test/java/pro/fessional/wings/slardar/app/service/TestCachingService.java index 7d6865b46..bf45b555d 100644 --- a/wings/slardar/src/test/java/pro/fessional/wings/slardar/app/service/TestCachingService.java +++ b/wings/slardar/src/test/java/pro/fessional/wings/slardar/app/service/TestCachingService.java @@ -14,9 +14,11 @@ */ @Service @Slf4j -@CacheConfig(cacheNames = WingsCache.Level.Service + "TestCachingService", cacheManager = WingsCache.Manager.Memory) +@CacheConfig(cacheNames = TestCachingService.CacheName, cacheManager = WingsCache.Manager.Memory) public class TestCachingService { + public static final String CacheName = WingsCache.Level.Service + "TestCachingService"; + @Cacheable public Key cache(Key key) { return key; diff --git a/wings/slardar/src/test/java/pro/fessional/wings/slardar/cache/spring/WingsCacheInterceptorTest.java b/wings/slardar/src/test/java/pro/fessional/wings/slardar/cache/spring/WingsCacheInterceptorTest.java index 00337fe1b..12e780463 100644 --- a/wings/slardar/src/test/java/pro/fessional/wings/slardar/cache/spring/WingsCacheInterceptorTest.java +++ b/wings/slardar/src/test/java/pro/fessional/wings/slardar/cache/spring/WingsCacheInterceptorTest.java @@ -7,7 +7,11 @@ import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.context.ApplicationContext; import pro.fessional.wings.slardar.app.service.TestCachingService; +import pro.fessional.wings.slardar.app.service.TestCachingService.Key; +import pro.fessional.wings.slardar.cache.SimpleCacheTemplate; +import pro.fessional.wings.slardar.cache.WingsCache; /** * @author trydofor @@ -17,40 +21,67 @@ @Slf4j class WingsCacheInterceptorTest { - @Setter(onMethod_ = {@Autowired}) + private final SimpleCacheTemplate cacheTemplate = new SimpleCacheTemplate<>( + WingsCache.Manager.Memory, TestCachingService.CacheName); + + @Setter(onMethod_ = { @Autowired }) protected TestCachingService testCachingService; + @Autowired + public void setApplicationContext(ApplicationContext applicationContext) { + this.cacheTemplate.setBeanFactory(applicationContext); + } + @Test @TmsLink("C13119") void doEvict() { - TestCachingService.Key k1a = new TestCachingService.Key("key1"); - TestCachingService.Key k1b = new TestCachingService.Key("key" + 1); + Key k1a = new Key("key1"); + Key k1b = new Key("key" + 1); { - TestCachingService.Key v1a = testCachingService.cache(k1a); + Key v1a = testCachingService.cache(k1a); Assertions.assertSame(k1a, v1a); - TestCachingService.Key v1b = testCachingService.cache(k1b); + Key v1b = testCachingService.cache(k1b); Assertions.assertSame(k1a, v1b); testCachingService.evict(new CacheEvictKey()); - TestCachingService.Key v1c = testCachingService.cache(k1b); + Key v1c = testCachingService.cache(k1b); Assertions.assertSame(k1b, v1c); } - TestCachingService.Key k2a = new TestCachingService.Key("key2"); - TestCachingService.Key k2b = new TestCachingService.Key("key" + 2); + Key k2a = new Key("key2"); + Key k2b = new Key("key" + 2); { - TestCachingService.Key v2a = testCachingService.cache(k2a); + Key v2a = testCachingService.cache(k2a); Assertions.assertSame(k2a, v2a); testCachingService.evict(new CacheEvictKey().add(k1a).add(k2a)); - TestCachingService.Key v1a = testCachingService.cache(k1a); + Key v1a = testCachingService.cache(k1a); Assertions.assertSame(k1a, v1a); - TestCachingService.Key v2b = testCachingService.cache(k2b); + Key v2b = testCachingService.cache(k2b); + Assertions.assertSame(k2b, v2b); + } + + Key k3a = new Key("key3"); + Key k3b = new Key("key" + 3); + Key k3c = new Key("0key3".substring(1)); + + { + // assert same cache + Key v2b = cacheTemplate.getArgKey(k2a); Assertions.assertSame(k2b, v2b); + + // assert action + cacheTemplate.putArgKey(k3a, k3a); + Key v3a = cacheTemplate.getArgKey(k3b); + Assertions.assertSame(k3a, v3a); + + cacheTemplate.evictArgKey(k3a); + Key v3c = cacheTemplate.getArgKey(() -> k3c, k3b); + Assertions.assertSame(k3c, v3c); } } } \ No newline at end of file diff --git a/wings/warlock/src/test/java/pro/fessional/wings/warlock/service/conf/RuntimeConfServiceTest.java b/wings/warlock/src/test/java/pro/fessional/wings/warlock/service/conf/RuntimeConfServiceTest.java index 2bdb5799f..f6305dcbe 100644 --- a/wings/warlock/src/test/java/pro/fessional/wings/warlock/service/conf/RuntimeConfServiceTest.java +++ b/wings/warlock/src/test/java/pro/fessional/wings/warlock/service/conf/RuntimeConfServiceTest.java @@ -9,8 +9,11 @@ import org.springframework.boot.sql.init.dependency.DependsOnDatabaseInitialization; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.cache.CacheManager; +import org.springframework.context.ApplicationContext; import pro.fessional.mirana.time.Sleep; +import pro.fessional.wings.silencer.enhance.TypeSugar; import pro.fessional.wings.silencer.modulate.RunMode; +import pro.fessional.wings.slardar.cache.SimpleCacheTemplate; import pro.fessional.wings.slardar.cache.WingsCacheHelper; import pro.fessional.wings.testing.silencer.TestingLoggerAssert; import pro.fessional.wings.warlock.caching.CacheConst; @@ -25,6 +28,7 @@ import java.util.Map; import java.util.Set; + /** * Need init database via BootDatabaseTest * Need sleep for cache evict @@ -39,8 +43,17 @@ @DependsOnDatabaseInitialization class RuntimeConfServiceTest { + private final SimpleCacheTemplate cacheTemplate = new SimpleCacheTemplate<>( + CacheConst.RuntimeConfService.CacheManager, + CacheConst.RuntimeConfService.CacheName); + @Setter(onMethod_ = { @Autowired }) - private RuntimeConfService runtimeConfService; + protected RuntimeConfService runtimeConfService; + + @Autowired + public void setApplicationContext(ApplicationContext applicationContext) { + this.cacheTemplate.setBeanFactory(applicationContext); + } @Test @TmsLink("C14008") @@ -73,6 +86,9 @@ private void assertSimple(Class clz, T obj) { Sleep.ignoreInterrupt(1000); // wait for event sync final T obj1 = runtimeConfService.getSimple(clz, clz); Assertions.assertEquals(obj, obj1); + + final Object obj2 = cacheTemplate.getArgKey(clz.getName(), TypeSugar.describe(clz)); + Assertions.assertEquals(obj, obj2); } private void assertEnable(Class clz) { From a2d3f494cc536cffb6a179ca005e5660ad7fb229 Mon Sep 17 00:00:00 2001 From: trydofor Date: Wed, 26 Jun 2024 15:50:57 +0800 Subject: [PATCH 05/51] =?UTF-8?q?=E2=9C=A8=20add=20Started/Elapsed=20time?= =?UTF-8?q?=20to=20starter?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- observe/scripts/wings-starter.sh | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/observe/scripts/wings-starter.sh b/observe/scripts/wings-starter.sh index 77f0e90fb..1997e15bf 100755 --- a/observe/scripts/wings-starter.sh +++ b/observe/scripts/wings-starter.sh @@ -1,5 +1,5 @@ #!/bin/bash -e -THIS_VERSION=2024-06-01 +THIS_VERSION=2024-06-26 ################ system env to use ################ # JAVA_HOME # if JDK_HOME is not valid # JAVA_OPTS # prepend to java args @@ -569,13 +569,15 @@ case "$ARGS_RUN" in echo -e "\033[31mWARN: pid not match, proc-pid=$cid, file-pid=$pid \033[0m" fi - # shellcheck disable=SC2009 - mrs=$(ps -o rss "$cid" | grep -v RSS | numfmt --grouping) - # shellcheck disable=SC2009 - mvs=$(ps -o vsz "$cid" | grep -v VSZ | numfmt --grouping) - echo -e "\033[37;42;1mINFO: ps -o rss -o vsz $cid \033[0m" - echo -e "Resident (RSS) = $(printf '%*s' 12 $mrs) Kb" - echo -e "Virtual (VSZ) = $(printf '%*s' 12 $mvs) Kb" + stm=$(ps -o lstart= "$cid") + etm=$(ps -o etime= "$cid" | tr -d ' ') + mrs=$(ps -o rss= "$cid" | numfmt --grouping) + mvs=$(ps -o vsz= "$cid" | numfmt --grouping) + echo -e "\033[37;42;1mINFO: ps -o rss,vsz,etime,lstart $cid \033[0m" + echo -e "Started Time = $stm" + echo -e "Elapsed Time = $etm" + echo -e "Resident (RSS) = $(printf '%12s' "$mrs") Kb" + echo -e "Virtual (VSZ) = $(printf '%12s' "$mvs") Kb" if [[ "$USER_RUN" == "$USER" ]]; then echo -e "\033[37;42;1mINFO: $(which jstat) -gcutil $cid 1000 3 \033[0m" From 4f7feeebc74eeb16e8741eb170bccb895189aa2c Mon Sep 17 00:00:00 2001 From: trydofor Date: Thu, 27 Jun 2024 14:35:07 +0800 Subject: [PATCH 06/51] =?UTF-8?q?=E2=9C=A8=20conf=5Fruntime=20outline=20ty?= =?UTF-8?q?pe=20#262?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../wings/devs/init/AutogenMainCodeTest.java | 5 +- .../wings/silencer/enhance/TypeSugar.java | 171 +++++++++++++++++- .../wings/silencer/enhance/TypeSugarTest.java | 54 +++++- .../autogen/tables/WinConfRuntimeTable.java | 21 ++- .../tables/daos/WinConfRuntimeDao.java | 19 ++ .../tables/interfaces/IWinConfRuntime.java | 10 + .../autogen/tables/pojos/WinConfRuntime.java | 93 ++++++++++ .../tables/records/WinConfRuntimeRecord.java | 77 ++++++-- .../service/conf/RuntimeConfService.java | 98 +++++++--- .../conf/impl/RuntimeConfServiceImpl.java | 42 +++-- .../04-conf-size/2021-10-26u03-conf-size.sql | 5 +- .../04-conf-size/2021-10-26v03-conf-size.sql | 16 +- .../05-conf/2020-10-25v01-conf_runtime.sql | 21 ++- .../service/conf/RuntimeConfServiceTest.java | 19 +- 14 files changed, 555 insertions(+), 96 deletions(-) diff --git a/radiant/devs-codegen/src/test/java/pro/fessional/wings/devs/init/AutogenMainCodeTest.java b/radiant/devs-codegen/src/test/java/pro/fessional/wings/devs/init/AutogenMainCodeTest.java index 2e2c505eb..65cd5e6be 100644 --- a/radiant/devs-codegen/src/test/java/pro/fessional/wings/devs/init/AutogenMainCodeTest.java +++ b/radiant/devs-codegen/src/test/java/pro/fessional/wings/devs/init/AutogenMainCodeTest.java @@ -11,7 +11,6 @@ import pro.fessional.wings.faceless.codegen.ConstantEnumGenerator; import pro.fessional.wings.faceless.codegen.ConstantEnumJdbcLoader; import pro.fessional.wings.faceless.codegen.JdbcDataLoadHelper; -import pro.fessional.wings.faceless.enums.autogen.StandardLanguage; import pro.fessional.wings.faceless.project.ProjectEnumGenerator; import pro.fessional.wings.faceless.project.ProjectJooqGenerator; import pro.fessional.wings.warlock.project.Warlock2EnumGenerator; @@ -44,7 +43,7 @@ public class AutogenMainCodeTest { @Test void autogen01AllMainCode() { // use wings database - autogen10FacelessAutogen(); // faceless/enums + autogen10FacelessAutogenEnum(); // faceless/enums autogen20WarlockAutogenEnum(); // warlock/enums autogen20WarlockAutogenAuth(); // warlock/security @@ -55,7 +54,7 @@ void autogen01AllMainCode() { // ////////////////// individual test ////////////////// - void autogen10FacelessAutogen() { + void autogen10FacelessAutogenEnum() { final JdbcDataLoadHelper helper = JdbcDataLoadHelper.use(dataSource); final List enums = ConstantEnumJdbcLoader.load(helper); ConstantEnumGenerator.builder() diff --git a/wings/silencer/src/main/java/pro/fessional/wings/silencer/enhance/TypeSugar.java b/wings/silencer/src/main/java/pro/fessional/wings/silencer/enhance/TypeSugar.java index efd8bd97b..f24e98014 100644 --- a/wings/silencer/src/main/java/pro/fessional/wings/silencer/enhance/TypeSugar.java +++ b/wings/silencer/src/main/java/pro/fessional/wings/silencer/enhance/TypeSugar.java @@ -1,19 +1,41 @@ package pro.fessional.wings.silencer.enhance; +import jakarta.annotation.Nullable; +import lombok.SneakyThrows; import org.jetbrains.annotations.NotNull; import org.springframework.core.ResolvableType; import org.springframework.core.convert.TypeDescriptor; +import org.springframework.util.ClassUtils; +import pro.fessional.mirana.data.Null; import pro.fessional.mirana.lock.ArrayKey; import java.lang.reflect.Type; import java.math.BigDecimal; +import java.math.BigInteger; +import java.time.Instant; import java.time.LocalDate; import java.time.LocalDateTime; import java.time.LocalTime; import java.time.OffsetDateTime; import java.time.ZoneId; import java.time.ZonedDateTime; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Date; +import java.util.HashMap; +import java.util.HashSet; +import java.util.LinkedHashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.Optional; +import java.util.Set; +import java.util.TimeZone; +import java.util.TreeMap; +import java.util.TreeSet; import java.util.concurrent.ConcurrentHashMap; +import java.util.regex.Pattern; /** * ResolvableType for Class with Generics with cache, @@ -87,21 +109,154 @@ public static TypeDescriptor describeNew(@NotNull Class clazz, Class... ge */ @NotNull public static ResolvableType resolveNew(@NotNull Class clazz, Class... generics) { - if (generics == null || generics.length == 0) return ResolvableType.forClass(clazz); - final int rootCnt = clazz.getTypeParameters().length; - final ResolvableType[] rootArg = new ResolvableType[rootCnt]; + if (rootCnt == 0) return ResolvableType.forClass(clazz); - int nextIdx = 0; - for (int ri = 0; ri < rootCnt; ri++) { - Class rt = generics[nextIdx++]; - int rc = rt.getTypeParameters().length; - nextIdx = resolve(rt, rootArg, ri, rc, generics, nextIdx); + final int paraCnt = generics == null ? 0 : generics.length; + final ResolvableType[] rootArg = new ResolvableType[rootCnt]; + if (paraCnt <= rootCnt) { + for (int i = 0; i < paraCnt; i++) { + rootArg[i] = ResolvableType.forClass(generics[i]); + } + for (int i = paraCnt; i < rootCnt; i++) { + rootArg[i] = ResolvableType.forClass(Object.class); + } + } + else { + int nextIdx = 0; + for (int ri = 0; ri < rootCnt; ri++) { + Class rt = generics[nextIdx++]; + int rc = rt.getTypeParameters().length; + nextIdx = resolve(rt, rootArg, ri, rc, generics, nextIdx); + } } return ResolvableType.forClassWithGenerics(clazz, rootArg); } + private static final ConcurrentHashMap ShortLong = new ConcurrentHashMap<>(); + private static final Pattern TypeSplit = Pattern.compile("[,<> ]+"); + + public static boolean shorten(@NotNull Class claz) { + String v1 = ShortLong.putIfAbsent(claz.getSimpleName(), claz.getName()); + return v1 == null; + } + + static { + shorten(void.class); + shorten(boolean.class); + shorten(byte.class); + shorten(char.class); + shorten(short.class); + shorten(int.class); + shorten(long.class); + shorten(float.class); + shorten(double.class); + + shorten(Void.class); + shorten(String.class); + shorten(Object.class); + + shorten(Boolean.class); + shorten(Byte.class); + shorten(Character.class); + shorten(Short.class); + shorten(Integer.class); + shorten(Long.class); + shorten(Float.class); + shorten(Double.class); + shorten(BigDecimal.class); + shorten(BigInteger.class); + + shorten(Date.class); + shorten(ZoneId.class); + shorten(TimeZone.class); + shorten(Locale.class); + shorten(LocalDate.class); + shorten(LocalTime.class); + shorten(LocalDateTime.class); + shorten(ZonedDateTime.class); + shorten(OffsetDateTime.class); + shorten(Instant.class); + + shorten(Collection.class); + shorten(Optional.class); + shorten(List.class); + shorten(ArrayList.class); + shorten(LinkedList.class); + shorten(Map.class); + shorten(HashMap.class); + shorten(TreeMap.class); + shorten(LinkedHashMap.class); + shorten(Set.class); + shorten(HashSet.class); + shorten(TreeSet.class); + + shorten(ConcurrentHashMap.class); + } + + @NotNull + public static String outline(@NotNull ResolvableType type) { + return outline(type, true); + } + + @NotNull + public static String outline(@NotNull ResolvableType type, boolean shorten) { + String st = type.toString(); + st = st.replace("?", "Object"); + + if (shorten) { + for (Map.Entry en : ShortLong.entrySet()) { + st = st.replace(en.getValue(), en.getKey()); + } + } + + return st; + } + + @Nullable + public static ResolvableType resolve(String structs) { + if (structs == null) return null; + return CacheResolvable.computeIfAbsent(structs, ignore -> resolveNew(structs)); + } + + @SneakyThrows + @Nullable + public static ResolvableType resolveNew(String structs) { + if (structs == null || structs.isEmpty()) return null; + + // java.util.Map>, java.lang.String> + String[] pts = TypeSplit.split(structs.trim()); + if (pts.length == 0) return null; + + List> clz = new ArrayList<>(pts.length); + for (String str : pts) { + if (str.isEmpty()) continue; // should not happen + + // java.util.List + if (str.equals("?")) { + clz.add(Object.class); + continue; + } + + final String name; + if (str.endsWith("[]")) { + String sub = str.substring(0, str.length() - 2); + name = ShortLong.getOrDefault(sub, sub) + "[]"; + } + else { + name = ShortLong.getOrDefault(str, str); + } + clz.add(ClassUtils.forName(name, null)); + } + + final int size = clz.size(); + if (size == 0) return null; + if (size == 1) return resolve(clz.get(0)); + Class[] ots = clz.subList(1, size).toArray(Null.ClzArr); + return resolve(clz.get(0), ots); + } + private static int resolve(Class rootClz, ResolvableType[] rootArg, int rootIdx, int paraCnt, Class[] nextClz, int nextIdx) { if (paraCnt <= 0) { rootArg[rootIdx] = ResolvableType.forClass(rootClz); diff --git a/wings/silencer/src/test/java/pro/fessional/wings/silencer/enhance/TypeSugarTest.java b/wings/silencer/src/test/java/pro/fessional/wings/silencer/enhance/TypeSugarTest.java index d9ceea328..df6fd6df7 100644 --- a/wings/silencer/src/test/java/pro/fessional/wings/silencer/enhance/TypeSugarTest.java +++ b/wings/silencer/src/test/java/pro/fessional/wings/silencer/enhance/TypeSugarTest.java @@ -1,23 +1,29 @@ package pro.fessional.wings.silencer.enhance; import io.qameta.allure.TmsLink; +import lombok.extern.slf4j.Slf4j; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import org.springframework.core.ResolvableType; import org.springframework.core.convert.TypeDescriptor; +import pro.fessional.mirana.data.R; +import pro.fessional.wings.silencer.app.conf.TestMergingProp; +import java.time.LocalDate; import java.util.List; import java.util.Map; +import java.util.Set; /** * @author trydofor * @since 2024-06-09 */ +@Slf4j public class TypeSugarTest { @Test @TmsLink("C11035") - void test() { + void test() throws ClassNotFoundException { // Map var a0 = ResolvableType.forClassWithGenerics(Map.class, @@ -25,6 +31,7 @@ void test() { ResolvableType.forClassWithGenerics(List.class, Long[].class) ); var a1 = TypeSugar.resolve(Map.class, String.class, List.class, Long[].class); + log.info("type a1={}", a1); var a2 = TypeDescriptor.map(Map.class, TypeDescriptor.valueOf(String.class), @@ -32,6 +39,7 @@ void test() { ); var a3 = TypeSugar.describe(Map.class, String.class, List.class, Long[].class); + log.info("type a3={}", a3); Assertions.assertEquals(a0, a1); Assertions.assertEquals(a2, a3); @@ -41,6 +49,7 @@ void test() { ResolvableType.forClass(String.class) ); var b1 = TypeSugar.resolve(Map.class, List.class, Long[].class, String.class); + log.info("type b1={}", b1); var b2 = TypeDescriptor.map(Map.class, TypeDescriptor.collection(List.class, TypeDescriptor.valueOf(Long[].class)), @@ -48,6 +57,7 @@ void test() { ); var b3 = TypeSugar.describe(Map.class, List.class, Long[].class, String.class); + log.info("type b3={}", b3); Assertions.assertEquals(b0, b1); Assertions.assertEquals(b2, b3); @@ -59,6 +69,7 @@ void test() { ResolvableType.forClass(String.class) ); var c1 = TypeSugar.resolve(Map.class, List.class, List.class, Long[].class, String.class); + log.info("type c1={}", c1); var c2 = TypeDescriptor.map(Map.class, TypeDescriptor.collection(List.class, @@ -68,6 +79,7 @@ void test() { ); var c3 = TypeSugar.describe(Map.class, List.class, List.class, Long[].class, String.class); + log.info("type c3={}", c3); Assertions.assertEquals(c0, c1); Assertions.assertEquals(c2, c3); @@ -75,7 +87,47 @@ void test() { var d1 = TypeSugar.resolve(Map.class, List.class, List.class, Long[].class, String.class); var d2 = TypeSugar.describe(Map.class, List.class, List.class, Long[].class, String.class); var d3 = TypeSugar.describe(Map.class, List.class, List.class, Long[].class, String.class); + + log.info("type d1={}", d1); + log.info("type d3={}", d3); Assertions.assertSame(d0, d1); Assertions.assertSame(d2, d3); + + // + testStructs(TypeSugar.resolve(boolean.class)); + testStructs(TypeSugar.resolve(boolean[].class)); + testStructs(TypeSugar.resolve(byte.class)); + testStructs(TypeSugar.resolve(byte[].class)); + testStructs(TypeSugar.resolve(char.class)); + testStructs(TypeSugar.resolve(char[].class)); + testStructs(TypeSugar.resolve(short.class)); + testStructs(TypeSugar.resolve(short[].class)); + testStructs(TypeSugar.resolve(int.class)); + testStructs(TypeSugar.resolve(int[].class)); + testStructs(TypeSugar.resolve(long.class)); + testStructs(TypeSugar.resolve(long[].class)); + testStructs(TypeSugar.resolve(float.class)); + testStructs(TypeSugar.resolve(float[].class)); + testStructs(TypeSugar.resolve(double.class)); + testStructs(TypeSugar.resolve(double[].class)); + testStructs(TypeSugar.resolve(String.class)); + testStructs(TypeSugar.resolve(String[].class)); + + testStructs(a0); + testStructs(b0); + testStructs(c0); + testStructs(d0); + testStructs(TypeSugar.resolve(R.class, TestMergingProp.Pojo.class)); + testStructs(TypeSugar.resolve(R.class)); + testStructs(TypeSugar.resolve(List.class)); + testStructs(TypeSugar.resolve(Map.class)); + testStructs(TypeSugar.resolve(Set.class, LocalDate.class)); + } + + private void testStructs(ResolvableType rt) { + String str = TypeSugar.outline(rt); + log.info("structs={}", str); + ResolvableType rt1 = TypeSugar.resolve(str); + Assertions.assertEquals(rt, rt1); } } \ No newline at end of file diff --git a/wings/warlock/src/main/java-gen/pro/fessional/wings/warlock/database/autogen/tables/WinConfRuntimeTable.java b/wings/warlock/src/main/java-gen/pro/fessional/wings/warlock/database/autogen/tables/WinConfRuntimeTable.java index 23fb70b8d..5a23cbc4c 100644 --- a/wings/warlock/src/main/java-gen/pro/fessional/wings/warlock/database/autogen/tables/WinConfRuntimeTable.java +++ b/wings/warlock/src/main/java-gen/pro/fessional/wings/warlock/database/autogen/tables/WinConfRuntimeTable.java @@ -6,10 +6,10 @@ import org.jetbrains.annotations.NotNull; import org.jooq.Field; -import org.jooq.Function7; +import org.jooq.Function8; import org.jooq.Name; import org.jooq.Records; -import org.jooq.Row7; +import org.jooq.Row8; import org.jooq.Schema; import org.jooq.SelectField; import org.jooq.Table; @@ -83,10 +83,15 @@ public Class getRecordType() { */ public final TableField Initial = createField(DSL.name("initial"), SQLDataType.CLOB.nullable(false), this, ""); + /** + * The column win_conf_runtime.outline. + */ + public final TableField Outline = createField(DSL.name("outline"), SQLDataType.VARCHAR(5000).nullable(false).defaultValue(DSL.inline("", SQLDataType.VARCHAR)), this, ""); + /** * The column win_conf_runtime.comment. */ - public final TableField Comment = createField(DSL.name("comment"), SQLDataType.VARCHAR(500).nullable(false).defaultValue(DSL.inline("", SQLDataType.VARCHAR)), this, ""); + public final TableField Comment = createField(DSL.name("comment"), SQLDataType.VARCHAR(5000).nullable(false).defaultValue(DSL.inline("", SQLDataType.VARCHAR)), this, ""); /** * The column win_conf_runtime.handler. @@ -172,18 +177,18 @@ public WinConfRuntimeTable rename(Table name) { } // ------------------------------------------------------------------------- - // Row7 type methods + // Row8 type methods // ------------------------------------------------------------------------- @Override - public Row7 fieldsRow() { - return (Row7) super.fieldsRow(); + public Row8 fieldsRow() { + return (Row8) super.fieldsRow(); } /** * Convenience mapping calling {@link SelectField#convertFrom(Function)}. */ - public SelectField mapping(Function7 from) { + public SelectField mapping(Function8 from) { return convertFrom(Records.mapping(from)); } @@ -191,7 +196,7 @@ public SelectField mapping(Function7 SelectField mapping(Class toType, Function7 from) { + public SelectField mapping(Class toType, Function8 from) { return convertFrom(toType, Records.mapping(from)); } diff --git a/wings/warlock/src/main/java-gen/pro/fessional/wings/warlock/database/autogen/tables/daos/WinConfRuntimeDao.java b/wings/warlock/src/main/java-gen/pro/fessional/wings/warlock/database/autogen/tables/daos/WinConfRuntimeDao.java index 4e90bea4d..d7b810a93 100644 --- a/wings/warlock/src/main/java-gen/pro/fessional/wings/warlock/database/autogen/tables/daos/WinConfRuntimeDao.java +++ b/wings/warlock/src/main/java-gen/pro/fessional/wings/warlock/database/autogen/tables/daos/WinConfRuntimeDao.java @@ -164,6 +164,25 @@ public List fetchByInitial(Collection values) return fetch(WinConfRuntimeTable.WinConfRuntime.Initial, values); } + /** + * Fetch records that have outline BETWEEN lowerInclusive AND + * upperInclusive + */ + public List fetchRangeOfOutline(String lowerInclusive, String upperInclusive) { + return fetchRange(WinConfRuntimeTable.WinConfRuntime.Outline, lowerInclusive, upperInclusive); + } + + /** + * Fetch records that have outline IN (values) + */ + public List fetchByOutline(String... values) { + return fetch(WinConfRuntimeTable.WinConfRuntime.Outline, values); + } + + public List fetchByOutline(Collection values) { + return fetch(WinConfRuntimeTable.WinConfRuntime.Outline, values); + } + /** * Fetch records that have comment BETWEEN lowerInclusive AND * upperInclusive diff --git a/wings/warlock/src/main/java-gen/pro/fessional/wings/warlock/database/autogen/tables/interfaces/IWinConfRuntime.java b/wings/warlock/src/main/java-gen/pro/fessional/wings/warlock/database/autogen/tables/interfaces/IWinConfRuntime.java index 350fd1cc6..d4572a3b6 100644 --- a/wings/warlock/src/main/java-gen/pro/fessional/wings/warlock/database/autogen/tables/interfaces/IWinConfRuntime.java +++ b/wings/warlock/src/main/java-gen/pro/fessional/wings/warlock/database/autogen/tables/interfaces/IWinConfRuntime.java @@ -72,6 +72,16 @@ public interface IWinConfRuntime extends Serializable { */ public String getInitial(); + /** + * Setter for win_conf_runtime.outline. + */ + public void setOutline(String value); + + /** + * Getter for win_conf_runtime.outline. + */ + public String getOutline(); + /** * Setter for win_conf_runtime.comment. */ diff --git a/wings/warlock/src/main/java-gen/pro/fessional/wings/warlock/database/autogen/tables/pojos/WinConfRuntime.java b/wings/warlock/src/main/java-gen/pro/fessional/wings/warlock/database/autogen/tables/pojos/WinConfRuntime.java index f837e92d6..8600ca6ce 100644 --- a/wings/warlock/src/main/java-gen/pro/fessional/wings/warlock/database/autogen/tables/pojos/WinConfRuntime.java +++ b/wings/warlock/src/main/java-gen/pro/fessional/wings/warlock/database/autogen/tables/pojos/WinConfRuntime.java @@ -34,6 +34,7 @@ public class WinConfRuntime implements IWinConfRuntime { private String current; private String previous; private String initial; + private String outline; private String comment; private String handler; @@ -45,6 +46,7 @@ public WinConfRuntime(IWinConfRuntime value) { this.current = value.getCurrent(); this.previous = value.getPrevious(); this.initial = value.getInitial(); + this.outline = value.getOutline(); this.comment = value.getComment(); this.handler = value.getHandler(); } @@ -55,6 +57,7 @@ public WinConfRuntime( String current, String previous, String initial, + String outline, String comment, String handler ) { @@ -63,6 +66,7 @@ public WinConfRuntime( this.current = current; this.previous = previous; this.initial = initial; + this.outline = outline; this.comment = comment; this.handler = handler; } @@ -467,6 +471,86 @@ public void setInitialIf(UnaryOperator initial) { } + /** + * Getter for win_conf_runtime.outline. + */ + @Override + public String getOutline() { + return this.outline; + } + + /** + * Setter for win_conf_runtime.outline. + */ + @Override + public void setOutline(String outline) { + this.outline = outline; + } + + @Transient + public void setOutlineIf(String outline, boolean bool) { + if (bool) { + this.outline = outline; + } + } + + @Transient + public void setOutlineIf(Supplier outline, boolean bool) { + if (bool) { + this.outline = outline.get(); + } + } + + @Transient + public void setOutlineIf(String outline, Predicate bool) { + if (bool.test(outline)) { + this.outline = outline; + } + } + + @Transient + public void setOutlineIf(String outline, Predicate bool, Supplier... outlines) { + if (bool.test(outline)) { + this.outline = outline; + return; + } + for (Supplier supplier : outlines) { + outline = supplier.get(); + if (bool.test(outline)) { + this.outline = outline; + return; + } + } + } + + @Transient + public void setOutlineIfNot(String outline, Predicate bool) { + if (!bool.test(outline)) { + this.outline = outline; + } + } + + @Transient + public void setOutlineIfNot(String outline, Predicate bool, Supplier... outlines) { + if (!bool.test(outline)) { + this.outline = outline; + return; + } + for (Supplier supplier : outlines) { + outline = supplier.get(); + if (!bool.test(outline)) { + this.outline = outline; + return; + } + } + } + + @Transient + public void setOutlineIf(UnaryOperator outline) { + this.outline = outline.apply(this.outline); + } + + /** * Getter for win_conf_runtime.comment. */ @@ -666,6 +750,12 @@ else if (!this.previous.equals(other.previous)) } else if (!this.initial.equals(other.initial)) return false; + if (this.outline == null) { + if (other.outline != null) + return false; + } + else if (!this.outline.equals(other.outline)) + return false; if (this.comment == null) { if (other.comment != null) return false; @@ -690,6 +780,7 @@ public int hashCode() { result = prime * result + ((this.current == null) ? 0 : this.current.hashCode()); result = prime * result + ((this.previous == null) ? 0 : this.previous.hashCode()); result = prime * result + ((this.initial == null) ? 0 : this.initial.hashCode()); + result = prime * result + ((this.outline == null) ? 0 : this.outline.hashCode()); result = prime * result + ((this.comment == null) ? 0 : this.comment.hashCode()); result = prime * result + ((this.handler == null) ? 0 : this.handler.hashCode()); return result; @@ -704,6 +795,7 @@ public String toString() { sb.append(", ").append(current); sb.append(", ").append(previous); sb.append(", ").append(initial); + sb.append(", ").append(outline); sb.append(", ").append(comment); sb.append(", ").append(handler); @@ -722,6 +814,7 @@ public void from(IWinConfRuntime from) { setCurrent(from.getCurrent()); setPrevious(from.getPrevious()); setInitial(from.getInitial()); + setOutline(from.getOutline()); setComment(from.getComment()); setHandler(from.getHandler()); } diff --git a/wings/warlock/src/main/java-gen/pro/fessional/wings/warlock/database/autogen/tables/records/WinConfRuntimeRecord.java b/wings/warlock/src/main/java-gen/pro/fessional/wings/warlock/database/autogen/tables/records/WinConfRuntimeRecord.java index d1bc6e3ca..32d280c84 100644 --- a/wings/warlock/src/main/java-gen/pro/fessional/wings/warlock/database/autogen/tables/records/WinConfRuntimeRecord.java +++ b/wings/warlock/src/main/java-gen/pro/fessional/wings/warlock/database/autogen/tables/records/WinConfRuntimeRecord.java @@ -6,8 +6,8 @@ import org.jooq.Field; import org.jooq.Record1; -import org.jooq.Record7; -import org.jooq.Row7; +import org.jooq.Record8; +import org.jooq.Row8; import org.jooq.impl.UpdatableRecordImpl; import pro.fessional.wings.warlock.database.autogen.tables.WinConfRuntimeTable; import pro.fessional.wings.warlock.database.autogen.tables.interfaces.IWinConfRuntime; @@ -28,7 +28,7 @@ comments = "This class is generated by jOOQ" ) @SuppressWarnings({ "all", "unchecked", "rawtypes", "this-escape" }) -public class WinConfRuntimeRecord extends UpdatableRecordImpl implements Record7, IWinConfRuntime { +public class WinConfRuntimeRecord extends UpdatableRecordImpl implements Record8, IWinConfRuntime { private static final long serialVersionUID = 1L; @@ -112,12 +112,28 @@ public String getInitial() { return (String) get(4); } + /** + * Setter for win_conf_runtime.outline. + */ + @Override + public void setOutline(String value) { + set(5, value); + } + + /** + * Getter for win_conf_runtime.outline. + */ + @Override + public String getOutline() { + return (String) get(5); + } + /** * Setter for win_conf_runtime.comment. */ @Override public void setComment(String value) { - set(5, value); + set(6, value); } /** @@ -125,7 +141,7 @@ public void setComment(String value) { */ @Override public String getComment() { - return (String) get(5); + return (String) get(6); } /** @@ -133,7 +149,7 @@ public String getComment() { */ @Override public void setHandler(String value) { - set(6, value); + set(7, value); } /** @@ -141,7 +157,7 @@ public void setHandler(String value) { */ @Override public String getHandler() { - return (String) get(6); + return (String) get(7); } // ------------------------------------------------------------------------- @@ -154,17 +170,17 @@ public Record1 key() { } // ------------------------------------------------------------------------- - // Record7 type implementation + // Record8 type implementation // ------------------------------------------------------------------------- @Override - public Row7 fieldsRow() { - return (Row7) super.fieldsRow(); + public Row8 fieldsRow() { + return (Row8) super.fieldsRow(); } @Override - public Row7 valuesRow() { - return (Row7) super.valuesRow(); + public Row8 valuesRow() { + return (Row8) super.valuesRow(); } @Override @@ -194,11 +210,16 @@ public Field field5() { @Override public Field field6() { - return WinConfRuntimeTable.WinConfRuntime.Comment; + return WinConfRuntimeTable.WinConfRuntime.Outline; } @Override public Field field7() { + return WinConfRuntimeTable.WinConfRuntime.Comment; + } + + @Override + public Field field8() { return WinConfRuntimeTable.WinConfRuntime.Handler; } @@ -229,11 +250,16 @@ public String component5() { @Override public String component6() { - return getComment(); + return getOutline(); } @Override public String component7() { + return getComment(); + } + + @Override + public String component8() { return getHandler(); } @@ -264,11 +290,16 @@ public String value5() { @Override public String value6() { - return getComment(); + return getOutline(); } @Override public String value7() { + return getComment(); + } + + @Override + public String value8() { return getHandler(); } @@ -304,18 +335,24 @@ public WinConfRuntimeRecord value5(String value) { @Override public WinConfRuntimeRecord value6(String value) { - setComment(value); + setOutline(value); return this; } @Override public WinConfRuntimeRecord value7(String value) { + setComment(value); + return this; + } + + @Override + public WinConfRuntimeRecord value8(String value) { setHandler(value); return this; } @Override - public WinConfRuntimeRecord values(String value1, Boolean value2, String value3, String value4, String value5, String value6, String value7) { + public WinConfRuntimeRecord values(String value1, Boolean value2, String value3, String value4, String value5, String value6, String value7, String value8) { value1(value1); value2(value2); value3(value3); @@ -323,6 +360,7 @@ public WinConfRuntimeRecord values(String value1, Boolean value2, String value3, value5(value5); value6(value6); value7(value7); + value8(value8); return this; } @@ -337,6 +375,7 @@ public void from(IWinConfRuntime from) { setCurrent(from.getCurrent()); setPrevious(from.getPrevious()); setInitial(from.getInitial()); + setOutline(from.getOutline()); setComment(from.getComment()); setHandler(from.getHandler()); resetChangedOnNotNull(); @@ -362,7 +401,7 @@ public WinConfRuntimeRecord() { /** * Create a detached, initialised WinConfRuntimeRecord */ - public WinConfRuntimeRecord(String key, Boolean enabled, String current, String previous, String initial, String comment, String handler) { + public WinConfRuntimeRecord(String key, Boolean enabled, String current, String previous, String initial, String outline, String comment, String handler) { super(WinConfRuntimeTable.WinConfRuntime); setKey(key); @@ -370,6 +409,7 @@ public WinConfRuntimeRecord(String key, Boolean enabled, String current, String setCurrent(current); setPrevious(previous); setInitial(initial); + setOutline(outline); setComment(comment); setHandler(handler); resetChangedOnNotNull(); @@ -387,6 +427,7 @@ public WinConfRuntimeRecord(WinConfRuntime value) { setCurrent(value.getCurrent()); setPrevious(value.getPrevious()); setInitial(value.getInitial()); + setOutline(value.getOutline()); setComment(value.getComment()); setHandler(value.getHandler()); resetChangedOnNotNull(); diff --git a/wings/warlock/src/main/java/pro/fessional/wings/warlock/service/conf/RuntimeConfService.java b/wings/warlock/src/main/java/pro/fessional/wings/warlock/service/conf/RuntimeConfService.java index 56bddefff..e3fa345a3 100644 --- a/wings/warlock/src/main/java/pro/fessional/wings/warlock/service/conf/RuntimeConfService.java +++ b/wings/warlock/src/main/java/pro/fessional/wings/warlock/service/conf/RuntimeConfService.java @@ -1,12 +1,14 @@ package pro.fessional.wings.warlock.service.conf; import org.jetbrains.annotations.NotNull; +import org.springframework.core.ResolvableType; import org.springframework.core.convert.TypeDescriptor; import pro.fessional.mirana.cast.EnumConvertor; import pro.fessional.wings.silencer.enhance.TypeSugar; import java.util.List; import java.util.Map; +import java.util.Set; /** * Support for ConversionService and Json parsing configuration @@ -102,6 +104,22 @@ default List getList(@NotNull Enum key, @NotNull Class type) { return getList(EnumConvertor.enum2Str(key), type); } + + @NotNull + default Set getSet(@NotNull String key, @NotNull Class type) { + return getObject(key, TypeSugar.describe(Set.class, type)); + } + + @NotNull + default Set getSet(@NotNull Class key, @NotNull Class type) { + return getSet(key.getName(), type); + } + + @NotNull + default Set getSet(@NotNull Enum key, @NotNull Class type) { + return getSet(EnumConvertor.enum2Str(key), type); + } + @NotNull default Map getMap(@NotNull String key, @NotNull Class keyType, @NotNull Class valueType) { return getObject(key, TypeSugar.describe(Map.class, keyType, valueType)); @@ -137,55 +155,87 @@ default T getObject(@NotNull Enum key, @NotNull TypeDescriptor type) { /** - * set value of config + * set value of config, return false if not found * * @param key key * @param value config */ - void setObject(@NotNull String key, @NotNull Object value); + boolean setObject(@NotNull String key, @NotNull Object value); - default void setObject(@NotNull Class key, @NotNull Object value) { - setObject(key.getName(), value); + default boolean setObject(@NotNull Class key, @NotNull Object value) { + return setObject(key.getName(), value); } - default void setObject(@NotNull Enum key, @NotNull Object value) { - setObject(EnumConvertor.enum2Str(key), value); + default boolean setObject(@NotNull Enum key, @NotNull Object value) { + return setObject(EnumConvertor.enum2Str(key), value); } /** - * create new config + * create new config, return true if handled * * @param key config key * @param value config value - * @param comment config comment - * @param handler type handler name + * @param comment config comment, empty if null + * @param handler type handler name, auto select if null + * @param outline type outline, resolved from value if null * @return whether handled */ - boolean newObject(@NotNull String key, @NotNull Object value, String comment, @NotNull String handler); + boolean newObject(@NotNull String key, @NotNull Object value, String comment, String handler, ResolvableType outline); - default boolean newObject(@NotNull Class key, @NotNull Object value, String comment, @NotNull String handler) { - return newObject(key.getName(), value, comment, handler); + default boolean newObject(@NotNull Class key, @NotNull Object value, String comment, String handler, ResolvableType outline) { + return newObject(key.getName(), value, comment, handler, outline); } - default boolean newObject(@NotNull Enum key, @NotNull Object value, String comment, @NotNull String handler) { - return newObject(EnumConvertor.enum2Str(key), value, comment, handler); + default boolean newObject(@NotNull Enum key, @NotNull Object value, String comment, String handler, ResolvableType outline) { + return newObject(EnumConvertor.enum2Str(key), value, comment, handler, outline); } - /** - * create new config with auto selected handler, success or throw an error. - * - * @param key config key - * @param value config value - * @param comment config comment - */ - boolean newObject(@NotNull String key, @NotNull Object value, String comment); + default boolean newObject(@NotNull String key, @NotNull Object value, String comment, String handler, TypeDescriptor outline) { + return newObject(key, value, comment, handler, outline == null ? (ResolvableType) null : outline.getResolvableType()); + } + + default boolean newObject(@NotNull Class key, @NotNull Object value, String comment, String handler, TypeDescriptor outline) { + return newObject(key.getName(), value, comment, handler, outline == null ? (ResolvableType) null : outline.getResolvableType()); + } + + default boolean newObject(@NotNull Enum key, @NotNull Object value, String comment, String handler, TypeDescriptor outline) { + return newObject(EnumConvertor.enum2Str(key), value, comment, handler, outline == null ? (ResolvableType) null : outline.getResolvableType()); + } + + default boolean newObject(@NotNull String key, @NotNull Object value, String comment, String handler, Class outline, Class... gernics) { + return newObject(key, value, comment, handler, outline == null ? (ResolvableType) null : TypeSugar.resolve(outline, gernics)); + } + + default boolean newObject(@NotNull Class key, @NotNull Object value, String comment, String handler, Class outline, Class... gernics) { + return newObject(key.getName(), value, comment, handler, outline == null ? (ResolvableType) null : TypeSugar.resolve(outline, gernics)); + } + + default boolean newObject(@NotNull Enum key, @NotNull Object value, String comment, String handler, Class outline, Class... gernics) { + return newObject(EnumConvertor.enum2Str(key), value, comment, handler, outline == null ? (ResolvableType) null : TypeSugar.resolve(outline, gernics)); + } + + default boolean newObject(@NotNull String key, @NotNull Object value, String comment, String handler) { + return newObject(key, value, comment, handler, (ResolvableType) null); + } + + default boolean newObject(@NotNull Class key, @NotNull Object value, String comment, String handler) { + return newObject(key.getName(), value, comment, handler, (ResolvableType) null); + } + + default boolean newObject(@NotNull Enum key, @NotNull Object value, String comment, String handler) { + return newObject(EnumConvertor.enum2Str(key), value, comment, handler, (ResolvableType) null); + } + + default boolean newObject(@NotNull String key, @NotNull Object value, String comment) { + return newObject(key, value, comment, null, (ResolvableType) null); + } default boolean newObject(@NotNull Class key, @NotNull Object value, String comment) { - return newObject(key.getName(), value, comment); + return newObject(key.getName(), value, comment, null, (ResolvableType) null); } default boolean newObject(@NotNull Enum key, @NotNull Object value, String comment) { - return newObject(EnumConvertor.enum2Str(key), value, comment); + return newObject(EnumConvertor.enum2Str(key), value, comment, null, (ResolvableType) null); } /** diff --git a/wings/warlock/src/main/java/pro/fessional/wings/warlock/service/conf/impl/RuntimeConfServiceImpl.java b/wings/warlock/src/main/java/pro/fessional/wings/warlock/service/conf/impl/RuntimeConfServiceImpl.java index a5f7dcf9f..9c63b6926 100644 --- a/wings/warlock/src/main/java/pro/fessional/wings/warlock/service/conf/impl/RuntimeConfServiceImpl.java +++ b/wings/warlock/src/main/java/pro/fessional/wings/warlock/service/conf/impl/RuntimeConfServiceImpl.java @@ -10,6 +10,7 @@ import org.springframework.cache.annotation.CacheEvict; import org.springframework.cache.annotation.Cacheable; import org.springframework.context.event.EventListener; +import org.springframework.core.ResolvableType; import org.springframework.core.convert.ConversionService; import org.springframework.core.convert.TypeDescriptor; import pro.fessional.mirana.best.AssertArgs; @@ -25,7 +26,6 @@ import pro.fessional.wings.warlock.event.cache.TableChangeEvent; import pro.fessional.wings.warlock.service.conf.RuntimeConfService; -import java.util.ArrayList; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; @@ -70,7 +70,7 @@ public T getObject(@NotNull String key, @NotNull TypeDescriptor type) { } @Override - public void setObject(@NotNull String key, @NotNull Object value) { + public boolean setObject(@NotNull String key, @NotNull Object value) { final WinConfRuntimeTable t = winConfRuntimeDao.getTable(); final String handler = winConfRuntimeDao.fetchOne(String.class, t, t.Key.eq(key), t.Handler); @@ -92,24 +92,46 @@ public void setObject(@NotNull String key, @NotNull Object value) { field.put(t.Current.getName(), List.of(str)); }); } + + return rc >= 1; } @Override - public boolean newObject(@NotNull String key, @NotNull Object value, String comment, @NotNull String handler) { + public boolean newObject(@NotNull String key, @NotNull Object value, String comment, String handler, ResolvableType structs) { AssertArgs.notEmpty(key, "empty key"); + final Class valClaz = value.getClass(); + + ConversionService service = null; + if (handler == null) { // auto select + for (var en : handlerMap.entrySet()) { + if (en.getValue().canConvert(valClaz, String.class)) { + service = en.getValue(); + handler = en.getKey(); + break; + } + } + } + else { // specified + ConversionService cs = handlerMap.get(handler); + if (cs.canConvert(valClaz, String.class)) { + service = cs; + } + } - ConversionService service = handlerMap.get(handler); - if (service == null || !service.canConvert(value.getClass(), String.class)) return false; + if (service == null) return false; final String str = service.convert(value, String.class); AssertArgs.notNull(str, "can not covert value to string, key={}", key); + if (structs == null) structs = ResolvableType.forClass(valClaz); + final WinConfRuntime pojo = new WinConfRuntime(); pojo.setKey(key); pojo.setEnabled(true); pojo.setCurrent(str); pojo.setPrevious(Null.Str); pojo.setInitial(str); + pojo.setOutline(TypeSugar.outline(structs)); pojo.setComment(StringUtils.trimToEmpty(comment)); pojo.setHandler(handler); @@ -128,16 +150,6 @@ public boolean newObject(@NotNull String key, @NotNull Object value, String comm return rc >= 1; } - @Override - public boolean newObject(@NotNull String key, @NotNull Object value, String comment) { - for (String handler : new ArrayList<>(handlerMap.keySet())) { - if (newObject(key, value, comment, handler)) { - return true; - } - } - return false; - } - @Override public boolean enable(@NotNull String key, boolean enable) { WinConfRuntimeTable t = winConfRuntimeDao.getTable(); diff --git a/wings/warlock/src/main/resources/wings-flywave/branch/somefix/04-conf-size/2021-10-26u03-conf-size.sql b/wings/warlock/src/main/resources/wings-flywave/branch/somefix/04-conf-size/2021-10-26u03-conf-size.sql index e164af59b..8bbd1e773 100644 --- a/wings/warlock/src/main/resources/wings-flywave/branch/somefix/04-conf-size/2021-10-26u03-conf-size.sql +++ b/wings/warlock/src/main/resources/wings-flywave/branch/somefix/04-conf-size/2021-10-26u03-conf-size.sql @@ -1,5 +1,8 @@ ALTER TABLE `win_conf_runtime` DROP COLUMN `enabled`, + DROP COLUMN `outline`, CHANGE COLUMN `current` `current` VARCHAR(5000) NOT NULL DEFAULT '' COMMENT 'current value', CHANGE COLUMN `previous` `previous` VARCHAR(5000) NOT NULL DEFAULT '' COMMENT 'previous value', - CHANGE COLUMN `initial` `initial` VARCHAR(5000) NOT NULL DEFAULT '' COMMENT 'initial value'; + CHANGE COLUMN `initial` `initial` VARCHAR(5000) NOT NULL DEFAULT '' COMMENT 'initial value', + CHANGE COLUMN `comment` `comment` VARCHAR(500) NOT NULL DEFAULT '' COMMENT 'comment', + CHANGE COLUMN `handler` `handler` VARCHAR(200) NOT NULL DEFAULT 'prop' COMMENT 'data handling:prop|json'; diff --git a/wings/warlock/src/main/resources/wings-flywave/branch/somefix/04-conf-size/2021-10-26v03-conf-size.sql b/wings/warlock/src/main/resources/wings-flywave/branch/somefix/04-conf-size/2021-10-26v03-conf-size.sql index 35ec303fb..5f5b71014 100644 --- a/wings/warlock/src/main/resources/wings-flywave/branch/somefix/04-conf-size/2021-10-26v03-conf-size.sql +++ b/wings/warlock/src/main/resources/wings-flywave/branch/somefix/04-conf-size/2021-10-26v03-conf-size.sql @@ -1,5 +1,17 @@ ALTER TABLE `win_conf_runtime` - ADD COLUMN `enabled` TINYINT(1) NOT NULL DEFAULT '1' COMMENT 'enabled' AFTER `key`, + ADD COLUMN `enabled` TINYINT(1) NOT NULL DEFAULT '1' COMMENT 'enabled' AFTER `key`, + ADD COLUMN `outline` VARCHAR(5000) NOT NULL DEFAULT '' COMMENT 'value ResolvableType' AFTER `initial`, CHANGE COLUMN `current` `current` TEXT NOT NULL COMMENT 'current value', CHANGE COLUMN `previous` `previous` TEXT NOT NULL COMMENT 'previous value', - CHANGE COLUMN `initial` `initial` TEXT NOT NULL COMMENT 'initial value'; + CHANGE COLUMN `initial` `initial` TEXT NOT NULL COMMENT 'initial value', + CHANGE COLUMN `comment` `comment` VARCHAR(5000) NOT NULL DEFAULT '' COMMENT 'usage or purpose', + CHANGE COLUMN `handler` `handler` VARCHAR(200) NOT NULL DEFAULT 'prop' COMMENT 'data handling:prop|json|kryo'; + +UPDATE `win_conf_runtime` +SET outline = `key` +WHERE `key` = 'pro.fessional.wings.warlock.service.conf.mode.RunMode'; + +UPDATE `win_conf_runtime` +SET outline = `key`, + `initial` = 'Nothing' +WHERE `key` = 'pro.fessional.wings.warlock.service.conf.mode.ApiMode'; diff --git a/wings/warlock/src/main/resources/wings-flywave/master/05-conf/2020-10-25v01-conf_runtime.sql b/wings/warlock/src/main/resources/wings-flywave/master/05-conf/2020-10-25v01-conf_runtime.sql index c9c7ff178..e3ebc47bc 100644 --- a/wings/warlock/src/main/resources/wings-flywave/master/05-conf/2020-10-25v01-conf_runtime.sql +++ b/wings/warlock/src/main/resources/wings-flywave/master/05-conf/2020-10-25v01-conf_runtime.sql @@ -1,16 +1,17 @@ CREATE TABLE `win_conf_runtime` ( - `key` VARCHAR(200) NOT NULL COMMENT 'conf key:Enum|Class|String', - `enabled` TINYINT(1) NOT NULL DEFAULT '1' COMMENT 'enabled', - `current` TEXT NOT NULL COMMENT 'current value', - `previous` TEXT NOT NULL COMMENT 'previous value', - `initial` TEXT NOT NULL COMMENT 'initial value', - `comment` VARCHAR(500) NOT NULL DEFAULT '' COMMENT 'comment', - `handler` VARCHAR(200) NOT NULL DEFAULT 'prop' COMMENT 'data handling:prop|json', + `key` VARCHAR(200) NOT NULL COMMENT 'conf key:Enum|Class|String', + `enabled` TINYINT(1) NOT NULL DEFAULT '1' COMMENT 'enabled', + `current` TEXT NOT NULL COMMENT 'current value', + `previous` TEXT NOT NULL COMMENT 'previous value', + `initial` TEXT NOT NULL COMMENT 'initial value', + `outline` VARCHAR(5000) NOT NULL DEFAULT '' COMMENT 'value ResolvableType', + `comment` VARCHAR(5000) NOT NULL DEFAULT '' COMMENT 'usage or purpose', + `handler` VARCHAR(200) NOT NULL DEFAULT 'prop' COMMENT 'data handling:prop|json|kryo', PRIMARY KEY (`key`) ) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COMMENT ='110/Runtime Config'; -- ----------- -INSERT IGNORE INTO `win_conf_runtime` (`key`, `current`, `previous`, `initial`, `comment`) -VALUES ('pro.fessional.wings.warlock.service.conf.mode.RunMode', 'Local', '', 'Local', 'RunMode') - , ('pro.fessional.wings.warlock.service.conf.mode.ApiMode', 'Nothing', '', 'Local', 'ApiMode'); +INSERT IGNORE INTO `win_conf_runtime` (`key`, `current`, `previous`, `initial`, `outline`, `comment`, `handler`) +VALUES ('pro.fessional.wings.warlock.service.conf.mode.RunMode', 'Local', 'pro.fessional.wings.warlock.service.conf.mode.RunMode', '', 'Local', 'RunMode', 'prop') + , ('pro.fessional.wings.warlock.service.conf.mode.ApiMode', 'Nothing', 'pro.fessional.wings.warlock.service.conf.mode.ApiMode', '', 'Nothing', 'ApiMode', 'prop'); diff --git a/wings/warlock/src/test/java/pro/fessional/wings/warlock/service/conf/RuntimeConfServiceTest.java b/wings/warlock/src/test/java/pro/fessional/wings/warlock/service/conf/RuntimeConfServiceTest.java index f6305dcbe..3815e7be1 100644 --- a/wings/warlock/src/test/java/pro/fessional/wings/warlock/service/conf/RuntimeConfServiceTest.java +++ b/wings/warlock/src/test/java/pro/fessional/wings/warlock/service/conf/RuntimeConfServiceTest.java @@ -20,6 +20,7 @@ import pro.fessional.wings.warlock.service.conf.impl.RuntimeConfServiceImpl; import java.math.BigDecimal; +import java.time.LocalDate; import java.time.LocalDateTime; import java.time.ZoneId; import java.time.ZonedDateTime; @@ -82,7 +83,7 @@ void testSimple() { } private void assertSimple(Class clz, T obj) { - runtimeConfService.newObject(clz, obj, "test " + clz.getSimpleName()); + runtimeConfService.newObject(clz, obj, "test " + clz.getSimpleName(), null); Sleep.ignoreInterrupt(1000); // wait for event sync final T obj1 = runtimeConfService.getSimple(clz, clz); Assertions.assertEquals(obj, obj1); @@ -106,15 +107,21 @@ private void assertEnable(Class clz) { @TmsLink("C14009") void testCollection() { List ls = List.of("Jan", "Fer"); - runtimeConfService.newObject(List.class, ls, "test list"); + runtimeConfService.newObject(List.class, ls, "test list", null, List.class, String.class); Sleep.ignoreInterrupt(1000); // wait for event sync final List ls1 = runtimeConfService.getList(List.class, String.class); Assertions.assertEquals(ls, ls1); + Set ss = Set.of(LocalDate.now(), LocalDate.now().plusDays(1)); + runtimeConfService.newObject(Set.class, ss, "test set LocalDate", null, Set.class, LocalDate.class); + Sleep.ignoreInterrupt(1000); // wait for event sync + final Set ss1 = runtimeConfService.getSet(Set.class, LocalDate.class); + Assertions.assertEquals(ss, ss1); + Map map = new HashMap<>(); map.put("Jan", true); map.put("Fer", false); - runtimeConfService.newObject(Map.class, map, "test map"); + runtimeConfService.newObject(Map.class, map, "test map", null, Map.class, String.class, Boolean.class); Sleep.ignoreInterrupt(1000); // wait for event sync final Map map1 = runtimeConfService.getMap(Map.class, String.class, Boolean.class); Assertions.assertEquals(map, map1); @@ -131,7 +138,7 @@ public static class Dto { @TmsLink("C14010") void testJson() { Dto dto = new Dto(); - runtimeConfService.newObject(Dto.class, dto, "Need init database via BootDatabaseTest"); + runtimeConfService.newObject(Dto.class, dto, "Need init database via BootDatabaseTest", null); Sleep.ignoreInterrupt(1000); // wait for event sync final Dto dto1 = runtimeConfService.getSimple(Dto.class, Dto.class); Assertions.assertEquals(dto, dto1); @@ -153,7 +160,7 @@ void testKryo() { void testMode() { final List arm = List.of(RunMode.Develop, RunMode.Local); final String key = "RuntimeConfServiceTest.testMode"; - runtimeConfService.newObject(key, arm, "test RunMode"); + runtimeConfService.newObject(key, arm, "test RunMode", null, List.class, RunMode.class); Sleep.ignoreInterrupt(1000); // wait for event sync final List arm1 = runtimeConfService.getList(key, RunMode.class); Assertions.assertEquals(arm, arm1); @@ -176,7 +183,7 @@ void testCacheWithCud() { final List arm = List.of(RunMode.Develop, RunMode.Local); final String key = "RuntimeConfCacheTest.testCache"; // insert on duplicated key - runtimeConfService.newObject(key, arm, "test RunMode"); + runtimeConfService.newObject(key, arm, "test RunMode", null, List.class, RunMode.class); Sleep.ignoreInterrupt(1000); // wait for event sync final List arm1 = runtimeConfService.getList(key, RunMode.class); final List arm2 = runtimeConfService.getList(key, RunMode.class); From 93bca81c9117bf5a56bf35a1dbcafd9df9aa8167 Mon Sep 17 00:00:00 2001 From: trydofor Date: Fri, 28 Jun 2024 08:45:56 +0800 Subject: [PATCH 07/51] =?UTF-8?q?=F0=9F=A7=91=E2=80=8D=F0=9F=92=BB=20impro?= =?UTF-8?q?ve=20log=20and=20doc?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../service/impl/TinyTaskBeatServiceImpl.java | 17 +++-- .../service/impl/TinyTaskConfServiceImpl.java | 12 +-- .../service/impl/TinyTaskExecServiceImpl.java | 76 +++++++++---------- .../service/impl/TinyTaskServiceImpl.java | 8 +- .../database/helper/TransactionHelper.java | 2 +- .../slardar/cache/spring/CacheEvictKey.java | 2 +- 6 files changed, 60 insertions(+), 57 deletions(-) diff --git a/radiant/tiny-task/src/main/java/pro/fessional/wings/tiny/task/service/impl/TinyTaskBeatServiceImpl.java b/radiant/tiny-task/src/main/java/pro/fessional/wings/tiny/task/service/impl/TinyTaskBeatServiceImpl.java index 2e96ac80e..a363b25bb 100644 --- a/radiant/tiny-task/src/main/java/pro/fessional/wings/tiny/task/service/impl/TinyTaskBeatServiceImpl.java +++ b/radiant/tiny-task/src/main/java/pro/fessional/wings/tiny/task/service/impl/TinyTaskBeatServiceImpl.java @@ -62,7 +62,7 @@ public int cleanResult() { .from(tr) .fetchInto(Long.class); if (tid.isEmpty()) { - log.debug("no task result to clean"); + log.debug("no tiny-task result to clean"); return 0; } @@ -81,7 +81,7 @@ public int cleanResult() { .collect(Collectors.toList()); if (cond.isEmpty()) { - log.debug("no task condition to clean"); + log.debug("no tiny-task condition to clean"); return 0; } @@ -90,7 +90,7 @@ public int cleanResult() { .delete(tr) .where(DSL.or(cond)) .execute(); - log.info("clean task result, count={}", rc); + log.info("clean tiny-task result, count={}", rc); return rc; } @@ -111,13 +111,13 @@ public String checkHealth() { final StringBuilder mis = warmed ? new StringBuilder() : null; for (WinTaskDefine r : tks) { - log.debug("check health task id={}, name={}", r.getId(), r.getTaskerName()); + log.debug("check health tiny-task id={}, name={}", r.getId(), r.getTaskerName()); // coordinate to system timezone long beat = calcBeatMills(r, now); if (beat <= 0) continue; if (beat < now) { - log.info("misfired task id={}, name={}", r.getId(), r.getTaskerName()); + log.info("misfired tiny-task id={}, name={}", r.getId(), r.getTaskerName()); if (mis != null) { mis.append(r.getId()).append('@').append(r.getTaskerName()).append('\n'); } @@ -125,7 +125,7 @@ public String checkHealth() { } warmed = true; - return mis == null || mis.isEmpty() ? null : "misfired task id@name\n" + mis; + return mis == null || mis.isEmpty() ? null : "misfired tiny-task id@name\n" + mis; } private long calcBeatMills(WinTaskDefine td, long now) { @@ -154,7 +154,10 @@ private long calcBeatMills(WinTaskDefine td, long now) { final CronExpression cronExpr = CronExpression.parse(cron); for (int i = 0; i < beatTimes; i++) { - beatZdt = cronExpr.next(beatZdt); + ZonedDateTime nxt = cronExpr.next(beatZdt); + if (nxt == null) break; + + beatZdt = nxt; } // then convert to instance diff --git a/radiant/tiny-task/src/main/java/pro/fessional/wings/tiny/task/service/impl/TinyTaskConfServiceImpl.java b/radiant/tiny-task/src/main/java/pro/fessional/wings/tiny/task/service/impl/TinyTaskConfServiceImpl.java index 3aec8e18d..4c8e7a7ca 100644 --- a/radiant/tiny-task/src/main/java/pro/fessional/wings/tiny/task/service/impl/TinyTaskConfServiceImpl.java +++ b/radiant/tiny-task/src/main/java/pro/fessional/wings/tiny/task/service/impl/TinyTaskConfServiceImpl.java @@ -154,7 +154,7 @@ private TaskerProp property(@NotNull String key, @NotNull TinyTasker anno) { public TaskerProp database(long id, boolean nonnull) { final TaskerProp conf = fetchProp(TaskerProp.class, t -> t.Id.eq(id)); if (conf == null && nonnull) { - throw new IllegalArgumentException("database tasker is null, id=" + id); + throw new IllegalArgumentException("database tiny-task is null, id=" + id); } return conf; } @@ -171,7 +171,7 @@ public TaskerProp property(long id, boolean nonnull) { .fetchOne(); if (r2 == null || isEmpty(r2.value1()) || isEmpty(r2.value2())) { if (nonnull) { - throw new IllegalArgumentException("database tasker is null, id=" + id); + throw new IllegalArgumentException("database tiny-task is null, id=" + id); } else { return null; @@ -188,10 +188,10 @@ public TaskerProp property(long id, boolean nonnull) { @NotNull public LinkedHashMap> diffProp(long id) { final WinTaskDefine po = fetchProp(WinTaskDefine.class, t -> t.Id.eq(id)); - AssertArgs.notNull(po, "database tasker is null, id={}", id); + AssertArgs.notNull(po, "database tiny-task is null, id={}", id); final TinyTasker anno = referAnno(po.getPropkey(), po.getTaskerBean()); - AssertArgs.notNull(anno, "database without TinyTasker, id={}", id); + AssertArgs.notNull(anno, "database without tiny-task, id={}", id); final TaskerProp prop = property(po.getPropkey(), anno); return diff(po, prop); @@ -229,7 +229,7 @@ public boolean replace(long id, TaskerProp prop) { private Conf config(@NotNull Class claz, @NotNull Object bean, @NotNull Method method, @Nullable Object para) { final TinyTasker anno = method.getAnnotation(TinyTasker.class); if (anno == null) { - throw new IllegalStateException("need @TinyTasker, tasker method=" + method.getName() + ", class=" + claz.getName()); + throw new IllegalStateException("need @TinyTasker, tiny-task method=" + method.getName() + ", class=" + claz.getName()); } final String entry = TaskerHelper.tokenize(claz, method.getName()); @@ -243,7 +243,7 @@ private Conf config(@NotNull Class claz, @NotNull Object bean, @NotNull Metho ); } - log.info("find tiny task, prop={}, entry={}", key, entry); + log.info("find tiny-task, prop={}, entry={}", key, entry); if (isEmpty(prop.getTaskerName())) { prop.setTaskerName(claz.getSimpleName() + TaskerHelper.MethodPrefix + method.getName()); diff --git a/radiant/tiny-task/src/main/java/pro/fessional/wings/tiny/task/service/impl/TinyTaskExecServiceImpl.java b/radiant/tiny-task/src/main/java/pro/fessional/wings/tiny/task/service/impl/TinyTaskExecServiceImpl.java index 071e42007..6616a82f1 100644 --- a/radiant/tiny-task/src/main/java/pro/fessional/wings/tiny/task/service/impl/TinyTaskExecServiceImpl.java +++ b/radiant/tiny-task/src/main/java/pro/fessional/wings/tiny/task/service/impl/TinyTaskExecServiceImpl.java @@ -105,7 +105,7 @@ public boolean launch(long id) { public boolean force(long id) { final WinTaskDefine td = winTaskDefineDao.fetchOneById(id); if (td == null) { - log.info("skip task for not found, id={}", id); + log.info("skip tiny-task for not found, id={}", id); return false; } @@ -118,7 +118,7 @@ public boolean force(long id) { final String taskerInfo = td.getPropkey() + " force"; final String noticeConf = td.getNoticeConf(); - String taskMsg = "force task id=" + id; + String taskMsg = "force tiny-task id=" + id; NoticeExec notice = null; Set ntcWhen = Collections.emptySet(); try { @@ -128,17 +128,17 @@ public boolean force(long id) { if (notice != null) ntcWhen = noticeWhen(td.getNoticeWhen()); postNotice(notice, noticeConf, ntcWhen, taskerInfo, taskMsg, execTms, WhenExec); - log.debug("task force exec, id={}", id); + log.debug("tiny-task force exec, id={}", id); final Object result; if (execProp.isDryrun()) { final long slp = Sleep.ignoreInterrupt(10, 2000); result = "dryrun and sleep " + slp; - log.info("task force done, dryrun and sleep {} ms, id={}", slp, id); + log.info("tiny-task force done, dryrun and sleep {} ms, id={}", slp, id); } else { result = tasker.invoke(td.getTaskerPara(), true); - log.info("task force done, id={}", id); + log.info("tiny-task force done, id={}", id); } // doneTms = ThreadNow.millis(); @@ -146,7 +146,7 @@ public boolean force(long id) { postNotice(notice, noticeConf, ntcWhen, taskerInfo, taskMsg, doneTms, WhenFeed, WhenDone); } catch (Exception e) { - log.error("task force fail, id=" + id, e); + log.error("tiny-task force fail, id=" + id, e); failTms = ThreadNow.millis(); taskMsg = ThrowableUtil.toString(e); postNotice(notice, noticeConf, ntcWhen, taskerInfo, taskMsg, failTms, WhenFail); @@ -156,7 +156,7 @@ public boolean force(long id) { saveResult(id, td.getPropkey(), execTms, failTms, doneTms, taskMsg, td.getDurFail()); } catch (Exception e) { - log.error("failed to save result, id=" + id, e); + log.error("failed to save tiny-task result, id=" + id, e); } } }, Instant.ofEpochMilli(ThreadNow.millis())); @@ -194,13 +194,13 @@ private boolean relaunch(long id) { try { lock.lock(); if (Handle.containsKey(id)) { - log.info("skip task for launching, id={}", id); + log.info("skip tiny-task for launching, id={}", id); return false; } final WinTaskDefine td = winTaskDefineDao.fetchOneById(id); if (td == null) { - log.info("skip task for not found, id={}", id); + log.info("skip tiny-task for not found, id={}", id); return false; } @@ -225,12 +225,12 @@ private boolean relaunch(long id) { return false; } - log.info("prepare task id={}, prop={}", id, key); + log.info("prepare tiny-task id={}, prop={}", id, key); final ScheduledFuture handle = taskScheduler.schedule(() -> { long execTms = ThreadNow.millis(); try { if (notNextLock(td, execTms)) { - log.warn("skip task for Not nextLock, should manually check and launch it, id={}, prop={}", id, key); + log.warn("skip tiny-task for Not nextLock, should manually check and launch it, id={}, prop={}", id, key); Handle.remove(id); return; } @@ -246,7 +246,7 @@ private boolean relaunch(long id) { final String taskerInfo = key + " launch"; final String noticeConf = td.getNoticeConf(); - String exitMsg = "relaunch task key=" + key; + String exitMsg = "relaunch tiny-task key=" + key; NoticeExec notice = null; Set ntcWhen = Collections.emptySet(); try { @@ -256,17 +256,17 @@ private boolean relaunch(long id) { if (notice != null) ntcWhen = noticeWhen(td.getNoticeWhen()); postNotice(notice, noticeConf, ntcWhen, taskerInfo, exitMsg, execTms, WhenExec); - log.info("task exec, id={}, prop={}", id, key); + log.info("tiny-task exec, id={}, prop={}", id, key); final Object result; if (execProp.isDryrun()) { final long slp = Sleep.ignoreInterrupt(10, 2000); result = "dryrun and sleep " + slp; - log.info("task done, dryrun and sleep {} ms, id={}, prop={}", slp, id, key); + log.info("tiny-task done, dryrun and sleep {} ms, id={}, prop={}", slp, id, key); } else { result = tasker.invoke(td.getTaskerPara(), true); - log.info("task done, id={}, prop={}", id, key); + log.info("tiny-task done, id={}, prop={}", id, key); } // doneTms = ThreadNow.millis(); @@ -275,7 +275,7 @@ private boolean relaunch(long id) { } catch (Exception e) { Throwable c = ThrowableUtil.cause(e, 1); - log.error("task fail, id=" + id + ", prop=" + key, c); + log.error("tiny-task fail, id=" + id + ", prop=" + key, c); failTms = ThreadNow.millis(); exitMsg = ThrowableUtil.toString(c); postNotice(notice, noticeConf, ntcWhen, taskerInfo, exitMsg, failTms, WhenFail); @@ -286,7 +286,7 @@ private boolean relaunch(long id) { saveResult(id, key, execTms, failTms, doneTms, exitMsg, td.getDurFail()); } catch (Exception e) { - log.error("failed to save result, id=" + id + ", prop=" + key, e); + log.error("failed to save tiny-task result, id=" + id + ", prop=" + key, e); } if (canRelaunch(id, doneTms, failTms, td)) { // canceled @@ -309,7 +309,7 @@ private boolean notEnable(Boolean b, long id, String key) { if (BoxedCastUtil.orTrue(b)) { return false; } - log.info("skip task for not enabled, id={}, prop={}", id, key); + log.info("skip tiny-task for not enabled, id={}, prop={}", id, key); return true; } @@ -319,7 +319,7 @@ private boolean notApps(String apps, long id, String key) { for (String s : arrayOrNull(apps, true)) { if (s.trim().equals(appName)) return false; } - log.info("skip task for not apps={}, cur={}, id={}, prop={}", apps, appName, id, key); + log.info("skip tiny-task for not apps={}, cur={}, id={}, prop={}", apps, appName, id, key); return true; } @@ -328,12 +328,12 @@ private boolean notRuns(String runs, long id, String key) { final RunMode rmd = RuntimeMode.getRunMode(); if (rmd == RunMode.Nothing) { - log.info("skip task for not runs={}, cur is Nothing, id={}, prop={}", runs, id, key); + log.info("skip tiny-task for not runs={}, cur is Nothing, id={}, prop={}", runs, id, key); return true; } if (!RuntimeMode.voteRunMode(runs)) { - log.info("skip task for not runs={}, cur={}, id={}, prop={}", runs, rmd, id, key); + log.info("skip tiny-task for not runs={}, cur={}, id={}, prop={}", runs, rmd, id, key); return true; } @@ -466,26 +466,26 @@ private boolean canRelaunch(long id, long doneTms, long failTms, WinTaskDefine t final int duringExec = td.getDuringExec(); final int sumExec = td.getSumExec(); if (duringExec > 0 && duringExec <= sumExec + 1) { - log.info("remove task for duringExec={}, sumExec={}, id={}, name={}", duringExec, sumExec, id, td.getTaskerName()); + log.info("remove tiny-task for duringExec={}, sumExec={}, id={}, prop={}", duringExec, sumExec, id, td.getPropkey()); return false; } final int duringDone = td.getDuringDone(); final int sumDone = td.getSumDone(); if (duringDone > 0 && duringDone <= (doneTms < 0 ? sumDone : sumDone + 1)) { - log.info("remove task for duringDone={}, sumDone={}, id={}, name={}", duringDone, sumDone, id, td.getTaskerName()); + log.info("remove tiny-task for duringDone={}, sumDone={}, id={}, prop={}", duringDone, sumDone, id, td.getPropkey()); return false; } final int duringFail = td.getDuringFail(); final int durFail = td.getDurFail(); if (duringFail > 0 && duringFail <= (failTms < 0 ? durFail : durFail + 1)) { - log.info("remove task for duringFail={}, durFail={}, id={}, name={}", duringFail, durFail, id, td.getTaskerName()); + log.info("remove tiny-task for duringFail={}, durFail={}, id={}, prop={}", duringFail, durFail, id, td.getPropkey()); return false; } if (Cancel.containsKey(id)) { // canceled - log.info("remove task for canceled, id={}, name={}", id); + log.info("remove tiny-task for canceled, id={}, prop={}", id, td.getPropkey()); return false; } @@ -493,7 +493,7 @@ private boolean canRelaunch(long id, long doneTms, long failTms, WinTaskDefine t if (duringBoot > 0) { final int bct = Booted.compute(id, (ignored, v) -> v == null ? 1 : v + 1); if (bct >= duringBoot) { - log.info("remove task for duringBoot={}, id={}, name={}", bct, id, td.getTaskerName()); + log.info("remove tiny-task for duringBoot={}, id={}, prop={}", bct, id, td.getPropkey()); return false; } } @@ -514,7 +514,7 @@ private long calcNextExec(WinTaskDefine td) { // Planned, program was killed before execution ends final long nextMs = DateLocaling.sysEpoch(td.getNextExec()); if (nextMs + timingMiss >= now) { - log.info("launch misfire task, id={}, name={}", id, td.getTaskerName()); + log.info("launch misfire tiny-task, id={}, prop={}", id, td.getPropkey()); return nextMs; } @@ -525,14 +525,14 @@ private long calcNextExec(WinTaskDefine td) { while (true) { Instant next = trigger.nextExecution(context); if (next == null) { - log.info("skip task for trigger not fire, id={}, name={}", id, td.getTaskerName()); + log.info("skip tiny-task for trigger not fire, id={}, prop={}", id, td.getPropkey()); break; } final long nxt = next.toEpochMilli(); if (nxt < now) { if (timingMiss > 0 && nxt + timingMiss >= now) { - log.info("launch task for misfire={}, id={}, name={}", next, id, td.getTaskerName()); + log.info("launch tiny-task for misfire={}, id={}, prop={}", next, id, td.getPropkey()); nextExec = nxt; break; } @@ -541,7 +541,7 @@ private long calcNextExec(WinTaskDefine td) { } } else { - log.info("launch task for next={}, id={}, name={}", next, id, td.getTaskerName()); + log.info("launch tiny-task for next={}, id={}, prop={}", next, id, td.getPropkey()); nextExec = nxt; break; } @@ -586,13 +586,13 @@ private SimpleTriggerContext makeContext(WinTaskDefine td, ZoneId zone, long now private Trigger makeTrigger(WinTaskDefine td, ZoneId zone) { final String cron = td.getTimingCron(); if (StringUtils.isNotEmpty(cron)) { - log.info("use trigger cron={}, id={}, name={}", cron, td.getId(), td.getTaskerName()); + log.info("use trigger cron={}, id={}, prop={}", cron, td.getId(), td.getPropkey()); return new CronTrigger(cron, zone); } final int idle = td.getTimingIdle(); if (idle > 0) { - log.info("use trigger idle={}, id={}, name={}", idle, td.getId(), td.getTaskerName()); + log.info("use trigger idle={}, id={}, prop={}", idle, td.getId(), td.getPropkey()); PeriodicTrigger trg = new PeriodicTrigger(Duration.ofSeconds(idle)); trg.setFixedRate(false); return trg; @@ -600,7 +600,7 @@ private Trigger makeTrigger(WinTaskDefine td, ZoneId zone) { final int rate = td.getTimingRate(); if (rate > 0) { - log.info("use trigger rate={}, id={}, name={}", rate, td.getId(), td.getTaskerName()); + log.info("use trigger rate={}, id={}, prop={}", rate, td.getId(), td.getPropkey()); PeriodicTrigger trg = new PeriodicTrigger(Duration.ofSeconds(rate)); trg.setFixedRate(true); return trg; @@ -615,7 +615,7 @@ private boolean notRanged(WinTaskDefine td, ZoneId zone, long now) { final LocalDateTime ldt = DateParser.parseDateTime(duringFrom); final long ms = DateLocaling.useEpoch(ldt, zone); if (ms > now) { - log.info("skip task for duringFrom={}, id={}, name={}", duringFrom, td.getId(), td.getTaskerName()); + log.info("skip tiny-task for duringFrom={}, id={}, prop={}", duringFrom, td.getId(), td.getPropkey()); return true; } } @@ -625,26 +625,26 @@ private boolean notRanged(WinTaskDefine td, ZoneId zone, long now) { final LocalDateTime ldt = DateParser.parseDateTime(duringStop); final long ms = DateLocaling.useEpoch(ldt, zone); if (ms < now) { - log.info("skip task for duringStop={}, id={}, name={}", duringStop, td.getId(), td.getTaskerName()); + log.info("skip tiny-task for duringStop={}, id={}, prop={}", duringStop, td.getId(), td.getPropkey()); return true; } } final int duringExec = td.getDuringExec(); if (duringExec > 0 && duringExec <= td.getSumExec()) { - log.info("skip task for duringExec={}, sumExec={}, id={}, name={}", duringExec, td.getSumExec(), td.getId(), td.getTaskerName()); + log.info("skip tiny-task for duringExec={}, sumExec={}, id={}, prop={}", duringExec, td.getSumExec(), td.getId(), td.getPropkey()); return true; } final int duringDone = td.getDuringDone(); if (duringDone > 0 && duringDone <= td.getSumDone()) { - log.info("skip task for duringDone={}, sumDone={}, id={}, name={}", duringDone, td.getSumDone(), td.getId(), td.getTaskerName()); + log.info("skip tiny-task for duringDone={}, sumDone={}, id={}, prop={}", duringDone, td.getSumDone(), td.getId(), td.getPropkey()); return true; } final int duringFail = td.getDuringFail(); if (duringFail > 0 && duringFail <= td.getDurFail()) { - log.info("skip task for duringFail={}, durFail={}, id={}, name={}", duringFail, td.getDurFail(), td.getId(), td.getTaskerName()); + log.info("skip tiny-task for duringFail={}, durFail={}, id={}, prop={}", duringFail, td.getDurFail(), td.getId(), td.getPropkey()); return true; } diff --git a/radiant/tiny-task/src/main/java/pro/fessional/wings/tiny/task/service/impl/TinyTaskServiceImpl.java b/radiant/tiny-task/src/main/java/pro/fessional/wings/tiny/task/service/impl/TinyTaskServiceImpl.java index e34f82d7d..719f13470 100644 --- a/radiant/tiny-task/src/main/java/pro/fessional/wings/tiny/task/service/impl/TinyTaskServiceImpl.java +++ b/radiant/tiny-task/src/main/java/pro/fessional/wings/tiny/task/service/impl/TinyTaskServiceImpl.java @@ -47,11 +47,11 @@ public Set schedule(@NotNull Object taskerBean) { for (Conf cnf : conf) { if (cnf.isEnabled() && cnf.isAutorun()) { final boolean cd = tinyTaskExecService.launch(cnf.getId()); - log.info("schedule task {}, scheduled={}", cnf, cd); + log.info("schedule tiny-task {}, scheduled={}", cnf, cd); rst.add(new Task(cnf.getId(), cnf.getKey(), cd)); } else { - log.info("skip task {}", cnf); + log.info("skip tiny-task {}", cnf); } } return rst; @@ -63,11 +63,11 @@ public Task schedule(@NotNull Object taskerBean, @NotNull Method taskerCall, @Nu final boolean cd; if (cnf.isEnabled()) { cd = tinyTaskExecService.launch(cnf.getId()); - log.info("schedule task {}, scheduled={}", cnf, cd); + log.info("schedule tiny-task {}, scheduled={}", cnf, cd); } else { cd = false; - log.info("skip task {}", cnf); + log.info("skip tiny-task {}", cnf); } return new Task(cnf.getId(), cnf.getKey(), cd); diff --git a/wings/faceless/src/main/java/pro/fessional/wings/faceless/database/helper/TransactionHelper.java b/wings/faceless/src/main/java/pro/fessional/wings/faceless/database/helper/TransactionHelper.java index 60052e472..6f261635f 100644 --- a/wings/faceless/src/main/java/pro/fessional/wings/faceless/database/helper/TransactionHelper.java +++ b/wings/faceless/src/main/java/pro/fessional/wings/faceless/database/helper/TransactionHelper.java @@ -97,7 +97,7 @@ public static TransactionDefinition definition(@Nullable Propagation propagation /** * Propagation(REQUIRED), Isolation(DEFAULT) and timeout(-1) */ - @Contract("_->param1") + @Contract("_,_,_,_->param1") public static T definition(@NotNull T tpl, @Nullable Propagation propagation, @Nullable Isolation isolation, int timeoutSeconds) { tpl.setPropagationBehavior(propagation == null ? Propagation.REQUIRED.value() : propagation.value()); tpl.setIsolationLevel(isolation == null ? Isolation.DEFAULT.value() : isolation.value()); diff --git a/wings/slardar/src/main/java/pro/fessional/wings/slardar/cache/spring/CacheEvictKey.java b/wings/slardar/src/main/java/pro/fessional/wings/slardar/cache/spring/CacheEvictKey.java index b8638907a..a623dd7ed 100644 --- a/wings/slardar/src/main/java/pro/fessional/wings/slardar/cache/spring/CacheEvictKey.java +++ b/wings/slardar/src/main/java/pro/fessional/wings/slardar/cache/spring/CacheEvictKey.java @@ -40,7 +40,7 @@ public Object getKey() { * * @see #KeyGenerator */ - @Contract("_->this") + @Contract("_,_,_->this") public final CacheEvictKey add(Object target, Method method, Object... arg) { if (keys.isEmpty()) { keys = new LinkedList<>(); From f64bac6d5b47ab58d956dd7056c51357f10a003a Mon Sep 17 00:00:00 2001 From: trydofor Date: Fri, 28 Jun 2024 08:57:35 +0800 Subject: [PATCH 08/51] =?UTF-8?q?=E2=9C=A8=20tiny-mail=20with=20runs-not?= =?UTF-8?q?=20#261?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../service/impl/TinyMailServiceImpl.java | 66 +++++++++---------- .../slardar/context/LocaleZoneIdUtil.java | 11 +--- 2 files changed, 35 insertions(+), 42 deletions(-) diff --git a/radiant/tiny-mail/src/main/java/pro/fessional/wings/tiny/mail/service/impl/TinyMailServiceImpl.java b/radiant/tiny-mail/src/main/java/pro/fessional/wings/tiny/mail/service/impl/TinyMailServiceImpl.java index 62f91aca7..76facdc7b 100644 --- a/radiant/tiny-mail/src/main/java/pro/fessional/wings/tiny/mail/service/impl/TinyMailServiceImpl.java +++ b/radiant/tiny-mail/src/main/java/pro/fessional/wings/tiny/mail/service/impl/TinyMailServiceImpl.java @@ -101,7 +101,7 @@ public class TinyMailServiceImpl implements TinyMailService, InitializingBean { public boolean send(@NotNull TinyMail message, boolean retry) { final String conf = message.getConf(); final TinyMailConfig config = mailConfigProvider.bynamedConfig(conf); - AssertArgs.notNull(config, "mail conf={} not found", conf); + AssertArgs.notNull(config, "tiny-mail conf={} not found", conf); final WinMailSender po = saveMailSender(config, message); final TinyMailMessage mailMessage = makeMailMessage(config, po, message); @@ -114,7 +114,7 @@ public boolean post(@NotNull TinyMail message, boolean retry) { return send(message, retry); } catch (Exception e) { - log.error("fail to post mail, subject=" + message.getSubject(), e); + log.error("fail to post tiny-mail, subject=" + message.getSubject(), e); return false; } } @@ -133,13 +133,13 @@ public long emit(@NotNull TinyMail message, boolean retry) { public boolean send(long id, boolean retry, boolean check) { final WinMailSender po = winMailSenderDao.fetchOneById(id); if (po == null) { - log.warn("mail not found by id={}, skip send", id); + log.warn("tiny-mail not found by id={}, skip send", id); return false; } final String conf = po.getMailConf(); final TinyMailConfig config = mailConfigProvider.bynamedConfig(conf); if (config == null) { - log.warn("mail conf={} not found", conf); + log.warn("tiny-mail conf={} not found", conf); return false; } @@ -153,7 +153,7 @@ public boolean post(long id, boolean retry, boolean check) { return send(id, retry, check); } catch (Exception e) { - log.error("fail to post mail, id=" + id, e); + log.error("fail to post tiny-mail, id=" + id, e); return false; } } @@ -162,7 +162,7 @@ public boolean post(long id, boolean retry, boolean check) { public long emit(long id, boolean retry, boolean check) { final WinMailSender po = winMailSenderDao.fetchOneById(id); if (po == null) { - log.warn("mail not found by id={}, skip emit", id); + log.warn("tiny-mail not found by id={}, skip emit", id); return -1; } return doAsyncFreshSend(po, null, retry, check); @@ -173,7 +173,7 @@ public long emit(long id, boolean retry, boolean check) { public long save(@NotNull TinyMailPlain msg) { final String conf = msg.getConf(); final TinyMailConfig config = mailConfigProvider.bynamedConfig(conf); - AssertArgs.notNull(config, "mail conf={} not found", conf); + AssertArgs.notNull(config, "tiny-mail conf={} not found", conf); final WinMailSender po = new WinMailSender(); final boolean isNew = msg.getId() == null || msg.getId() <= 0; @@ -243,7 +243,7 @@ public int scan() { final long now = ThreadNow.millis(); final LocalDateTime min = DateLocaling.sysLdt(now - tinyMailServiceProp.getMaxNext().toMillis()); final LocalDateTime max = DateLocaling.sysLdt(now + tinyMailServiceProp.getTryNext().toMillis()); - log.info("scan misfire-mail to queue, min={}, max={}", min, max); + log.info("scan misfire tiny-mail to queue, min={}, max={}", min, max); final WinMailSenderTable t = winMailSenderDao.getTable(); final List pos = winMailSenderDao @@ -259,7 +259,7 @@ public int scan() { // final int size = pos.size(); - log.info("plan misfire-mail, size={}", size); + log.info("plan misfire tiny-mail, size={}", size); if (size > 0) { asyncMails.addAll(pos); taskScheduler.schedule(this::doAsyncBatchSend, Instant.ofEpochMilli(now)); @@ -361,7 +361,7 @@ private boolean notMatchProp(WinMailSender po) { if (tinyMailServiceProp.isOnlyApp()) { final String ma = po.getMailApps(); if (StringUtils.isNotEmpty(ma) && !appName.equalsIgnoreCase(ma)) { - log.debug("skip only send app-mail app={}, id={}", appName, po.getId()); + log.debug("skip only send app tiny-mail app={}, id={}", appName, po.getId()); return true; } } @@ -370,11 +370,11 @@ private boolean notMatchProp(WinMailSender po) { if (StringUtils.isNotEmpty(mrs)) { final RunMode rmd = RuntimeMode.getRunMode(); if (rmd == RunMode.Nothing) { - log.debug("skip only send run-mail, run={}, id={}", mrs, po.getId()); + log.debug("skip only send run tiny-mail, run={}, id={}", mrs, po.getId()); return true; } - if (!RuntimeMode.hasRunMode(arrayOrNull(mrs, true))) { - log.debug("skip only send run-mail, run={}, cur={}, id={}", mrs, rmd, po.getId()); + if (!RuntimeMode.voteRunMode(mrs)) { + log.debug("skip only send run tiny-mail, run={}, cur={}, id={}", mrs, rmd, po.getId()); return true; } } @@ -383,14 +383,14 @@ private boolean notMatchProp(WinMailSender po) { final int maxDone = BoxedCastUtil.orElse(po.getMaxDone(), 0) > 0 ? po.getMaxDone() : tinyMailServiceProp.getMaxDone(); final int sumDone = BoxedCastUtil.orElse(po.getSumDone(), 0); if (sumDone >= maxDone) { - log.debug("skip max-send, max={}, sum={}, id={}", maxDone, sumDone, po.getId()); + log.debug("skip max-send tiny-mail, max={}, sum={}, id={}", maxDone, sumDone, po.getId()); return true; } final int maxFail = BoxedCastUtil.orElse(po.getMaxFail(), 0) > 0 ? po.getMaxFail() : tinyMailServiceProp.getMaxFail(); final int sumFail = BoxedCastUtil.orElse(po.getSumFail(), 0); if (sumFail >= maxFail) { - log.debug("skip max-fail, max={}, sum={}, id={}", maxFail, sumFail, po.getId()); + log.debug("skip max-fail tiny-mail, max={}, sum={}, id={}", maxFail, sumFail, po.getId()); return true; } @@ -408,7 +408,7 @@ private boolean notNextLock(WinMailSender po, long now) { .execute(); if (rc <= 0) { - log.debug("skip not-next-lock mail, id={}", po.getId()); + log.debug("skip not-next-lock tiny-mail, id={}", po.getId()); return true; } @@ -428,12 +428,12 @@ private void saveStatusAndRetry(@NotNull WinMailSender po, TinyMailMessage messa if (po.getSumDone() + 1 >= tinyMailServiceProp.getMaxDone()) { setter.put(t.NextSend, EmptyValue.DATE_TIME); - log.debug("done mail by max-send id={}, subject={}", po.getId(), po.getMailSubj()); + log.debug("done tiny-mail by max-send id={}, subject={}", po.getId(), po.getMailSubj()); } else { nextSend = now + tinyMailServiceProp.getTryNext().toMillis(); setter.put(t.NextSend, DateLocaling.sysLdt(nextSend)); - log.debug("next done-mail id={}, subject={}", po.getId(), po.getMailSubj()); + log.debug("next done-tiny-mail id={}, subject={}", po.getId(), po.getMailSubj()); } setter.put(t.SumSend, t.SumSend.add(1)); @@ -447,13 +447,13 @@ private void saveStatusAndRetry(@NotNull WinMailSender po, TinyMailMessage messa final int maxFail = BoxedCastUtil.orElse(po.getMaxFail(), 0) > 0 ? po.getMaxFail() : tinyMailServiceProp.getMaxFail(); if (po.getSumFail() + 1 >= maxFail) { setter.put(t.NextSend, EmptyValue.DATE_TIME); - log.debug("done mail by max-fail id={}, subject={}", po.getId(), po.getMailSubj()); + log.debug("done tiny-mail by max-fail id={}, subject={}", po.getId(), po.getMailSubj()); } else if (retry) { if (exception instanceof MailWaitException mwe) { if (mwe.isStopRetry()) { setter.put(t.NextSend, EmptyValue.DATE_TIME); - log.error("stop stop-retry mail, id=" + po.getId(), exception); + log.error("stop stop-retry tiny-mail, id=" + po.getId(), exception); } else { nextSend = mwe.getWaitEpoch(); @@ -461,7 +461,7 @@ else if (retry) { } else if (exception instanceof MailParseException || exception instanceof MessagingException) { setter.put(t.NextSend, EmptyValue.DATE_TIME); - log.error("failed to parse, stop mail, id=" + po.getId(), exception); + log.error("failed to parse, stop tiny-mail, id=" + po.getId(), exception); } else { nextSend = now + tinyMailServiceProp.getTryNext().toMillis(); @@ -469,12 +469,12 @@ else if (exception instanceof MailParseException || exception instanceof Messagi if (nextSend > 0) { setter.put(t.NextSend, DateLocaling.sysLdt(nextSend)); - log.debug("next fail-mail id={}, subject={}", po.getId(), po.getMailSubj()); + log.debug("next fail-tiny-mail id={}, subject={}", po.getId(), po.getMailSubj()); } } else { setter.put(t.NextSend, EmptyValue.DATE_TIME); - log.error("stop not-retry mail, id=" + po.getId(), exception); + log.error("stop not-retry tiny-mail, id=" + po.getId(), exception); } setter.put(t.SumSend, t.SumSend.add(1)); setter.put(t.SumFail, t.SumFail.add(1)); @@ -495,7 +495,7 @@ else if (exception instanceof MailParseException || exception instanceof Messagi if (!notHookStop) { setter.put(t.NextSend, EmptyValue.DATE_TIME); - log.debug("hook stop mail, id={}", po.getId()); + log.debug("hook stop tiny-mail, id={}", po.getId()); } journalService.commit(Jane.Update, journal -> { @@ -509,7 +509,7 @@ else if (exception instanceof MailParseException || exception instanceof Messagi }); } catch (Exception e) { - log.error("failed to save mail status, id=" + po.getId() + ", subject=" + po.getMailSubj(), e); + log.error("failed to save tiny-mail status, id=" + po.getId() + ", subject=" + po.getMailSubj(), e); nextSend = now + tinyMailServiceProp.getTryNext().toMillis(); } @@ -517,14 +517,14 @@ else if (exception instanceof MailParseException || exception instanceof Messagi if (notHookStop && nextSend > 0) { asyncMails.add(new AsyncMail(po.getId(), nextSend, retry, check, null, message)); taskScheduler.schedule(this::doAsyncBatchSend, Instant.ofEpochMilli(nextSend)); - log.debug("schedule done-mail send, id={}, subject={}", po.getId(), po.getMailSubj()); + log.debug("schedule done-tiny-mail send, id={}, subject={}", po.getId(), po.getMailSubj()); } } else { if (notHookStop && retry && nextSend > 0 && nextSend - now < tinyMailServiceProp.getMaxNext().toMillis()) { asyncMails.add(new AsyncMail(po.getId(), nextSend, retry, check, null, message)); taskScheduler.schedule(this::doAsyncBatchSend, Instant.ofEpochMilli(nextSend)); - log.debug("schedule fail-mail send, id=" + po.getId() + ", subject=" + po.getMailSubj()); + log.debug("schedule fail-tiny-mail send, id=" + po.getId() + ", subject=" + po.getMailSubj()); } else { if (rethrow) { @@ -532,11 +532,11 @@ else if (exception instanceof MailParseException || exception instanceof Messagi throw (RuntimeException) exception; } else { - throw new MailSendException("failed mail, id=" + po.getId() + ", subject=" + po.getMailSubj(), exception); + throw new MailSendException("failed tiny-mail, id=" + po.getId() + ", subject=" + po.getMailSubj(), exception); } } else { - log.debug("no rethrow or retry mail, id=" + po.getId() + ", subject=" + po.getMailSubj()); + log.debug("no rethrow or retry tiny-mail, id=" + po.getId() + ", subject=" + po.getMailSubj()); } } } @@ -583,11 +583,11 @@ private long doAsyncFreshSend(@NotNull WinMailSender po, TinyMailMessage message final long nxt; if (mds > now) { nxt = mds; - log.debug("plan async date={} id={}", md, id); + log.debug("plan async tiny-mail date={} id={}", md, id); } else { nxt = now; - log.debug("plan async date=now id={}", id); + log.debug("plan async tiny-mail date=now id={}", id); } // check format @@ -677,10 +677,10 @@ private void doAsyncBatchSend() { final long next = start + tinyMailServiceProp.getTryNext().toMillis(); taskScheduler.schedule(this::doAsyncBatchSend, Instant.ofEpochMilli(next)); if (size > tinyMailServiceProp.getWarnSize()) { - log.warn("plan next war-size={}, idle={}", size, tinyMailServiceProp.getTryNext()); + log.warn("plan next tiny-mail warn-size={}, idle={}", size, tinyMailServiceProp.getTryNext()); } else { - log.debug("plan next size={}, idle={}", size, tinyMailServiceProp.getTryNext()); + log.debug("plan next tiny-mail size={}, idle={}", size, tinyMailServiceProp.getTryNext()); } } } diff --git a/wings/slardar/src/main/java/pro/fessional/wings/slardar/context/LocaleZoneIdUtil.java b/wings/slardar/src/main/java/pro/fessional/wings/slardar/context/LocaleZoneIdUtil.java index 89ba287e8..6651f77f3 100644 --- a/wings/slardar/src/main/java/pro/fessional/wings/slardar/context/LocaleZoneIdUtil.java +++ b/wings/slardar/src/main/java/pro/fessional/wings/slardar/context/LocaleZoneIdUtil.java @@ -2,7 +2,6 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import org.springframework.context.i18n.LocaleContextHolder; import java.time.ZoneId; import java.util.Locale; @@ -19,10 +18,7 @@ public class LocaleZoneIdUtil { @Nullable public static ZoneId ZoneIdNullable() { final TerminalContext.Context ctx = TerminalContext.get(false); - if (!ctx.isNull()) { - return ctx.getZoneId(); - } - return LocaleContextHolder.getTimeZone().toZoneId(); + return ctx.isNull() ? null: ctx.getZoneId(); } @@ -32,10 +28,7 @@ public static ZoneId ZoneIdNullable() { @Nullable public static Locale LocaleNullable() { final TerminalContext.Context ctx = TerminalContext.get(false); - if (!ctx.isNull()) { - return ctx.getLocale(); - } - return LocaleContextHolder.getLocale(); + return ctx.isNull() ? null: ctx.getLocale(); } /** From b8832a70fb555fe97aa669fe68d5c64e2574aea7 Mon Sep 17 00:00:00 2001 From: trydofor Date: Fri, 28 Jun 2024 14:07:26 +0800 Subject: [PATCH 09/51] =?UTF-8?q?=F0=9F=A7=91=E2=80=8D=F0=9F=92=BB=20add?= =?UTF-8?q?=20git-info=20to=20starter?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- observe/scripts/wings-starter.sh | 58 ++++++++++++++++++++------------ 1 file changed, 36 insertions(+), 22 deletions(-) diff --git a/observe/scripts/wings-starter.sh b/observe/scripts/wings-starter.sh index 1997e15bf..9cc720951 100755 --- a/observe/scripts/wings-starter.sh +++ b/observe/scripts/wings-starter.sh @@ -137,6 +137,22 @@ function print_args() { echo "BOOT_ARG=$BOOT_ARG" echo -e "\033[37;42;1mINFO: ==== java arguments ==== \033[0m" echo "$JAVA_OPT" + + git_jar="${BOOT_JAR}_${BOOT_MD5}" + if [[ ! -f "$git_jar" ]]; then + git_jar="${BOOT_JAR}" + fi + if [[ -f "$git_jar" ]]; then + giti=$(jar tf "$git_jar" 2>/dev/null | grep git.properties ) + if [[ "$giti" != "" ]]; then + tmp="./tmp-$BOOT_MD5" + mkdir -p "$tmp" + (cd "$tmp" && jar xf "$git_jar" "$giti") + echo -e "\033[37;42;1mINFO: ==== git build info ==== \033[0m" + grep -vE '=$' "$tmp/$giti" + rm -rf "$tmp" + fi + fi } function check_cmd() { @@ -202,7 +218,7 @@ function check_boot() { function safe_start() { # safe backup md5sum "$BOOT_JAR" >"$file_md5" - BOOT_MD5=$(awk '{print $1}' <"$file_md5") + BOOT_MD5=$(awk '{print $1}' "$file_md5") # `_` as delimiter safe_jar="${BOOT_JAR}_${BOOT_MD5}" if [[ ! -f "$safe_jar" ]]; then @@ -229,7 +245,7 @@ if [[ -L "$this_file" ]]; then link_file=$(realpath "$this_file") link_envs=${link_file%.*}.env if [[ -f "$link_envs" ]]; then - echo -e "\033[37;42;1mINFO: load link-envs form $link_envs ==== \033[0m" + echo -e "\033[37;42;1mINFO: link-envs=$link_envs \033[0m" # shellcheck disable=SC1090 source "$link_envs" fi @@ -237,7 +253,7 @@ fi this_envs=${this_file%.*}.env if [[ -f "$this_envs" ]]; then - echo -e "\033[37;42;1mINFO: load this-envs form $this_envs ==== \033[0m" + echo -e "\033[37;42;1mINFO: this-envs=$this_envs \033[0m" # shellcheck disable=SC1090 source "$this_envs" else @@ -245,7 +261,7 @@ else fi if [[ -f "$BOOT_ENVF" ]]; then - echo -e "\033[37;42;1mINFO: load boot-envs form $BOOT_ENVF ==== \033[0m" + echo -e "\033[37;42;1mINFO: boot-envs=$BOOT_ENVF \033[0m" # shellcheck disable=SC1090 source "$BOOT_ENVF" fi @@ -366,14 +382,14 @@ fi # boot md5 file_md5="${JAR_NAME}.md5" if [[ -f "$file_md5" ]]; then - BOOT_MD5=$(awk '{print $1}' <"$file_md5") + BOOT_MD5=$(awk '{print $1}' "$file_md5") fi # java home & path if [[ "$JDK_HOME" != "" && "$JDK_HOME" != "$JAVA_HOME" ]]; then PATH=$JDK_HOME/bin:$PATH JAVA_HOME=$JDK_HOME - echo -e "\033[37;42;1mINFO: ==== JAVA_HOME=$JAVA_HOME ==== \033[0m" + echo -e "\033[37;42;1mINFO: JAVA_HOME=$JAVA_HOME \033[0m" fi # lazy env eval @@ -442,9 +458,9 @@ case "$ARGS_RUN" in if [[ "$ARGS_RUN" != "start" ]]; then echo -e "\033[37;42;1mINFO: tail -f $BOOT_OUT \033[0m" timeout -s 9 10 tail -f "$BOOT_OUT" - echo -e "\033[37;43;1m====== ${BOOT_JAR//?/=} ======\033[0m" - echo -e "\033[37;43;1m====== $BOOT_JAR ======\033[0m" - echo -e "\033[37;43;1m====== ${BOOT_JAR//?/=} ======\033[0m" + echo -e "\033[37;42;1m =====${BOOT_JAR//?/=}===== \033[0m" + echo -e "\033[37;42;1m ==== $BOOT_JAR ==== \033[0m" + echo -e "\033[37;42;1m =====${BOOT_JAR//?/=}===== \033[0m" exit fi @@ -550,15 +566,6 @@ case "$ARGS_RUN" in check_java print_args - tail_num=20 - if [[ -f "$BOOT_OUT" ]]; then - echo -e "\033[37;42;1mINFO: tail -n $tail_num $BOOT_OUT \033[0m" - tail -n $tail_num "$BOOT_OUT" - fi - if [[ -f "$BOOT_LOG" ]]; then - echo -e "\033[37;42;1mINFO: tail -n $tail_num $BOOT_LOG \033[0m" - tail -n $tail_num "$BOOT_LOG" - fi pid=$(awk '{print $1}' "$BOOT_PID") cid=$(pgrep -f "$grep_key") echo -e "\033[37;42;1mINFO: boot.pid=$pid \033[0m" @@ -582,14 +589,11 @@ case "$ARGS_RUN" in if [[ "$USER_RUN" == "$USER" ]]; then echo -e "\033[37;42;1mINFO: $(which jstat) -gcutil $cid 1000 3 \033[0m" jstat -gcutil "$cid" 1000 3 - echo -e "\033[37;42;1mINFO: $(which jstat) -gc $cid 1000 3 \033[0m" - jstat -gc "$cid" 1000 3 else echo -e "\033[37;43;1mNOTE: sudo $(which jstat) -gcutil $cid 1000 3 \033[0m" echo -e "\033[37;43;1mNOTE: sudo $(which jstat) -gc $cid 1000 3 \033[0m" fi - if id | grep -q '(sudo)'; then if which jhsdb &> /dev/null; then _jhsdb=$(which jhsdb) @@ -608,7 +612,17 @@ case "$ARGS_RUN" in fi fi - echo -e "\033[37;43;1mNOTE: ==== useful tool ==== \033[0m" + tail_num=20 + if [[ -f "$BOOT_OUT" ]]; then + echo -e "\033[37;42;1mINFO: tail -n $tail_num $BOOT_OUT \033[0m" + tail -n $tail_num "$BOOT_OUT" + fi + if [[ -f "$BOOT_LOG" ]]; then + echo -e "\033[37;42;1mINFO: tail -n $tail_num $BOOT_LOG \033[0m" + tail -n $tail_num "$BOOT_LOG" + fi + + echo -e "\033[37;42;1mINFO: ==== useful tool ==== \033[0m" echo -e "\033[32m profiler.sh -d 30 -f profile.svg $cid \033[m https://github.com/jvm-profiling-tools/async-profiler" echo -e "\033[32m $(which java) -jar arthas-boot.jar $cid \033[m https://github.com/alibaba/arthas" ;; From 3b8a8e2f47abb36df245838cef801a10c744906d Mon Sep 17 00:00:00 2001 From: trydofor Date: Fri, 28 Jun 2024 18:31:34 +0800 Subject: [PATCH 10/51] =?UTF-8?q?=F0=9F=92=A5keep=20silencer=20simple=20#2?= =?UTF-8?q?65?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- WingsBoot.t.md | 1 + .../project/Devops7EnumsDumperTest.java | 4 +- observe/docs | 2 +- .../tiny/mail/sender/TinyMailConfig.java | 20 +- .../service/impl/TinyMailListServiceImpl.java | 5 +- .../service/impl/TinyMailServiceImpl.java | 74 +++--- .../07-mail/2020-10-27v01-tiny_mail.sql | 66 ++--- .../tiny/mail/service/ResourceMapTest.java | 4 +- .../service/impl/TinyTaskExecServiceImpl.java | 6 +- .../spring/prop/FacelessJooqCudProp.java | 4 +- .../wings/faceless/convention/EmptySugar.java | 2 +- .../wings/silencer/common/Splitter.java | 104 -------- .../wings/silencer/enhance/ThisLazy.java | 0 .../wings/silencer/enhance/ThisLazyAware.java | 0 .../enhance/ThisLazyPostProcessor.java | 0 .../bean/SilencerCurseConfiguration.java | 29 ++- .../spring/help/CommonPropHelper.java | 110 -------- .../app/TestSilencerCurseApplication.java | 3 + .../silencer/app/conf/TestMergingProp.java | 0 .../app/service/TestThisLazyService.java | 0 .../impl/TestThisLazyServiceEnhanced.java | 0 .../impl/TestThisLazyServiceItself.java | 0 .../impl/TestThisLazyServiceProxy.java | 0 .../silencer/enhance/ThisLazyCglibTest.java | 0 .../silencer/enhance/ThisLazyProxyTest.java | 0 .../spring/boot/WingsSilencerMergeTest.java | 0 .../wings-conf/wings-merge-a.properties | 0 .../wings-conf/wings-merge-b.properties | 0 .../spring/bean/SilencerConfiguration.java | 10 - .../silencer/support/InspectHelper.java} | 11 +- .../wings/silencer/support/PropHelper.java | 242 ++++++++++++++++++ .../silencer/support/SubclassGather.java} | 6 +- .../{enhance => support}/TypeSugar.java | 2 +- .../silencer/app/TestSilencerApplication.java | 3 - .../silencer/support/InspectHelperTest.java} | 30 +-- .../silencer/support/PropHelperTest.java | 44 ++++ .../{enhance => support}/TypeSugarMain.java | 3 +- .../{enhance => support}/TypeSugarTest.java | 41 +-- .../impl/WingsCookieInterceptorImpl.java | 4 +- .../bean/SlardarRemoteConfiguration.java | 8 +- .../bean/SlardarSwaggerConfiguration.java | 4 +- .../slardar/json/WingsJacksonMapperTest.java | 2 +- .../slardar/fastjson/FastJsonHelper.java | 2 +- .../jackson/AesStringDeserializer.java | 2 +- .../slardar/jackson/AesStringSerializer.java | 2 +- .../wings/slardar/jackson/JacksonHelper.java | 2 +- .../slardar/jackson/ResourceSerializer.java | 4 +- .../wings/slardar/notice/DingTalkConf.java | 16 +- .../bean/SlardarMonitorConfiguration.java | 6 +- .../wings/slardar/json/TypeReferenceTest.java | 2 +- .../security/justauth/AuthStateBuilder.java | 2 +- .../WarlockSecurityBeanConfiguration.java | 4 +- .../WarlockSecurityConfConfiguration.java | 12 +- .../spring/prop/WarlockSecurityProp.java | 4 +- .../service/conf/RuntimeConfService.java | 2 +- .../conf/impl/RuntimeConfServiceImpl.java | 2 +- .../service/conf/RuntimeConfServiceTest.java | 2 +- 57 files changed, 487 insertions(+), 421 deletions(-) delete mode 100644 wings/silencer-curse/src/main/java/pro/fessional/wings/silencer/common/Splitter.java rename wings/{silencer => silencer-curse}/src/main/java/pro/fessional/wings/silencer/enhance/ThisLazy.java (100%) rename wings/{silencer => silencer-curse}/src/main/java/pro/fessional/wings/silencer/enhance/ThisLazyAware.java (100%) rename wings/{silencer => silencer-curse}/src/main/java/pro/fessional/wings/silencer/enhance/ThisLazyPostProcessor.java (100%) delete mode 100644 wings/silencer-curse/src/main/java/pro/fessional/wings/silencer/spring/help/CommonPropHelper.java rename wings/{silencer => silencer-curse}/src/test/java/pro/fessional/wings/silencer/app/conf/TestMergingProp.java (100%) rename wings/{silencer => silencer-curse}/src/test/java/pro/fessional/wings/silencer/app/service/TestThisLazyService.java (100%) rename wings/{silencer => silencer-curse}/src/test/java/pro/fessional/wings/silencer/app/service/impl/TestThisLazyServiceEnhanced.java (100%) rename wings/{silencer => silencer-curse}/src/test/java/pro/fessional/wings/silencer/app/service/impl/TestThisLazyServiceItself.java (100%) rename wings/{silencer => silencer-curse}/src/test/java/pro/fessional/wings/silencer/app/service/impl/TestThisLazyServiceProxy.java (100%) rename wings/{silencer => silencer-curse}/src/test/java/pro/fessional/wings/silencer/enhance/ThisLazyCglibTest.java (100%) rename wings/{silencer => silencer-curse}/src/test/java/pro/fessional/wings/silencer/enhance/ThisLazyProxyTest.java (100%) rename wings/{silencer => silencer-curse}/src/test/java/pro/fessional/wings/silencer/spring/boot/WingsSilencerMergeTest.java (100%) rename wings/{silencer => silencer-curse}/src/test/resources/wings-conf/wings-merge-a.properties (100%) rename wings/{silencer => silencer-curse}/src/test/resources/wings-conf/wings-merge-b.properties (100%) rename wings/{silencer-curse/src/main/java/pro/fessional/wings/silencer/spring/help/VersionInfoHelper.java => silencer/src/main/java/pro/fessional/wings/silencer/support/InspectHelper.java} (86%) create mode 100644 wings/silencer/src/main/java/pro/fessional/wings/silencer/support/PropHelper.java rename wings/{silencer-curse/src/main/java/pro/fessional/wings/silencer/spring/help/SubclassSpringLoader.java => silencer/src/main/java/pro/fessional/wings/silencer/support/SubclassGather.java} (95%) rename wings/silencer/src/main/java/pro/fessional/wings/silencer/{enhance => support}/TypeSugar.java (99%) rename wings/{silencer-curse/src/test/java/pro/fessional/wings/silencer/spring/help/VersionInfoHelperTest.java => silencer/src/test/java/pro/fessional/wings/silencer/support/InspectHelperTest.java} (58%) create mode 100644 wings/silencer/src/test/java/pro/fessional/wings/silencer/support/PropHelperTest.java rename wings/silencer/src/test/java/pro/fessional/wings/silencer/{enhance => support}/TypeSugarMain.java (96%) rename wings/silencer/src/test/java/pro/fessional/wings/silencer/{enhance => support}/TypeSugarTest.java (81%) diff --git a/WingsBoot.t.md b/WingsBoot.t.md index 05978ad1d..af2032dfb 100644 --- a/WingsBoot.t.md +++ b/WingsBoot.t.md @@ -39,6 +39,7 @@ Use `t.md` as local [Test Management](https://www.jetbrains.com/help/idea/test-m * 11033 ThisLazyCglibTest: thisLazy with cglib * 11034 ThisLazyProxyTest: thisLazy with default jdk proxy * 11035 TypedClassTest: ResolvableType sugar +* 11036 CommonPropHelperTest: comma delimited string ## 12 Faceless diff --git a/example/winx-devops/src/test/java/com/moilioncircle/wings/devops/project/Devops7EnumsDumperTest.java b/example/winx-devops/src/test/java/com/moilioncircle/wings/devops/project/Devops7EnumsDumperTest.java index cd3d9d34f..8e0d54582 100644 --- a/example/winx-devops/src/test/java/com/moilioncircle/wings/devops/project/Devops7EnumsDumperTest.java +++ b/example/winx-devops/src/test/java/com/moilioncircle/wings/devops/project/Devops7EnumsDumperTest.java @@ -8,7 +8,7 @@ import org.springframework.boot.test.context.SpringBootTest; import org.springframework.core.io.ResourceLoader; import pro.fessional.mirana.data.CodeEnum; -import pro.fessional.wings.silencer.spring.help.SubclassSpringLoader; +import pro.fessional.wings.silencer.support.SubclassGather; import java.util.Map; @@ -27,7 +27,7 @@ public class Devops7EnumsDumperTest { @Test public void dumpCodeEnum() { - SubclassSpringLoader loader = new SubclassSpringLoader(resourceLoader); + SubclassGather loader = new SubclassGather(resourceLoader); Class superEnum = CodeEnum.class; Map, Enum[]> enums = loader.loadSubEnums("pro.fessional", superEnum); diff --git a/observe/docs b/observe/docs index 6d6c110a6..e1df9bdee 160000 --- a/observe/docs +++ b/observe/docs @@ -1 +1 @@ -Subproject commit 6d6c110a640c4bbfc56b19fd7b177f690d758afc +Subproject commit e1df9bdeefc83fdf5720de4b6bcf6b1ca075ae3d diff --git a/radiant/tiny-mail/src/main/java/pro/fessional/wings/tiny/mail/sender/TinyMailConfig.java b/radiant/tiny-mail/src/main/java/pro/fessional/wings/tiny/mail/sender/TinyMailConfig.java index 9c35a5abd..aa3e5afec 100644 --- a/radiant/tiny-mail/src/main/java/pro/fessional/wings/tiny/mail/sender/TinyMailConfig.java +++ b/radiant/tiny-mail/src/main/java/pro/fessional/wings/tiny/mail/sender/TinyMailConfig.java @@ -9,8 +9,8 @@ import java.util.Arrays; import java.util.Objects; -import static pro.fessional.wings.silencer.spring.help.CommonPropHelper.mergeNotValue; -import static pro.fessional.wings.silencer.spring.help.CommonPropHelper.notValue; +import static pro.fessional.wings.silencer.support.PropHelper.mergeIfNon; +import static pro.fessional.wings.silencer.support.PropHelper.nonValue; /** * hashCode and equals with @@ -138,27 +138,27 @@ public void adopt(TinyMailConfig that) { public void merge(MailProperties that) { if (that == null) return; - if (notValue(getHost())) { + if (nonValue(getHost())) { setHost(that.getHost()); } if (getPort() == null) { setPort(that.getPort()); } - if (notValue(getUsername())) { + if (nonValue(getUsername())) { setUsername(that.getUsername()); } final String password = getPassword(); - if (notValue(password)) { + if (nonValue(password)) { setPassword(that.getPassword()); } - if (notValue(getProtocol())) { + if (nonValue(getProtocol())) { setProtocol(that.getProtocol()); } if (getDefaultEncoding() == null) { setDefaultEncoding(that.getDefaultEncoding()); } - mergeNotValue(getProperties(), that.getProperties()); + mergeIfNon(getProperties(), that.getProperties()); } /** @@ -169,12 +169,12 @@ public void merge(TinyMailConfig that) { merge((MailProperties) that); if (dryrun == null) dryrun = that.dryrun; - if (notValue(name)) name = that.name; - if (notValue(from)) from = that.from; + if (nonValue(name)) name = that.name; + if (nonValue(from)) from = that.from; if (to == null) to = that.to; if (cc == null) cc = that.cc; if (bcc == null) bcc = that.bcc; - if (notValue(reply)) reply = that.reply; + if (nonValue(reply)) reply = that.reply; if (html == null) html = that.html; } diff --git a/radiant/tiny-mail/src/main/java/pro/fessional/wings/tiny/mail/service/impl/TinyMailListServiceImpl.java b/radiant/tiny-mail/src/main/java/pro/fessional/wings/tiny/mail/service/impl/TinyMailListServiceImpl.java index ad0104e58..5d366cf8d 100644 --- a/radiant/tiny-mail/src/main/java/pro/fessional/wings/tiny/mail/service/impl/TinyMailListServiceImpl.java +++ b/radiant/tiny-mail/src/main/java/pro/fessional/wings/tiny/mail/service/impl/TinyMailListServiceImpl.java @@ -198,10 +198,11 @@ public TinyMailPlain loadDetail(long id) { @Override public void afterPropertiesSet() { final WinMailSenderTable t = winMailSenderDao.getTable(); + // skip large field plainFields = new SelectField[]{ t.Id, t.MailApps, t.MailRuns, t.MailConf, t.MailFrom, t.MailTo, t.MailCc, t.MailBcc, - t.MailReply, t.MailSubj, /*t.MailText,*/ t.MailFile, + t.MailReply, t.MailSubj, /*t.MailText, t.MailFile,*/ t.MailHtml, t.MailMark, t.MailDate, t.CreateDt, t.LastSend, /*t.LastFail,*/ t.LastDone, t.NextSend, t.SumSend, t.SumFail, t.SumDone, t.MaxFail, t.MaxDone, @@ -209,6 +210,6 @@ public void afterPropertiesSet() { sortsFields.put("id", t.Id); sortsFields.put("done", t.LastDone); - sortsFields.put("fail", t.LastFail); + sortsFields.put("send", t.LastSend); } } diff --git a/radiant/tiny-mail/src/main/java/pro/fessional/wings/tiny/mail/service/impl/TinyMailServiceImpl.java b/radiant/tiny-mail/src/main/java/pro/fessional/wings/tiny/mail/service/impl/TinyMailServiceImpl.java index 76facdc7b..0e1732775 100644 --- a/radiant/tiny-mail/src/main/java/pro/fessional/wings/tiny/mail/service/impl/TinyMailServiceImpl.java +++ b/radiant/tiny-mail/src/main/java/pro/fessional/wings/tiny/mail/service/impl/TinyMailServiceImpl.java @@ -1,10 +1,8 @@ package pro.fessional.wings.tiny.mail.service.impl; -import com.fasterxml.jackson.databind.JsonNode; import jakarta.mail.MessagingException; import lombok.Data; import lombok.Setter; -import lombok.SneakyThrows; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.jetbrains.annotations.NotNull; @@ -25,14 +23,15 @@ import pro.fessional.mirana.pain.ThrowableUtil; import pro.fessional.mirana.time.DateLocaling; import pro.fessional.mirana.time.ThreadNow; +import pro.fessional.wings.faceless.convention.EmptySugar; import pro.fessional.wings.faceless.convention.EmptyValue; import pro.fessional.wings.faceless.service.journal.JournalService; import pro.fessional.wings.faceless.service.lightid.LightIdService; import pro.fessional.wings.silencer.modulate.RunMode; import pro.fessional.wings.silencer.modulate.RuntimeMode; import pro.fessional.wings.silencer.spring.boot.ConditionalWingsEnabled; -import pro.fessional.wings.silencer.spring.help.CommonPropHelper; -import pro.fessional.wings.slardar.jackson.JacksonHelper; +import pro.fessional.wings.silencer.support.PropHelper; +import pro.fessional.wings.slardar.fastjson.FastJsonHelper; import pro.fessional.wings.tiny.mail.database.autogen.tables.WinMailSenderTable; import pro.fessional.wings.tiny.mail.database.autogen.tables.daos.WinMailSenderDao; import pro.fessional.wings.tiny.mail.database.autogen.tables.pojos.WinMailSender; @@ -52,7 +51,6 @@ import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; -import java.util.Iterator; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; @@ -60,8 +58,8 @@ import java.util.concurrent.atomic.AtomicInteger; import static org.springframework.scheduling.annotation.ScheduledAnnotationBeanPostProcessor.DEFAULT_TASK_SCHEDULER_BEAN_NAME; -import static pro.fessional.wings.silencer.spring.help.CommonPropHelper.arrayOrNull; -import static pro.fessional.wings.silencer.spring.help.CommonPropHelper.notValue; +import static pro.fessional.wings.silencer.support.PropHelper.commaArray; +import static pro.fessional.wings.silencer.support.PropHelper.nonValue; /** * @author trydofor @@ -209,7 +207,7 @@ public long save(@NotNull TinyMailPlain msg) { po.setMailSubj(msg.getSubject()); po.setMailText(msg.getContent()); po.setMailHtml(BoxedCastUtil.orElse(msg.getHtml(), config.getHtml())); - po.setMailFile(toStringMap(msg.getAttachment())); + po.setMailFile(toString(msg.getAttachment())); po.setMailMark(msg.getMark()); po.setMailDate(md); @@ -282,18 +280,18 @@ private TinyMailMessage makeMailMessage(@NotNull TinyMailConfig config, @NotNull if (msg == null) { message.setFrom(po.getMailFrom()); - message.setTo(arrayOrNull(po.getMailTo(), true)); - message.setCc(arrayOrNull(po.getMailCc(), true)); - message.setBcc(arrayOrNull(po.getMailBcc(), true)); - message.setReply(toStrOrNull(po.getMailReply())); + message.setTo(commaArray(po.getMailTo())); + message.setCc(commaArray(po.getMailCc())); + message.setBcc(commaArray(po.getMailBcc())); + message.setReply(EmptySugar.emptyToNull(po.getMailReply())); message.setHtml(po.getMailHtml()); message.setSubject(po.getMailSubj()); message.setContent(po.getMailText()); - final Map files = toResource(po.getMailFile()); + final Map files = resourceString(po.getMailFile()); if (!files.isEmpty()) { message.setAttachment(files); } - message.setBizMark(toStrOrNull(po.getMailMark())); + message.setBizMark(EmptySugar.emptyToNull(po.getMailMark())); } else { if (msg.getFrom() != null) message.setFrom(msg.getFrom()); @@ -328,7 +326,7 @@ private WinMailSender saveMailSender(@NotNull TinyMailConfig config, @NotNull Ti po.setMailSubj(msg.getSubject()); po.setMailText(msg.getContent()); po.setMailHtml(BoxedCastUtil.orElse(msg.getHtml(), config.getHtml())); - po.setMailFile(toString(msg.getAttachment())); + po.setMailFile(stringResource(msg.getAttachment())); po.setMailMark(msg.getMark()); final LocalDateTime md = msg.getDate(); @@ -694,7 +692,7 @@ private String toString(String[] arr, String[] elz) { @Nullable private String toString(String str, String[] elz) { - return notValue(str) + return nonValue(str) ? (elz == null || elz.length == 0 ? null : String.join(",", elz)) @@ -703,40 +701,34 @@ private String toString(String str, String[] elz) { @Nullable private String toString(String str, String elz) { - return notValue(str) ? elz : str; - } - - @SneakyThrows - @NotNull - private String toString(Map file) { - if (file == null || file.isEmpty()) return Null.Str; - Map nameUrl = new LinkedHashMap<>(file.size()); - for (Map.Entry en : file.entrySet()) { - nameUrl.put(en.getKey(), CommonPropHelper.toString(en.getValue())); - } - return JacksonHelper.string(nameUrl, true); + return nonValue(str) ? elz : str; } - @SneakyThrows - @NotNull - private String toStringMap(Map file) { - if (file == null || file.isEmpty()) return Null.Str; - return JacksonHelper.string(file, true); + @Nullable + private String toString(Map file) { + if (file == null || file.isEmpty()) return null; + return FastJsonHelper.string(file); } @Nullable - private String toStrOrNull(String str) { - return (str == null || str.isEmpty()) ? null : str; + private String stringResource(Map file) { + if (file == null || file.isEmpty()) return null; + + Map nameUrl = new LinkedHashMap<>(); + for (Map.Entry en : file.entrySet()) { + nameUrl.put(en.getKey(), PropHelper.stringResource(en.getValue())); + } + return toString(nameUrl); } @NotNull - private Map toResource(String map) { - if (map == null || map.isEmpty()) return Collections.emptyMap(); + private Map resourceString(String jsonMap) { + if (EmptySugar.asEmptyValue(jsonMap)) return Collections.emptyMap(); + final Map rst = new LinkedHashMap<>(); - final Iterator> node = JacksonHelper.object(map).fields(); - while (node.hasNext()) { - final Map.Entry en = node.next(); - rst.put(en.getKey(), resourceLoader.getResource(en.getValue().asText())); + Map map = FastJsonHelper.object(jsonMap, Map.class, String.class, String.class); + for (Map.Entry en : map.entrySet()) { + rst.put(en.getKey(), PropHelper.resourceString(en.getValue(), resourceLoader)); } return rst; } diff --git a/radiant/tiny-mail/src/main/resources/wings-flywave/master/07-mail/2020-10-27v01-tiny_mail.sql b/radiant/tiny-mail/src/main/resources/wings-flywave/master/07-mail/2020-10-27v01-tiny_mail.sql index 6b560734a..358d8ce68 100644 --- a/radiant/tiny-mail/src/main/resources/wings-flywave/master/07-mail/2020-10-27v01-tiny_mail.sql +++ b/radiant/tiny-mail/src/main/resources/wings-flywave/master/07-mail/2020-10-27v01-tiny_mail.sql @@ -1,37 +1,37 @@ CREATE TABLE `win_mail_sender` ( - `id` BIGINT(20) NOT NULL COMMENT 'primary key/mail_id', - `create_dt` DATETIME(3) NOT NULL DEFAULT NOW(3) COMMENT 'created datetime(sys)', - `modify_dt` DATETIME(3) NOT NULL DEFAULT '1000-01-01' ON UPDATE NOW(3) COMMENT 'modified datetime(sys)', - `delete_dt` DATETIME(3) NOT NULL DEFAULT '1000-01-01' COMMENT 'logic deleted datetime', - `commit_id` BIGINT(20) NOT NULL COMMENT 'commit id', - `mail_apps` VARCHAR(500) NOT NULL DEFAULT '' COMMENT 'belong to applications, comma-separated, default spring.application.name', - `mail_runs` VARCHAR(100) NOT NULL DEFAULT '' COMMENT 'RunMode(product|test|develop|local), comma-separated case-insensitive, default all', - `mail_conf` VARCHAR(100) NOT NULL DEFAULT '' COMMENT 'config name, default', - `mail_from` VARCHAR(200) NOT NULL DEFAULT '' COMMENT 'mail from (sender)', - `mail_to` VARCHAR(500) NOT NULL DEFAULT '' COMMENT 'mail to, comma-separated', - `mail_cc` VARCHAR(500) NOT NULL DEFAULT '' COMMENT 'mail cc, comma-separated', - `mail_bcc` VARCHAR(500) NOT NULL DEFAULT '' COMMENT 'mail bcc, comma-separated', - `mail_reply` VARCHAR(200) NOT NULL DEFAULT '' COMMENT 'mail reply', - `mail_subj` VARCHAR(400) NOT NULL DEFAULT '' COMMENT 'mail subject', - `mail_text` TEXT NULL COMMENT 'mail content', - `mail_html` TINYINT(1) NOT NULL DEFAULT '1' COMMENT 'whether HTML email', - `mail_file` VARCHAR(9000) NOT NULL DEFAULT '' COMMENT 'attachment name and path map, json format', - `mail_mark` VARCHAR(200) NOT NULL DEFAULT '' COMMENT 'space-separated business key', - `mail_date` DATETIME(3) NOT NULL DEFAULT '1000-01-01' COMMENT 'scheduled mail send (sys)', - `last_send` DATETIME(3) NOT NULL DEFAULT '1000-01-01' COMMENT 'previous send (sys)', - `last_fail` TEXT NULL COMMENT 'previous fail info', - `last_done` DATETIME(3) NOT NULL DEFAULT '1000-01-01' COMMENT 'previous success (sys)', - `last_cost` INT(11) NOT NULL DEFAULT '0' COMMENT 'mills of previous send cost', - `next_send` DATETIME(3) NOT NULL DEFAULT '1000-01-01' COMMENT 'next send datetime (sys)', - `next_lock` INT(11) NOT NULL DEFAULT '0' COMMENT 'optimistic lock of sending', - `sum_send` INT(11) NOT NULL DEFAULT '0' COMMENT 'total count of send', - `sum_fail` INT(11) NOT NULL DEFAULT '0' COMMENT 'total count of fail', - `sum_done` INT(11) NOT NULL DEFAULT '0' COMMENT 'total count of success', - `max_fail` INT(11) NOT NULL DEFAULT '0' COMMENT 'max count of fail, 0 means use the config', - `max_done` INT(11) NOT NULL DEFAULT '0' COMMENT 'max count of success, 0 means use the config', - `ref_type` INT(11) NOT NULL DEFAULT '0' COMMENT 'ref type to mark key1, key2 use', - `ref_key1` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'ref key1, generally the primary key', - `ref_key2` VARCHAR(500) NOT NULL DEFAULT '' COMMENT 'ref key2, generally the composite data', + `id` BIGINT(20) NOT NULL COMMENT 'primary key/mail_id', + `create_dt` DATETIME(3) NOT NULL DEFAULT NOW(3) COMMENT 'created datetime(sys)', + `modify_dt` DATETIME(3) NOT NULL DEFAULT '1000-01-01' ON UPDATE NOW(3) COMMENT 'modified datetime(sys)', + `delete_dt` DATETIME(3) NOT NULL DEFAULT '1000-01-01' COMMENT 'logic deleted datetime', + `commit_id` BIGINT(20) NOT NULL COMMENT 'commit id', + `mail_apps` VARCHAR(500) NOT NULL DEFAULT '' COMMENT 'belong to applications, comma-separated, default spring.application.name', + `mail_runs` VARCHAR(100) NOT NULL DEFAULT '' COMMENT 'RunMode(product|test|develop|local), comma-separated case-insensitive, default all', + `mail_conf` VARCHAR(100) NOT NULL DEFAULT '' COMMENT 'config name, default', + `mail_from` VARCHAR(200) NOT NULL DEFAULT '' COMMENT 'mail from (sender)', + `mail_to` VARCHAR(900) NOT NULL DEFAULT '' COMMENT 'mail to, comma-separated', + `mail_cc` VARCHAR(900) NOT NULL DEFAULT '' COMMENT 'mail cc, comma-separated', + `mail_bcc` VARCHAR(900) NOT NULL DEFAULT '' COMMENT 'mail bcc, comma-separated', + `mail_reply` VARCHAR(200) NOT NULL DEFAULT '' COMMENT 'mail reply', + `mail_subj` VARCHAR(400) NOT NULL DEFAULT '' COMMENT 'mail subject', + `mail_text` TEXT NULL COMMENT 'mail content', + `mail_html` TINYINT(1) NOT NULL DEFAULT '1' COMMENT 'whether HTML email', + `mail_file` TEXT NULL COMMENT 'attachment name and path map, json format', + `mail_mark` VARCHAR(900) NOT NULL DEFAULT '' COMMENT 'business key to lookup', + `mail_date` DATETIME(3) NOT NULL DEFAULT '1000-01-01' COMMENT 'scheduled mail send (sys)', + `last_send` DATETIME(3) NOT NULL DEFAULT '1000-01-01' COMMENT 'previous send (sys)', + `last_fail` TEXT NULL COMMENT 'previous fail info', + `last_done` DATETIME(3) NOT NULL DEFAULT '1000-01-01' COMMENT 'previous success (sys)', + `last_cost` INT(11) NOT NULL DEFAULT '0' COMMENT 'mills of previous send cost', + `next_send` DATETIME(3) NOT NULL DEFAULT '1000-01-01' COMMENT 'next send datetime (sys)', + `next_lock` INT(11) NOT NULL DEFAULT '0' COMMENT 'optimistic lock of sending', + `sum_send` INT(11) NOT NULL DEFAULT '0' COMMENT 'total count of send', + `sum_fail` INT(11) NOT NULL DEFAULT '0' COMMENT 'total count of fail', + `sum_done` INT(11) NOT NULL DEFAULT '0' COMMENT 'total count of success', + `max_fail` INT(11) NOT NULL DEFAULT '0' COMMENT 'max count of fail, 0 means use the config', + `max_done` INT(11) NOT NULL DEFAULT '0' COMMENT 'max count of success, 0 means use the config', + `ref_type` INT(11) NOT NULL DEFAULT '0' COMMENT 'ref type indicate key1, key2 usage', + `ref_key1` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'ref key1, generally the primary key', + `ref_key2` VARCHAR(500) NOT NULL DEFAULT '' COMMENT 'ref key2, generally the composite data', PRIMARY KEY (`id`), INDEX ix_next_send (`next_send`), INDEX ix_sum_done (`sum_done`), diff --git a/radiant/tiny-mail/src/test/java/pro/fessional/wings/tiny/mail/service/ResourceMapTest.java b/radiant/tiny-mail/src/test/java/pro/fessional/wings/tiny/mail/service/ResourceMapTest.java index bb0e013d9..6369ca7d3 100644 --- a/radiant/tiny-mail/src/test/java/pro/fessional/wings/tiny/mail/service/ResourceMapTest.java +++ b/radiant/tiny-mail/src/test/java/pro/fessional/wings/tiny/mail/service/ResourceMapTest.java @@ -9,7 +9,7 @@ import org.springframework.core.io.DefaultResourceLoader; import org.springframework.core.io.Resource; import org.springframework.core.io.ResourceLoader; -import pro.fessional.wings.silencer.spring.help.CommonPropHelper; +import pro.fessional.wings.silencer.support.PropHelper; import java.io.IOException; import java.util.Iterator; @@ -36,7 +36,7 @@ public void jsonResourceSerializer() throws IOException { Map urls = new LinkedHashMap<>(); for (Map.Entry en : res1.entrySet()) { - urls.put(en.getKey(), CommonPropHelper.toString(en.getValue())); + urls.put(en.getKey(), PropHelper.stringResource(en.getValue())); } final String json = objectMapper.writeValueAsString(urls); Map res2 = new LinkedHashMap<>(); diff --git a/radiant/tiny-task/src/main/java/pro/fessional/wings/tiny/task/service/impl/TinyTaskExecServiceImpl.java b/radiant/tiny-task/src/main/java/pro/fessional/wings/tiny/task/service/impl/TinyTaskExecServiceImpl.java index 6616a82f1..36edca634 100644 --- a/radiant/tiny-task/src/main/java/pro/fessional/wings/tiny/task/service/impl/TinyTaskExecServiceImpl.java +++ b/radiant/tiny-task/src/main/java/pro/fessional/wings/tiny/task/service/impl/TinyTaskExecServiceImpl.java @@ -57,7 +57,7 @@ import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.locks.Lock; -import static pro.fessional.wings.silencer.spring.help.CommonPropHelper.arrayOrNull; +import static pro.fessional.wings.silencer.support.PropHelper.commaArray; import static pro.fessional.wings.tiny.task.schedule.exec.NoticeExec.WhenDone; import static pro.fessional.wings.tiny.task.schedule.exec.NoticeExec.WhenExec; import static pro.fessional.wings.tiny.task.schedule.exec.NoticeExec.WhenFail; @@ -316,7 +316,7 @@ private boolean notEnable(Boolean b, long id, String key) { private boolean notApps(String apps, long id, String key) { if (StringUtils.isEmpty(apps)) return false; - for (String s : arrayOrNull(apps, true)) { + for (String s : commaArray(apps)) { if (s.trim().equals(appName)) return false; } log.info("skip tiny-task for not apps={}, cur={}, id={}, prop={}", apps, appName, id, key); @@ -343,7 +343,7 @@ private boolean notRuns(String runs, long id, String key) { private Set noticeWhen(String nw) { if (nw == null || nw.isEmpty()) return Collections.emptySet(); Set rs = new HashSet<>(); - for (String s : arrayOrNull(nw, true)) { + for (String s : commaArray(nw)) { rs.add(s.trim().toLowerCase()); } return rs; diff --git a/wings/faceless-jooq/src/main/java/pro/fessional/wings/faceless/spring/prop/FacelessJooqCudProp.java b/wings/faceless-jooq/src/main/java/pro/fessional/wings/faceless/spring/prop/FacelessJooqCudProp.java index abf283321..9e561812b 100644 --- a/wings/faceless-jooq/src/main/java/pro/fessional/wings/faceless/spring/prop/FacelessJooqCudProp.java +++ b/wings/faceless-jooq/src/main/java/pro/fessional/wings/faceless/spring/prop/FacelessJooqCudProp.java @@ -11,7 +11,7 @@ import java.util.Map; import java.util.Set; -import static pro.fessional.wings.silencer.spring.help.CommonPropHelper.DisabledValue; +import static pro.fessional.wings.silencer.support.PropHelper.DisabledValue; /** * CUD listener settings for jooq. @@ -56,7 +56,7 @@ public class FacelessJooqCudProp { * Listening tables and their fields. `empty` means no fields are recorded, `-` means this table is ignored. * CUD listens to tables and fields, both tables and fields are case-sensitive. * - * @see pro.fessional.wings.silencer.spring.help.CommonPropHelper#DisabledValue + * @see pro.fessional.wings.silencer.support.PropHelper#DisabledValue * @see #Key$table */ private Map> table = Collections.emptyMap(); diff --git a/wings/faceless/src/main/java/pro/fessional/wings/faceless/convention/EmptySugar.java b/wings/faceless/src/main/java/pro/fessional/wings/faceless/convention/EmptySugar.java index e33bed889..6c6f121eb 100644 --- a/wings/faceless/src/main/java/pro/fessional/wings/faceless/convention/EmptySugar.java +++ b/wings/faceless/src/main/java/pro/fessional/wings/faceless/convention/EmptySugar.java @@ -147,7 +147,7 @@ public static boolean notEmptyValue(OffsetDateTime v) { // ///////////////////// public static boolean asEmptyValue(String v) { - return v == null || v.trim().isEmpty(); + return v == null || v.isBlank(); } public static boolean asEmptyValue(Integer v) { diff --git a/wings/silencer-curse/src/main/java/pro/fessional/wings/silencer/common/Splitter.java b/wings/silencer-curse/src/main/java/pro/fessional/wings/silencer/common/Splitter.java deleted file mode 100644 index cf23afb57..000000000 --- a/wings/silencer-curse/src/main/java/pro/fessional/wings/silencer/common/Splitter.java +++ /dev/null @@ -1,104 +0,0 @@ -package pro.fessional.wings.silencer.common; - -import org.apache.commons.lang3.StringUtils; -import org.jetbrains.annotations.NotNull; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.function.Function; - -/** - * @author trydofor - * @since 2023-06-13 - */ -public class Splitter { - - /** - * split string by separator - * - * @param sep separator - * @param str string - * @return list of string - * @see com.google.common.base.Splitter - */ - @NotNull - public static List list(@NotNull String sep, String str) { - if (str == null || str.isEmpty()) return Collections.emptyList(); - return com.google.common.base.Splitter.on(sep).splitToList(str); - } - - /** - * split string by separator - * - * @param sep separator - * @param str string - * @param max max items - * @return list of string - * @see com.google.common.base.Splitter - */ - @NotNull - public static List list(@NotNull String sep, String str, int max) { - if (str == null || str.isEmpty()) return Collections.emptyList(); - return com.google.common.base.Splitter.on(sep).limit(max).splitToList(str); - } - - /** - * split string by separator and convert to T - * - * @param sep separator - * @param str string - * @param fun convert string to T - * @return list of T - * @see com.google.common.base.Splitter - */ - @NotNull - public static List list(@NotNull String sep, String str, @NotNull Function fun) { - if (str == null || str.isEmpty()) return Collections.emptyList(); - final Iterable iter = com.google.common.base.Splitter.on(sep).split(str); - List result = new ArrayList<>(); - for (String s : iter) { - result.add(fun.apply(s)); - } - return Collections.unmodifiableList(result); - } - - /** - * split string by separator and convert to T - * - * @param sep separator - * @param str string - * @param max max items - * @param fun convert string to T - * @return list of T - * @see com.google.common.base.Splitter - */ - @NotNull - public static List list(@NotNull String sep, String str, int max, @NotNull Function fun) { - if (str == null || str.isEmpty()) return Collections.emptyList(); - final Iterable iter = com.google.common.base.Splitter.on(sep).limit(max).split(str); - List result = new ArrayList<>(); - for (String s : iter) { - result.add(fun.apply(s)); - } - return Collections.unmodifiableList(result); - } - - /** - * count items split by separator - *
-     * 0 - if str is empty
-     * 1 - if str does not contain sep
-     * n+1 - if str contains n sep
-     * 
- * - * @param sep separator - * @param str string - * @return count of items - * @see StringUtils#countMatches(CharSequence, CharSequence) - */ - public static int count(@NotNull String sep, String str) { - if (str == null || str.isEmpty()) return 0; - return StringUtils.countMatches(str, sep) + 1; - } -} diff --git a/wings/silencer/src/main/java/pro/fessional/wings/silencer/enhance/ThisLazy.java b/wings/silencer-curse/src/main/java/pro/fessional/wings/silencer/enhance/ThisLazy.java similarity index 100% rename from wings/silencer/src/main/java/pro/fessional/wings/silencer/enhance/ThisLazy.java rename to wings/silencer-curse/src/main/java/pro/fessional/wings/silencer/enhance/ThisLazy.java diff --git a/wings/silencer/src/main/java/pro/fessional/wings/silencer/enhance/ThisLazyAware.java b/wings/silencer-curse/src/main/java/pro/fessional/wings/silencer/enhance/ThisLazyAware.java similarity index 100% rename from wings/silencer/src/main/java/pro/fessional/wings/silencer/enhance/ThisLazyAware.java rename to wings/silencer-curse/src/main/java/pro/fessional/wings/silencer/enhance/ThisLazyAware.java diff --git a/wings/silencer/src/main/java/pro/fessional/wings/silencer/enhance/ThisLazyPostProcessor.java b/wings/silencer-curse/src/main/java/pro/fessional/wings/silencer/enhance/ThisLazyPostProcessor.java similarity index 100% rename from wings/silencer/src/main/java/pro/fessional/wings/silencer/enhance/ThisLazyPostProcessor.java rename to wings/silencer-curse/src/main/java/pro/fessional/wings/silencer/enhance/ThisLazyPostProcessor.java diff --git a/wings/silencer-curse/src/main/java/pro/fessional/wings/silencer/spring/bean/SilencerCurseConfiguration.java b/wings/silencer-curse/src/main/java/pro/fessional/wings/silencer/spring/bean/SilencerCurseConfiguration.java index 594467e19..f0a0bcdcd 100644 --- a/wings/silencer-curse/src/main/java/pro/fessional/wings/silencer/spring/bean/SilencerCurseConfiguration.java +++ b/wings/silencer-curse/src/main/java/pro/fessional/wings/silencer/spring/bean/SilencerCurseConfiguration.java @@ -8,18 +8,20 @@ import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.config.BeanPostProcessor; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.info.GitProperties; import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import pro.fessional.wings.silencer.enhance.ThisLazyPostProcessor; import pro.fessional.wings.silencer.modulate.RuntimeMode; import pro.fessional.wings.silencer.runner.ApplicationInspectRunner; import pro.fessional.wings.silencer.runner.ApplicationReadyEventRunner; import pro.fessional.wings.silencer.spring.WingsOrdered; import pro.fessional.wings.silencer.spring.boot.ConditionalWingsEnabled; import pro.fessional.wings.silencer.spring.help.ApplicationContextHelper; -import pro.fessional.wings.silencer.spring.help.VersionInfoHelper; +import pro.fessional.wings.silencer.support.InspectHelper; import pro.fessional.wings.silencer.spring.prop.SilencerAutoLogProp; import pro.fessional.wings.silencer.spring.prop.SilencerEnabledProp; import pro.fessional.wings.silencer.spring.prop.SilencerRuntimeProp; @@ -84,17 +86,17 @@ public ApplicationInspectRunner infoGitJvmRunner(ApplicationContext context) { return new ApplicationInspectRunner(WingsOrdered.Lv1Config, args -> { - log.info("jvm-name=" + VersionInfoHelper.jvmName()); - log.info("jvm-version=" + VersionInfoHelper.jvmVersion()); - log.info("jvm-vendor=" + VersionInfoHelper.jvmVendor()); + log.info("jvm-name=" + InspectHelper.jvmName()); + log.info("jvm-version=" + InspectHelper.jvmVersion()); + log.info("jvm-vendor=" + InspectHelper.jvmVendor()); var git = context.getBean(GitProperties.class); - log.info("git-branch=" + VersionInfoHelper.branch(git)); - log.info("git-id=" + VersionInfoHelper.commitId(git)); - log.info("git-time=" + VersionInfoHelper.commitDateTime(git)); - log.info("git-build=" + VersionInfoHelper.buildDateTime(git)); - log.info("git-version=" + VersionInfoHelper.buildVersion(git)); - log.info("git-message=" + VersionInfoHelper.commitMessage(git)); + log.info("git-branch=" + InspectHelper.branch(git)); + log.info("git-id=" + InspectHelper.commitId(git)); + log.info("git-time=" + InspectHelper.commitDateTime(git)); + log.info("git-build=" + InspectHelper.buildDateTime(git)); + log.info("git-version=" + InspectHelper.buildVersion(git)); + log.info("git-message=" + InspectHelper.commitMessage(git)); }); } @@ -152,6 +154,13 @@ else if (exists.contains(name)) { }); } + @Bean + @ConditionalWingsEnabled + public static BeanPostProcessor thisLazyAwarePostProcessor() { + log.info("Silencer spring-auto thisLazyAwarePostProcessor"); + return new ThisLazyPostProcessor(); + } + @Bean @ConditionalWingsEnabled public RuntimeMode runtimeMode(SilencerRuntimeProp prop) { diff --git a/wings/silencer-curse/src/main/java/pro/fessional/wings/silencer/spring/help/CommonPropHelper.java b/wings/silencer-curse/src/main/java/pro/fessional/wings/silencer/spring/help/CommonPropHelper.java deleted file mode 100644 index a4bc93825..000000000 --- a/wings/silencer-curse/src/main/java/pro/fessional/wings/silencer/spring/help/CommonPropHelper.java +++ /dev/null @@ -1,110 +0,0 @@ -package pro.fessional.wings.silencer.spring.help; - -import lombok.SneakyThrows; -import org.jetbrains.annotations.Contract; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; -import org.springframework.core.io.ClassPathResource; -import org.springframework.core.io.Resource; -import org.springframework.util.ResourceUtils; -import org.springframework.util.StringUtils; - -import java.util.Collection; -import java.util.Collections; -import java.util.LinkedHashMap; -import java.util.LinkedHashSet; -import java.util.Map; - -import static org.springframework.util.ResourceUtils.CLASSPATH_URL_PREFIX; - -/** - * @author trydofor - * @since 2022-06-17 - */ -public class CommonPropHelper { - - public static final String DisabledValue = "-"; - public static final String MaskingValue = "*****"; - - public static boolean notValue(String str) { - return str == null || str.isEmpty() || DisabledValue.equals(str) || MaskingValue.equals(str); - } - - public static boolean hasValue(String value) { - return !notValue(value); - } - - @NotNull - public static LinkedHashSet onlyValue(Collection values) { - if (values == null) values = Collections.emptyList(); - LinkedHashSet set = new LinkedHashSet<>(values); - set.removeIf(CommonPropHelper::notValue); - return set; - } - - @NotNull - public static LinkedHashMap onlyValue(Map values) { - if (values == null) values = Collections.emptyMap(); - LinkedHashMap map = new LinkedHashMap<>(); - for (Map.Entry en : values.entrySet()) { - final String value = en.getValue(); - if (hasValue(value)) { - map.put(en.getKey(), value); - } - } - return map; - } - - /** - * Use 'classpath:' format for ClassPathResource and getURL().toExternalForm() for the rest - * - * @see ResourceUtils - */ - @SneakyThrows @NotNull - public static String toString(@NotNull Resource resource) { - if (resource instanceof ClassPathResource) { - final String path = ((ClassPathResource) resource).getPath(); - return CLASSPATH_URL_PREFIX + path; - } - return resource.getURL().toExternalForm(); - } - - /** - * if this.value is invalid, then use that.value by key matches. - * - * @param thiz this map - * @param that that map - */ - public static void mergeNotValue(@NotNull Map thiz, @Nullable Map that) { - if (that == null || that.isEmpty()) return; - - if (thiz.isEmpty()) { - thiz.putAll(that); - } - else { - for (Map.Entry en : thiz.entrySet()) { - final String v = en.getValue(); - if (notValue(v)) { - final String tv = that.get(en.getKey()); - en.setValue(tv); - } - } - } - } - - /** - * comma-separated values to StringArray - * - * @see StringUtils#commaDelimitedListToStringArray(String) - */ - @Contract("_,true->!null") - public static String[] arrayOrNull(String str, boolean nonnull) { - final String[] arr = StringUtils.commaDelimitedListToStringArray(str); - if (nonnull) { - return arr; - } - else { - return arr.length == 0 ? null : arr; - } - } -} diff --git a/wings/silencer-curse/src/test/java/pro/fessional/wings/silencer/app/TestSilencerCurseApplication.java b/wings/silencer-curse/src/test/java/pro/fessional/wings/silencer/app/TestSilencerCurseApplication.java index 27197d7c1..04889639f 100644 --- a/wings/silencer-curse/src/test/java/pro/fessional/wings/silencer/app/TestSilencerCurseApplication.java +++ b/wings/silencer-curse/src/test/java/pro/fessional/wings/silencer/app/TestSilencerCurseApplication.java @@ -2,13 +2,16 @@ import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Bean; +import pro.fessional.wings.silencer.app.conf.TestMergingProp; /** * @author trydofor * @since 2019-07-20 */ @SpringBootApplication +@EnableConfigurationProperties(TestMergingProp.class) public class TestSilencerCurseApplication { public interface InnerFace { diff --git a/wings/silencer/src/test/java/pro/fessional/wings/silencer/app/conf/TestMergingProp.java b/wings/silencer-curse/src/test/java/pro/fessional/wings/silencer/app/conf/TestMergingProp.java similarity index 100% rename from wings/silencer/src/test/java/pro/fessional/wings/silencer/app/conf/TestMergingProp.java rename to wings/silencer-curse/src/test/java/pro/fessional/wings/silencer/app/conf/TestMergingProp.java diff --git a/wings/silencer/src/test/java/pro/fessional/wings/silencer/app/service/TestThisLazyService.java b/wings/silencer-curse/src/test/java/pro/fessional/wings/silencer/app/service/TestThisLazyService.java similarity index 100% rename from wings/silencer/src/test/java/pro/fessional/wings/silencer/app/service/TestThisLazyService.java rename to wings/silencer-curse/src/test/java/pro/fessional/wings/silencer/app/service/TestThisLazyService.java diff --git a/wings/silencer/src/test/java/pro/fessional/wings/silencer/app/service/impl/TestThisLazyServiceEnhanced.java b/wings/silencer-curse/src/test/java/pro/fessional/wings/silencer/app/service/impl/TestThisLazyServiceEnhanced.java similarity index 100% rename from wings/silencer/src/test/java/pro/fessional/wings/silencer/app/service/impl/TestThisLazyServiceEnhanced.java rename to wings/silencer-curse/src/test/java/pro/fessional/wings/silencer/app/service/impl/TestThisLazyServiceEnhanced.java diff --git a/wings/silencer/src/test/java/pro/fessional/wings/silencer/app/service/impl/TestThisLazyServiceItself.java b/wings/silencer-curse/src/test/java/pro/fessional/wings/silencer/app/service/impl/TestThisLazyServiceItself.java similarity index 100% rename from wings/silencer/src/test/java/pro/fessional/wings/silencer/app/service/impl/TestThisLazyServiceItself.java rename to wings/silencer-curse/src/test/java/pro/fessional/wings/silencer/app/service/impl/TestThisLazyServiceItself.java diff --git a/wings/silencer/src/test/java/pro/fessional/wings/silencer/app/service/impl/TestThisLazyServiceProxy.java b/wings/silencer-curse/src/test/java/pro/fessional/wings/silencer/app/service/impl/TestThisLazyServiceProxy.java similarity index 100% rename from wings/silencer/src/test/java/pro/fessional/wings/silencer/app/service/impl/TestThisLazyServiceProxy.java rename to wings/silencer-curse/src/test/java/pro/fessional/wings/silencer/app/service/impl/TestThisLazyServiceProxy.java diff --git a/wings/silencer/src/test/java/pro/fessional/wings/silencer/enhance/ThisLazyCglibTest.java b/wings/silencer-curse/src/test/java/pro/fessional/wings/silencer/enhance/ThisLazyCglibTest.java similarity index 100% rename from wings/silencer/src/test/java/pro/fessional/wings/silencer/enhance/ThisLazyCglibTest.java rename to wings/silencer-curse/src/test/java/pro/fessional/wings/silencer/enhance/ThisLazyCglibTest.java diff --git a/wings/silencer/src/test/java/pro/fessional/wings/silencer/enhance/ThisLazyProxyTest.java b/wings/silencer-curse/src/test/java/pro/fessional/wings/silencer/enhance/ThisLazyProxyTest.java similarity index 100% rename from wings/silencer/src/test/java/pro/fessional/wings/silencer/enhance/ThisLazyProxyTest.java rename to wings/silencer-curse/src/test/java/pro/fessional/wings/silencer/enhance/ThisLazyProxyTest.java diff --git a/wings/silencer/src/test/java/pro/fessional/wings/silencer/spring/boot/WingsSilencerMergeTest.java b/wings/silencer-curse/src/test/java/pro/fessional/wings/silencer/spring/boot/WingsSilencerMergeTest.java similarity index 100% rename from wings/silencer/src/test/java/pro/fessional/wings/silencer/spring/boot/WingsSilencerMergeTest.java rename to wings/silencer-curse/src/test/java/pro/fessional/wings/silencer/spring/boot/WingsSilencerMergeTest.java diff --git a/wings/silencer/src/test/resources/wings-conf/wings-merge-a.properties b/wings/silencer-curse/src/test/resources/wings-conf/wings-merge-a.properties similarity index 100% rename from wings/silencer/src/test/resources/wings-conf/wings-merge-a.properties rename to wings/silencer-curse/src/test/resources/wings-conf/wings-merge-a.properties diff --git a/wings/silencer/src/test/resources/wings-conf/wings-merge-b.properties b/wings/silencer-curse/src/test/resources/wings-conf/wings-merge-b.properties similarity index 100% rename from wings/silencer/src/test/resources/wings-conf/wings-merge-b.properties rename to wings/silencer-curse/src/test/resources/wings-conf/wings-merge-b.properties diff --git a/wings/silencer/src/main/java/pro/fessional/wings/silencer/spring/bean/SilencerConfiguration.java b/wings/silencer/src/main/java/pro/fessional/wings/silencer/spring/bean/SilencerConfiguration.java index ba668531b..43468a0d9 100644 --- a/wings/silencer/src/main/java/pro/fessional/wings/silencer/spring/bean/SilencerConfiguration.java +++ b/wings/silencer/src/main/java/pro/fessional/wings/silencer/spring/bean/SilencerConfiguration.java @@ -2,13 +2,11 @@ import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; -import org.springframework.beans.factory.config.BeanPostProcessor; import org.springframework.context.ApplicationContext; import org.springframework.context.MessageSource; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.core.Ordered; -import pro.fessional.wings.silencer.enhance.ThisLazyPostProcessor; import pro.fessional.wings.silencer.message.MessageSourceHelper; import pro.fessional.wings.silencer.runner.ApplicationInspectRunner; import pro.fessional.wings.silencer.runner.ApplicationRunnerOrdered; @@ -38,14 +36,6 @@ public static WingsReorderProcessor wingsReorderProcessor() { return new WingsReorderProcessor(); } - - @Bean - @ConditionalWingsEnabled - public static BeanPostProcessor thisLazyAwarePostProcessor() { - log.info("Silencer spring-auto thisLazyAwarePostProcessor"); - return new ThisLazyPostProcessor(); - } - /** * @link Internationalization * @see org.springframework.boot.autoconfigure.context.MessageSourceAutoConfiguration diff --git a/wings/silencer-curse/src/main/java/pro/fessional/wings/silencer/spring/help/VersionInfoHelper.java b/wings/silencer/src/main/java/pro/fessional/wings/silencer/support/InspectHelper.java similarity index 86% rename from wings/silencer-curse/src/main/java/pro/fessional/wings/silencer/spring/help/VersionInfoHelper.java rename to wings/silencer/src/main/java/pro/fessional/wings/silencer/support/InspectHelper.java index eb8132a67..19d438e97 100644 --- a/wings/silencer-curse/src/main/java/pro/fessional/wings/silencer/spring/help/VersionInfoHelper.java +++ b/wings/silencer/src/main/java/pro/fessional/wings/silencer/support/InspectHelper.java @@ -1,4 +1,4 @@ -package pro.fessional.wings.silencer.spring.help; +package pro.fessional.wings.silencer.support; import org.springframework.boot.info.GitProperties; @@ -6,14 +6,11 @@ import java.time.ZoneId; import java.time.ZonedDateTime; -import static pro.fessional.wings.silencer.datetime.DateTimePattern.FMT_DATE_10; -import static pro.fessional.wings.silencer.datetime.DateTimePattern.FMT_FULL_19Z; - /** * @author trydofor * @since 2024-06-03 */ -public class VersionInfoHelper { +public class InspectHelper { public static String jvmName() { return System.getProperty("java.vm.name"); @@ -67,12 +64,12 @@ public static String buildVersion(GitProperties git) { private static String toDatetime(Instant time) { if (time == null) return null; ZonedDateTime zdt = ZonedDateTime.ofInstant(time, ZoneId.systemDefault()); - return FMT_FULL_19Z.format(zdt); + return zdt.toString(); } private static String toDate(Instant time) { if (time == null) return null; ZonedDateTime zdt = ZonedDateTime.ofInstant(time, ZoneId.systemDefault()); - return FMT_DATE_10.format(zdt); + return zdt.toLocalDate().toString(); } } diff --git a/wings/silencer/src/main/java/pro/fessional/wings/silencer/support/PropHelper.java b/wings/silencer/src/main/java/pro/fessional/wings/silencer/support/PropHelper.java new file mode 100644 index 000000000..720d24df0 --- /dev/null +++ b/wings/silencer/src/main/java/pro/fessional/wings/silencer/support/PropHelper.java @@ -0,0 +1,242 @@ +package pro.fessional.wings.silencer.support; + +import lombok.SneakyThrows; +import org.jetbrains.annotations.Contract; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.springframework.core.io.ClassPathResource; +import org.springframework.core.io.Resource; +import org.springframework.core.io.ResourceLoader; +import org.springframework.util.ResourceUtils; +import pro.fessional.mirana.data.Null; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.LinkedHashMap; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Map; + +import static org.springframework.util.ResourceUtils.CLASSPATH_URL_PREFIX; + +/** + * @author trydofor + * @since 2022-06-17 + */ +public class PropHelper { + + public static final String DisabledValue = "-"; + public static final String MaskingValue = "*****"; + + /** + * true if empty or DisabledValue or MaskingValue + */ + public static boolean nonValue(String str) { + return str == null || str.isBlank() || DisabledValue.equals(str) || MaskingValue.equals(str); + } + + /** + * true if not non-value + */ + public static boolean hasValue(String value) { + return !nonValue(value); + } + + /** + * uniq and remove non-value + */ + @NotNull + public static LinkedHashSet onlyValue(Collection values) { + if (values == null) return new LinkedHashSet<>(); + + final LinkedHashSet set = new LinkedHashSet<>(values); + set.removeIf(PropHelper::nonValue); + return set; + } + + /** + * remove item that has non-value + */ + @NotNull + public static LinkedHashMap onlyValue(Map values) { + if (values == null) return new LinkedHashMap<>(); + + final LinkedHashMap map = new LinkedHashMap<>(); + for (Map.Entry en : values.entrySet()) { + final String value = en.getValue(); + if (!nonValue(value)) { + map.put(en.getKey(), value); + } + } + return map; + } + + /** + * Use 'classpath:' format for ClassPathResource and getURL().toExternalForm() for the rest + * + * @see ResourceUtils + */ + @SneakyThrows + @Contract("!null->!null") + public static String stringResource(Resource resource) { + if (resource == null) return null; + + if (resource instanceof ClassPathResource) { + final String path = ((ClassPathResource) resource).getPath(); + return CLASSPATH_URL_PREFIX + path; + } + return resource.getURL().toExternalForm(); + } + + public static Resource resourceString(String url, @NotNull ResourceLoader resourceLoader) { + if (url == null || url.isBlank()) return null; + return resourceLoader.getResource(url); + } + + /** + * if this.value is non-value, then use that.value by key + * + * @param thiz this map + * @param that that map + */ + public static void mergeIfNon(@NotNull Map thiz, @Nullable Map that) { + if (that == null || that.isEmpty()) return; + + if (thiz.isEmpty()) { + thiz.putAll(that); + } + else { + for (Map.Entry en : thiz.entrySet()) { + final String v = en.getValue(); + if (nonValue(v)) { + final String tv = that.get(en.getKey()); + en.setValue(tv); + } + } + } + } + + /** + * parse comma-delimited-list string, no strip item, no drop + */ + @Contract("!null -> !null") + public static String commaString(Object[] items) { + return delimitedString(items, ",", false, false); + } + + /** + * parse comma-delimited-list string, no strip item, no drop + */ + @Contract("!null -> !null") + public static String commaString(Collection items) { + return delimitedString(items, ",", false, false); + } + + @Contract("!null,_,_ -> !null") + public static String commaString(Object[] items, boolean strip, boolean drop) { + return delimitedString(items, ",", strip, drop); + } + + @Contract("!null,_,_ -> !null") + public static String commaString(Collection items, boolean strip, boolean drop) { + return delimitedString(items, ",", strip, drop); + } + + @Contract("!null,_,_,_ -> !null") + public static String delimitedString(Object[] items, String delimiter, boolean strip, boolean drop) { + Collection its = items == null ? null : Arrays.asList(items); + return delimitedString(its, delimiter, strip, drop); + } + + @Contract("!null,_,_,_ -> !null") + public static String delimitedString(Collection items, String delimiter, boolean strip, boolean drop) { + if (items == null) return null; + + StringBuilder sb = new StringBuilder(); + boolean empty = true; + for (Object obj : items) { + if (obj == null) { + if (!drop) { + empty = false; + sb.append(delimiter); + } + continue; + } + + String str = obj.toString(); + if (strip) str = str.strip(); + + if (!(drop && nonValue(str))) { + empty = false; + sb.append(delimiter).append(str); + } + } + return empty ? Null.Str : sb.substring(delimiter.length()); + } + + /** + * parse comma-delimited-list string, strip item, drop non-value + */ + @NotNull + public static String[] commaArray(String commaString) { + return commaArray(commaString, true, true); + } + + /** + * parse comma-delimited-list string, whether to strip item, whether to drop non-value + */ + @NotNull + public static String[] commaArray(String commaString, boolean strip, boolean drop) { + List list = delimitedList(commaString, ",", strip, drop); + return list.toArray(Null.StrArr); + } + + /** + * parse comma-delimited-list string, strip item, drop non-value + */ + @NotNull + public static List commaList(String commaString) { + return commaList(commaString, true, true); + } + + /** + * parse comma-delimited-list string, whether to strip item, whether to drop non-value + */ + @NotNull + public static List commaList(String commaString, boolean strip, boolean drop) { + return delimitedList(commaString, ",", strip, drop); + } + + /** + * parse delimiter(comma if empty) delimited-list string, whether to strip item, whether to drop non-value + */ + @NotNull + public static List delimitedList(String delimitedString, String delimiter, boolean strip, boolean drop) { + if (delimitedString == null || delimitedString.isBlank() && drop) return Collections.emptyList(); + + if (delimiter == null || delimiter.isEmpty()) delimiter = ","; + final int len = delimiter.length(); + + List result = new ArrayList<>(); + int offset = 0; + int curIdx; + while ((curIdx = delimitedString.indexOf(delimiter, offset)) != -1) { + addValue(result, delimitedString.substring(offset, curIdx), strip, drop); + offset = curIdx + len; + + } + if (offset <= delimitedString.length()) { + addValue(result, delimitedString.substring(offset), strip, drop); + } + + return result; + } + + private static void addValue(List result, String str, boolean strip, boolean drop) { + if (strip) str = str.strip(); + if (drop && nonValue(str)) return; + result.add(str); + } +} diff --git a/wings/silencer-curse/src/main/java/pro/fessional/wings/silencer/spring/help/SubclassSpringLoader.java b/wings/silencer/src/main/java/pro/fessional/wings/silencer/support/SubclassGather.java similarity index 95% rename from wings/silencer-curse/src/main/java/pro/fessional/wings/silencer/spring/help/SubclassSpringLoader.java rename to wings/silencer/src/main/java/pro/fessional/wings/silencer/support/SubclassGather.java index c047f1dc4..0aa231b68 100644 --- a/wings/silencer-curse/src/main/java/pro/fessional/wings/silencer/spring/help/SubclassSpringLoader.java +++ b/wings/silencer/src/main/java/pro/fessional/wings/silencer/support/SubclassGather.java @@ -1,4 +1,4 @@ -package pro.fessional.wings.silencer.spring.help; +package pro.fessional.wings.silencer.support; import org.springframework.core.io.Resource; import org.springframework.core.io.ResourceLoader; @@ -24,12 +24,12 @@ * @author trydofor * @since 2020-07-04 */ -public class SubclassSpringLoader { +public class SubclassGather { private final ResourcePatternResolver resourcePatternResolver; private final MetadataReaderFactory metadataReaderFactory; - public SubclassSpringLoader(ResourceLoader resourceLoader) { + public SubclassGather(ResourceLoader resourceLoader) { resourcePatternResolver = ResourcePatternUtils.getResourcePatternResolver(resourceLoader); metadataReaderFactory = new CachingMetadataReaderFactory(resourceLoader); } diff --git a/wings/silencer/src/main/java/pro/fessional/wings/silencer/enhance/TypeSugar.java b/wings/silencer/src/main/java/pro/fessional/wings/silencer/support/TypeSugar.java similarity index 99% rename from wings/silencer/src/main/java/pro/fessional/wings/silencer/enhance/TypeSugar.java rename to wings/silencer/src/main/java/pro/fessional/wings/silencer/support/TypeSugar.java index f24e98014..200000a5a 100644 --- a/wings/silencer/src/main/java/pro/fessional/wings/silencer/enhance/TypeSugar.java +++ b/wings/silencer/src/main/java/pro/fessional/wings/silencer/support/TypeSugar.java @@ -1,4 +1,4 @@ -package pro.fessional.wings.silencer.enhance; +package pro.fessional.wings.silencer.support; import jakarta.annotation.Nullable; import lombok.SneakyThrows; diff --git a/wings/silencer/src/test/java/pro/fessional/wings/silencer/app/TestSilencerApplication.java b/wings/silencer/src/test/java/pro/fessional/wings/silencer/app/TestSilencerApplication.java index 770765d04..0877aff41 100644 --- a/wings/silencer/src/test/java/pro/fessional/wings/silencer/app/TestSilencerApplication.java +++ b/wings/silencer/src/test/java/pro/fessional/wings/silencer/app/TestSilencerApplication.java @@ -2,15 +2,12 @@ import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; -import org.springframework.boot.context.properties.EnableConfigurationProperties; -import pro.fessional.wings.silencer.app.conf.TestMergingProp; /** * @author trydofor * @since 2019-07-20 */ @SpringBootApplication -@EnableConfigurationProperties(TestMergingProp.class) public class TestSilencerApplication { public static void main(String[] args) { diff --git a/wings/silencer-curse/src/test/java/pro/fessional/wings/silencer/spring/help/VersionInfoHelperTest.java b/wings/silencer/src/test/java/pro/fessional/wings/silencer/support/InspectHelperTest.java similarity index 58% rename from wings/silencer-curse/src/test/java/pro/fessional/wings/silencer/spring/help/VersionInfoHelperTest.java rename to wings/silencer/src/test/java/pro/fessional/wings/silencer/support/InspectHelperTest.java index 361dbc47e..d554a25e3 100644 --- a/wings/silencer-curse/src/test/java/pro/fessional/wings/silencer/spring/help/VersionInfoHelperTest.java +++ b/wings/silencer/src/test/java/pro/fessional/wings/silencer/support/InspectHelperTest.java @@ -1,4 +1,4 @@ -package pro.fessional.wings.silencer.spring.help; +package pro.fessional.wings.silencer.support; import io.qameta.allure.TmsLink; import lombok.Setter; @@ -17,7 +17,7 @@ */ @SpringBootTest @Slf4j -class VersionInfoHelperTest { +class InspectHelperTest { @Setter(onMethod_ = { @Autowired }) private BuildProperties buildProperties; @@ -34,7 +34,7 @@ public void infoBuildAndGit() { log.info("git={}", gitProperties); Assertions.assertEquals("pro.fessional.wings",buildProperties.getGroup()); - Assertions.assertEquals("silencer-curse",buildProperties.getArtifact()); + Assertions.assertEquals("silencer",buildProperties.getArtifact()); Assertions.assertNotNull(gitProperties.getBranch()); // spring use git.commit.id, need commitIdGenerationMode=flat, but wings use full Assertions.assertNull(gitProperties.getCommitId()); @@ -42,17 +42,17 @@ public void infoBuildAndGit() { Assertions.assertNotNull(gitProperties.getCommitTime()); // safe and format - Assertions.assertNotNull(VersionInfoHelper.jvmName()); - Assertions.assertNotNull(VersionInfoHelper.jvmVersion()); - Assertions.assertNotNull(VersionInfoHelper.jvmVendor()); - Assertions.assertNotNull(VersionInfoHelper.commitIdShort(gitProperties)); - Assertions.assertNotNull(VersionInfoHelper.commitId(gitProperties)); - Assertions.assertNotNull(VersionInfoHelper.commitDate(gitProperties)); - Assertions.assertNotNull(VersionInfoHelper.commitDateTime(gitProperties)); - Assertions.assertNotNull(VersionInfoHelper.commitMessage(gitProperties)); - Assertions.assertNotNull(VersionInfoHelper.branch(gitProperties)); - Assertions.assertNotNull(VersionInfoHelper.buildDate(gitProperties)); - Assertions.assertNotNull(VersionInfoHelper.buildDateTime(gitProperties)); - Assertions.assertNotNull(VersionInfoHelper.buildVersion(gitProperties)); + Assertions.assertNotNull(InspectHelper.jvmName()); + Assertions.assertNotNull(InspectHelper.jvmVersion()); + Assertions.assertNotNull(InspectHelper.jvmVendor()); + Assertions.assertNotNull(InspectHelper.commitIdShort(gitProperties)); + Assertions.assertNotNull(InspectHelper.commitId(gitProperties)); + Assertions.assertNotNull(InspectHelper.commitDate(gitProperties)); + Assertions.assertNotNull(InspectHelper.commitDateTime(gitProperties)); + Assertions.assertNotNull(InspectHelper.commitMessage(gitProperties)); + Assertions.assertNotNull(InspectHelper.branch(gitProperties)); + Assertions.assertNotNull(InspectHelper.buildDate(gitProperties)); + Assertions.assertNotNull(InspectHelper.buildDateTime(gitProperties)); + Assertions.assertNotNull(InspectHelper.buildVersion(gitProperties)); } } \ No newline at end of file diff --git a/wings/silencer/src/test/java/pro/fessional/wings/silencer/support/PropHelperTest.java b/wings/silencer/src/test/java/pro/fessional/wings/silencer/support/PropHelperTest.java new file mode 100644 index 000000000..3d761be55 --- /dev/null +++ b/wings/silencer/src/test/java/pro/fessional/wings/silencer/support/PropHelperTest.java @@ -0,0 +1,44 @@ +package pro.fessional.wings.silencer.support; + +import io.qameta.allure.TmsLink; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +import java.util.List; + +/** + * @author trydofor + * @since 2024-06-28 + */ +class PropHelperTest { + + @Test + @TmsLink("C11036") + void testCommaList() { + Assertions.assertTrue(PropHelper.commaList("").isEmpty()); + Assertions.assertTrue(PropHelper.commaList(",").isEmpty()); + Assertions.assertTrue(PropHelper.commaList(",,").isEmpty()); + Assertions.assertEquals(List.of("1", "2"), PropHelper.commaList("1,,2")); + Assertions.assertEquals(List.of("1", "2"), PropHelper.commaList("1 , - , , 2 ")); + + Assertions.assertEquals(List.of(""), PropHelper.commaList("", false, false)); + Assertions.assertEquals(List.of("", ""), PropHelper.commaList(",", false, false)); + Assertions.assertEquals(List.of("", "", ""), PropHelper.commaList(",,", false, false)); + Assertions.assertEquals(List.of("1", "", "2"), PropHelper.commaList("1,,2", false, false)); + Assertions.assertEquals(List.of("1 ", " ", " 2 "), PropHelper.commaList("1 , , 2 ", false, false)); + + Assertions.assertNull(PropHelper.commaString((String[]) null)); + Assertions.assertEquals("", PropHelper.commaString(List.of(""))); + Assertions.assertEquals(",", PropHelper.commaString(List.of("",""))); + Assertions.assertEquals(",,1", PropHelper.commaString(List.of("", "", "1"))); + Assertions.assertEquals(",,1 ", PropHelper.commaString(List.of("", "", "1 "))); + Assertions.assertEquals(",,1 ,-", PropHelper.commaString(List.of("", "", "1 ", "-"))); + + Assertions.assertEquals("", PropHelper.commaString(List.of(""), true, true)); + Assertions.assertEquals("", PropHelper.commaString(List.of("", ""), true, true)); + Assertions.assertEquals("1", PropHelper.commaString(List.of("", "", "1"), true, true)); + Assertions.assertEquals("1", PropHelper.commaString(List.of("", "", "1 "), true, true)); + Assertions.assertEquals("1", PropHelper.commaString(List.of("", "", "1 ", "- "), true, true)); + Assertions.assertEquals("1 ,- ", PropHelper.commaString(List.of("", "", "1 ", "- "), false, true)); + } +} \ No newline at end of file diff --git a/wings/silencer/src/test/java/pro/fessional/wings/silencer/enhance/TypeSugarMain.java b/wings/silencer/src/test/java/pro/fessional/wings/silencer/support/TypeSugarMain.java similarity index 96% rename from wings/silencer/src/test/java/pro/fessional/wings/silencer/enhance/TypeSugarMain.java rename to wings/silencer/src/test/java/pro/fessional/wings/silencer/support/TypeSugarMain.java index bb12c9acc..e5bc1f527 100644 --- a/wings/silencer/src/test/java/pro/fessional/wings/silencer/enhance/TypeSugarMain.java +++ b/wings/silencer/src/test/java/pro/fessional/wings/silencer/support/TypeSugarMain.java @@ -1,4 +1,4 @@ -package pro.fessional.wings.silencer.enhance; +package pro.fessional.wings.silencer.support; import org.openjdk.jmh.annotations.Benchmark; import org.openjdk.jmh.annotations.BenchmarkMode; @@ -11,6 +11,7 @@ import org.openjdk.jmh.annotations.Warmup; import org.springframework.core.ResolvableType; import org.springframework.core.convert.TypeDescriptor; +import pro.fessional.wings.silencer.support.TypeSugar; import java.io.IOException; import java.util.List; diff --git a/wings/silencer/src/test/java/pro/fessional/wings/silencer/enhance/TypeSugarTest.java b/wings/silencer/src/test/java/pro/fessional/wings/silencer/support/TypeSugarTest.java similarity index 81% rename from wings/silencer/src/test/java/pro/fessional/wings/silencer/enhance/TypeSugarTest.java rename to wings/silencer/src/test/java/pro/fessional/wings/silencer/support/TypeSugarTest.java index df6fd6df7..0799fe419 100644 --- a/wings/silencer/src/test/java/pro/fessional/wings/silencer/enhance/TypeSugarTest.java +++ b/wings/silencer/src/test/java/pro/fessional/wings/silencer/support/TypeSugarTest.java @@ -1,4 +1,4 @@ -package pro.fessional.wings.silencer.enhance; +package pro.fessional.wings.silencer.support; import io.qameta.allure.TmsLink; import lombok.extern.slf4j.Slf4j; @@ -7,7 +7,6 @@ import org.springframework.core.ResolvableType; import org.springframework.core.convert.TypeDescriptor; import pro.fessional.mirana.data.R; -import pro.fessional.wings.silencer.app.conf.TestMergingProp; import java.time.LocalDate; import java.util.List; @@ -21,21 +20,25 @@ @Slf4j public class TypeSugarTest { + public static class Inner { + + } + @Test @TmsLink("C11035") void test() throws ClassNotFoundException { // Map var a0 = ResolvableType.forClassWithGenerics(Map.class, - ResolvableType.forClass(String.class), - ResolvableType.forClassWithGenerics(List.class, Long[].class) + ResolvableType.forClass(String.class), + ResolvableType.forClassWithGenerics(List.class, Long[].class) ); var a1 = TypeSugar.resolve(Map.class, String.class, List.class, Long[].class); log.info("type a1={}", a1); var a2 = TypeDescriptor.map(Map.class, - TypeDescriptor.valueOf(String.class), - TypeDescriptor.collection(List.class, TypeDescriptor.valueOf(Long[].class)) + TypeDescriptor.valueOf(String.class), + TypeDescriptor.collection(List.class, TypeDescriptor.valueOf(Long[].class)) ); var a3 = TypeSugar.describe(Map.class, String.class, List.class, Long[].class); @@ -45,15 +48,15 @@ void test() throws ClassNotFoundException { // Map,String> var b0 = ResolvableType.forClassWithGenerics(Map.class, - ResolvableType.forClassWithGenerics(List.class, Long[].class), - ResolvableType.forClass(String.class) + ResolvableType.forClassWithGenerics(List.class, Long[].class), + ResolvableType.forClass(String.class) ); var b1 = TypeSugar.resolve(Map.class, List.class, Long[].class, String.class); log.info("type b1={}", b1); var b2 = TypeDescriptor.map(Map.class, - TypeDescriptor.collection(List.class, TypeDescriptor.valueOf(Long[].class)), - TypeDescriptor.valueOf(String.class) + TypeDescriptor.collection(List.class, TypeDescriptor.valueOf(Long[].class)), + TypeDescriptor.valueOf(String.class) ); var b3 = TypeSugar.describe(Map.class, List.class, Long[].class, String.class); @@ -63,19 +66,19 @@ void test() throws ClassNotFoundException { // Map>,String> var c0 = ResolvableType.forClassWithGenerics(Map.class, - ResolvableType.forClassWithGenerics(List.class, - ResolvableType.forClassWithGenerics(List.class, Long[].class) - ), - ResolvableType.forClass(String.class) + ResolvableType.forClassWithGenerics(List.class, + ResolvableType.forClassWithGenerics(List.class, Long[].class) + ), + ResolvableType.forClass(String.class) ); var c1 = TypeSugar.resolve(Map.class, List.class, List.class, Long[].class, String.class); log.info("type c1={}", c1); var c2 = TypeDescriptor.map(Map.class, - TypeDescriptor.collection(List.class, - TypeDescriptor.collection(List.class, TypeDescriptor.valueOf(Long[].class)) - ), - TypeDescriptor.valueOf(String.class) + TypeDescriptor.collection(List.class, + TypeDescriptor.collection(List.class, TypeDescriptor.valueOf(Long[].class)) + ), + TypeDescriptor.valueOf(String.class) ); var c3 = TypeSugar.describe(Map.class, List.class, List.class, Long[].class, String.class); @@ -117,7 +120,7 @@ void test() throws ClassNotFoundException { testStructs(b0); testStructs(c0); testStructs(d0); - testStructs(TypeSugar.resolve(R.class, TestMergingProp.Pojo.class)); + testStructs(TypeSugar.resolve(R.class, Inner.class)); testStructs(TypeSugar.resolve(R.class)); testStructs(TypeSugar.resolve(List.class)); testStructs(TypeSugar.resolve(Map.class)); diff --git a/wings/slardar-webmvc/src/main/java/pro/fessional/wings/slardar/servlet/cookie/impl/WingsCookieInterceptorImpl.java b/wings/slardar-webmvc/src/main/java/pro/fessional/wings/slardar/servlet/cookie/impl/WingsCookieInterceptorImpl.java index e79353b5a..f8055379d 100644 --- a/wings/slardar-webmvc/src/main/java/pro/fessional/wings/slardar/servlet/cookie/impl/WingsCookieInterceptorImpl.java +++ b/wings/slardar-webmvc/src/main/java/pro/fessional/wings/slardar/servlet/cookie/impl/WingsCookieInterceptorImpl.java @@ -17,7 +17,7 @@ import java.util.Map; import java.util.Set; -import static pro.fessional.wings.silencer.spring.help.CommonPropHelper.notValue; +import static pro.fessional.wings.silencer.support.PropHelper.nonValue; /** * Designed for non-runtime tuning, so no write protection is provided. @@ -205,7 +205,7 @@ public void addAlias(Map alias) { for (Map.Entry en : alias.entrySet()) { final String k = en.getKey(); final String v = en.getValue(); - if (k.equals(v) || notValue(v)) { + if (k.equals(v) || nonValue(v)) { continue; } aliasEnc.put(k, v); diff --git a/wings/slardar-webmvc/src/main/java/pro/fessional/wings/slardar/spring/bean/SlardarRemoteConfiguration.java b/wings/slardar-webmvc/src/main/java/pro/fessional/wings/slardar/spring/bean/SlardarRemoteConfiguration.java index 34a85889b..01e3c08b1 100644 --- a/wings/slardar-webmvc/src/main/java/pro/fessional/wings/slardar/spring/bean/SlardarRemoteConfiguration.java +++ b/wings/slardar-webmvc/src/main/java/pro/fessional/wings/slardar/spring/bean/SlardarRemoteConfiguration.java @@ -5,7 +5,7 @@ import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import pro.fessional.wings.silencer.spring.boot.ConditionalWingsEnabled; -import pro.fessional.wings.silencer.spring.help.CommonPropHelper; +import pro.fessional.wings.silencer.support.PropHelper; import pro.fessional.wings.slardar.servlet.resolver.WingsRemoteResolver; import pro.fessional.wings.slardar.spring.prop.SlardarRemoteProp; @@ -24,9 +24,9 @@ public class SlardarRemoteConfiguration { public WingsRemoteResolver wingsRemoteResolver(SlardarRemoteProp conf) { log.info("SlardarWebmvc spring-bean wingsRemoteResolver"); final WingsRemoteResolver resolver = new WingsRemoteResolver(); - resolver.addInnerIp(CommonPropHelper.onlyValue(conf.getInnerIp().values())); - resolver.addAgentHeader(CommonPropHelper.onlyValue(conf.getAgentHeader().values())); - resolver.addIpHeader(CommonPropHelper.onlyValue(conf.getIpHeader().values())); + resolver.addInnerIp(PropHelper.onlyValue(conf.getInnerIp().values())); + resolver.addAgentHeader(PropHelper.onlyValue(conf.getAgentHeader().values())); + resolver.addIpHeader(PropHelper.onlyValue(conf.getIpHeader().values())); return resolver; } } diff --git a/wings/slardar-webmvc/src/main/java/pro/fessional/wings/slardar/spring/bean/SlardarSwaggerConfiguration.java b/wings/slardar-webmvc/src/main/java/pro/fessional/wings/slardar/spring/bean/SlardarSwaggerConfiguration.java index d98be1e5c..becc13061 100644 --- a/wings/slardar-webmvc/src/main/java/pro/fessional/wings/slardar/spring/bean/SlardarSwaggerConfiguration.java +++ b/wings/slardar-webmvc/src/main/java/pro/fessional/wings/slardar/spring/bean/SlardarSwaggerConfiguration.java @@ -20,7 +20,7 @@ import org.springframework.context.annotation.Configuration; import pro.fessional.mirana.page.PageQuery; import pro.fessional.wings.silencer.spring.boot.ConditionalWingsEnabled; -import pro.fessional.wings.silencer.spring.help.CommonPropHelper; +import pro.fessional.wings.silencer.support.PropHelper; import pro.fessional.wings.slardar.spring.prop.SlardarEnabledProp; import pro.fessional.wings.slardar.spring.prop.SlardarPagequeryProp; import pro.fessional.wings.slardar.spring.prop.SlardarSwaggerProp; @@ -62,7 +62,7 @@ public OpenApiCustomizer slardarOpenApiCustomizer(SlardarSwaggerProp slardarSwag } final Map params = slardarSwaggerProp.toComPara(); - final Map accepts = CommonPropHelper.onlyValue(slardarSwaggerProp.getAccept()); + final Map accepts = PropHelper.onlyValue(slardarSwaggerProp.getAccept()); if (params.isEmpty() && accepts.isEmpty()) return; openApi.getPaths().values() diff --git a/wings/slardar-webmvc/src/test/java/pro/fessional/wings/slardar/json/WingsJacksonMapperTest.java b/wings/slardar-webmvc/src/test/java/pro/fessional/wings/slardar/json/WingsJacksonMapperTest.java index e77e854d5..19a67bdd4 100644 --- a/wings/slardar-webmvc/src/test/java/pro/fessional/wings/slardar/json/WingsJacksonMapperTest.java +++ b/wings/slardar-webmvc/src/test/java/pro/fessional/wings/slardar/json/WingsJacksonMapperTest.java @@ -58,7 +58,7 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertTrue; -import static pro.fessional.wings.silencer.spring.help.CommonPropHelper.MaskingValue; +import static pro.fessional.wings.silencer.support.PropHelper.MaskingValue; import static pro.fessional.wings.slardar.context.TerminalAttribute.TerminalAddr; import static pro.fessional.wings.slardar.context.TerminalAttribute.TerminalAgent; diff --git a/wings/slardar/src/main/java/pro/fessional/wings/slardar/fastjson/FastJsonHelper.java b/wings/slardar/src/main/java/pro/fessional/wings/slardar/fastjson/FastJsonHelper.java index d390553ea..d40705121 100644 --- a/wings/slardar/src/main/java/pro/fessional/wings/slardar/fastjson/FastJsonHelper.java +++ b/wings/slardar/src/main/java/pro/fessional/wings/slardar/fastjson/FastJsonHelper.java @@ -11,7 +11,7 @@ import org.springframework.core.ResolvableType; import org.springframework.core.convert.TypeDescriptor; import pro.fessional.mirana.lock.ArrayKey; -import pro.fessional.wings.silencer.enhance.TypeSugar; +import pro.fessional.wings.silencer.support.TypeSugar; import java.io.InputStream; import java.lang.reflect.Type; diff --git a/wings/slardar/src/main/java/pro/fessional/wings/slardar/jackson/AesStringDeserializer.java b/wings/slardar/src/main/java/pro/fessional/wings/slardar/jackson/AesStringDeserializer.java index 31f59460a..ea7fc78b9 100644 --- a/wings/slardar/src/main/java/pro/fessional/wings/slardar/jackson/AesStringDeserializer.java +++ b/wings/slardar/src/main/java/pro/fessional/wings/slardar/jackson/AesStringDeserializer.java @@ -15,7 +15,7 @@ import java.io.IOException; -import static pro.fessional.wings.silencer.spring.help.CommonPropHelper.MaskingValue; +import static pro.fessional.wings.silencer.support.PropHelper.MaskingValue; /** * @author trydofor diff --git a/wings/slardar/src/main/java/pro/fessional/wings/slardar/jackson/AesStringSerializer.java b/wings/slardar/src/main/java/pro/fessional/wings/slardar/jackson/AesStringSerializer.java index 4c117f744..817efcf0d 100644 --- a/wings/slardar/src/main/java/pro/fessional/wings/slardar/jackson/AesStringSerializer.java +++ b/wings/slardar/src/main/java/pro/fessional/wings/slardar/jackson/AesStringSerializer.java @@ -14,7 +14,7 @@ import java.io.IOException; -import static pro.fessional.wings.silencer.spring.help.CommonPropHelper.MaskingValue; +import static pro.fessional.wings.silencer.support.PropHelper.MaskingValue; /** diff --git a/wings/slardar/src/main/java/pro/fessional/wings/slardar/jackson/JacksonHelper.java b/wings/slardar/src/main/java/pro/fessional/wings/slardar/jackson/JacksonHelper.java index b226579a2..97dc507cb 100644 --- a/wings/slardar/src/main/java/pro/fessional/wings/slardar/jackson/JacksonHelper.java +++ b/wings/slardar/src/main/java/pro/fessional/wings/slardar/jackson/JacksonHelper.java @@ -16,7 +16,7 @@ import pro.fessional.mirana.text.WhiteUtil; import pro.fessional.mirana.time.DateFormatter; import pro.fessional.wings.silencer.datetime.DateTimePattern; -import pro.fessional.wings.silencer.enhance.TypeSugar; +import pro.fessional.wings.silencer.support.TypeSugar; import pro.fessional.wings.slardar.autozone.AutoZoneType; import pro.fessional.wings.slardar.autozone.json.JacksonLocalDateTimeDeserializer; import pro.fessional.wings.slardar.autozone.json.JacksonLocalDateTimeSerializer; diff --git a/wings/slardar/src/main/java/pro/fessional/wings/slardar/jackson/ResourceSerializer.java b/wings/slardar/src/main/java/pro/fessional/wings/slardar/jackson/ResourceSerializer.java index 8bbf9ff4a..606020035 100644 --- a/wings/slardar/src/main/java/pro/fessional/wings/slardar/jackson/ResourceSerializer.java +++ b/wings/slardar/src/main/java/pro/fessional/wings/slardar/jackson/ResourceSerializer.java @@ -4,7 +4,7 @@ import com.fasterxml.jackson.databind.JsonSerializer; import com.fasterxml.jackson.databind.SerializerProvider; import org.springframework.core.io.Resource; -import pro.fessional.wings.silencer.spring.help.CommonPropHelper; +import pro.fessional.wings.silencer.support.PropHelper; import java.io.IOException; @@ -15,7 +15,7 @@ public class ResourceSerializer extends JsonSerializer { @Override public void serialize(Resource value, JsonGenerator gen, SerializerProvider serializers) throws IOException { - final String res = CommonPropHelper.toString(value); + final String res = PropHelper.stringResource(value); gen.writeString(res); } } diff --git a/wings/slardar/src/main/java/pro/fessional/wings/slardar/notice/DingTalkConf.java b/wings/slardar/src/main/java/pro/fessional/wings/slardar/notice/DingTalkConf.java index c8ad2d86e..f475e0702 100644 --- a/wings/slardar/src/main/java/pro/fessional/wings/slardar/notice/DingTalkConf.java +++ b/wings/slardar/src/main/java/pro/fessional/wings/slardar/notice/DingTalkConf.java @@ -9,8 +9,8 @@ import java.util.HashMap; import java.util.Map; -import static pro.fessional.wings.silencer.spring.help.CommonPropHelper.mergeNotValue; -import static pro.fessional.wings.silencer.spring.help.CommonPropHelper.notValue; +import static pro.fessional.wings.silencer.support.PropHelper.mergeIfNon; +import static pro.fessional.wings.silencer.support.PropHelper.nonValue; /** * @author trydofor @@ -95,12 +95,12 @@ public void merge(DingTalkConf that) { if (that == null) return; if (dryrun == null) dryrun = that.dryrun; - if (notValue(webhookUrl)) webhookUrl = that.webhookUrl; - if (notValue(digestSecret)) digestSecret = that.digestSecret; - if (notValue(accessToken)) accessToken = that.accessToken; - if (notValue(noticeKeyword)) noticeKeyword = that.noticeKeyword; - if (notValue(msgType)) msgType = that.msgType; - mergeNotValue(noticeMobiles, that.noticeMobiles); + if (nonValue(webhookUrl)) webhookUrl = that.webhookUrl; + if (nonValue(digestSecret)) digestSecret = that.digestSecret; + if (nonValue(accessToken)) accessToken = that.accessToken; + if (nonValue(noticeKeyword)) noticeKeyword = that.noticeKeyword; + if (nonValue(msgType)) msgType = that.msgType; + mergeIfNon(noticeMobiles, that.noticeMobiles); } public interface Loader { diff --git a/wings/slardar/src/main/java/pro/fessional/wings/slardar/spring/bean/SlardarMonitorConfiguration.java b/wings/slardar/src/main/java/pro/fessional/wings/slardar/spring/bean/SlardarMonitorConfiguration.java index 21a8024e5..54e1aa9f3 100644 --- a/wings/slardar/src/main/java/pro/fessional/wings/slardar/spring/bean/SlardarMonitorConfiguration.java +++ b/wings/slardar/src/main/java/pro/fessional/wings/slardar/spring/bean/SlardarMonitorConfiguration.java @@ -27,9 +27,9 @@ import java.io.File; import java.util.Map; -import static pro.fessional.wings.silencer.spring.help.VersionInfoHelper.branch; -import static pro.fessional.wings.silencer.spring.help.VersionInfoHelper.buildDate; -import static pro.fessional.wings.silencer.spring.help.VersionInfoHelper.commitIdShort; +import static pro.fessional.wings.silencer.support.InspectHelper.branch; +import static pro.fessional.wings.silencer.support.InspectHelper.buildDate; +import static pro.fessional.wings.silencer.support.InspectHelper.commitIdShort; /** * @author trydofor diff --git a/wings/slardar/src/test/java/pro/fessional/wings/slardar/json/TypeReferenceTest.java b/wings/slardar/src/test/java/pro/fessional/wings/slardar/json/TypeReferenceTest.java index 188430efd..b6237da34 100644 --- a/wings/slardar/src/test/java/pro/fessional/wings/slardar/json/TypeReferenceTest.java +++ b/wings/slardar/src/test/java/pro/fessional/wings/slardar/json/TypeReferenceTest.java @@ -9,7 +9,7 @@ import org.junit.jupiter.api.Test; import org.springframework.core.ResolvableType; import org.springframework.core.convert.TypeDescriptor; -import pro.fessional.wings.silencer.enhance.TypeSugar; +import pro.fessional.wings.silencer.support.TypeSugar; import java.lang.reflect.Type; import java.util.List; diff --git a/wings/warlock-shadow/src/main/java/pro/fessional/wings/warlock/security/justauth/AuthStateBuilder.java b/wings/warlock-shadow/src/main/java/pro/fessional/wings/warlock/security/justauth/AuthStateBuilder.java index 0eb40daea..a1bc2f868 100644 --- a/wings/warlock-shadow/src/main/java/pro/fessional/wings/warlock/security/justauth/AuthStateBuilder.java +++ b/wings/warlock-shadow/src/main/java/pro/fessional/wings/warlock/security/justauth/AuthStateBuilder.java @@ -11,7 +11,7 @@ import pro.fessional.mirana.code.RandCode; import pro.fessional.mirana.data.Null; import pro.fessional.mirana.text.FormatUtil; -import pro.fessional.wings.silencer.enhance.TypeSugar; +import pro.fessional.wings.silencer.support.TypeSugar; import pro.fessional.wings.slardar.fastjson.FastJsonHelper; import pro.fessional.wings.slardar.security.WingsAuthHelper; import pro.fessional.wings.slardar.servlet.request.RequestHelper; diff --git a/wings/warlock-shadow/src/main/java/pro/fessional/wings/warlock/spring/bean/WarlockSecurityBeanConfiguration.java b/wings/warlock-shadow/src/main/java/pro/fessional/wings/warlock/spring/bean/WarlockSecurityBeanConfiguration.java index 8364792b9..332dbf1c6 100644 --- a/wings/warlock-shadow/src/main/java/pro/fessional/wings/warlock/spring/bean/WarlockSecurityBeanConfiguration.java +++ b/wings/warlock-shadow/src/main/java/pro/fessional/wings/warlock/spring/bean/WarlockSecurityBeanConfiguration.java @@ -18,7 +18,7 @@ import pro.fessional.mirana.bits.Aes; import pro.fessional.wings.silencer.spring.WingsOrdered; import pro.fessional.wings.silencer.spring.boot.ConditionalWingsEnabled; -import pro.fessional.wings.silencer.spring.help.CommonPropHelper; +import pro.fessional.wings.silencer.support.PropHelper; import pro.fessional.wings.slardar.cache.WingsCache; import pro.fessional.wings.slardar.security.WingsAuthDetailsSource; import pro.fessional.wings.slardar.security.WingsAuthPageHandler; @@ -393,7 +393,7 @@ public WingsAuthDetailsSource wingsAuthDetailsSource(ObjectProvider aesProvider) { log.info("WarlockShadow spring-bean authStateBuilder"); - final AuthStateBuilder bean = new AuthStateBuilder(CommonPropHelper.onlyValue(prop.getSafeState())); + final AuthStateBuilder bean = new AuthStateBuilder(PropHelper.onlyValue(prop.getSafeState())); final Aes aes = aesProvider.getIfAvailable(); if (aes != null) { bean.setAes(aes); diff --git a/wings/warlock-shadow/src/main/java/pro/fessional/wings/warlock/spring/bean/WarlockSecurityConfConfiguration.java b/wings/warlock-shadow/src/main/java/pro/fessional/wings/warlock/spring/bean/WarlockSecurityConfConfiguration.java index 566061ca1..aa3122363 100644 --- a/wings/warlock-shadow/src/main/java/pro/fessional/wings/warlock/spring/bean/WarlockSecurityConfConfiguration.java +++ b/wings/warlock-shadow/src/main/java/pro/fessional/wings/warlock/spring/bean/WarlockSecurityConfConfiguration.java @@ -29,7 +29,7 @@ import pro.fessional.wings.silencer.runner.ApplicationRunnerOrdered; import pro.fessional.wings.silencer.spring.WingsOrdered; import pro.fessional.wings.silencer.spring.boot.ConditionalWingsEnabled; -import pro.fessional.wings.silencer.spring.help.CommonPropHelper; +import pro.fessional.wings.silencer.support.PropHelper; import pro.fessional.wings.slardar.security.WingsAuthDetailsSource; import pro.fessional.wings.slardar.servlet.request.FakeHttpServletRequest; import pro.fessional.wings.slardar.servlet.response.ResponseHelper; @@ -72,7 +72,7 @@ public WebSecurityCustomizer warlockWebCustomizer(WarlockSecurityProp securityPr // https://github.com/spring-projects/spring-security/issues/10938 final Map webIgnore = securityProp.getWebIgnore(); if (!webIgnore.isEmpty()) { - final Set ignores = CommonPropHelper.onlyValue(webIgnore.values()); + final Set ignores = PropHelper.onlyValue(webIgnore.values()); log.info("WarlockShadow conf WebSecurity, ignoring=" + String.join("\n,", ignores)); web.ignoring().requestMatchers(ignores.toArray(String[]::new)); } @@ -168,14 +168,14 @@ public HttpSecurityCustomizer warlockSecurityAuthHttpConfigure(WarlockSecurityPr return http -> http.authorizeHttpRequests(conf -> { // 1 PermitAll - final Set permed = CommonPropHelper.onlyValue(securityProp.getPermitAll().values()); + final Set permed = PropHelper.onlyValue(securityProp.getPermitAll().values()); if (!permed.isEmpty()) { log.info("WarlockShadow conf HttpSecurity, bind PermitAll=" + String.join("\n,", permed)); conf.requestMatchers(permed.toArray(String[]::new)).permitAll(); } // 2 Authenticated - final Set authed = CommonPropHelper.onlyValue(securityProp.getAuthenticated().values()); + final Set authed = PropHelper.onlyValue(securityProp.getAuthenticated().values()); if (!authed.isEmpty()) { log.info("WarlockShadow conf HttpSecurity, bind Authenticated=" + String.join("\n,", authed)); conf.requestMatchers(authed.toArray(String[]::new)).authenticated(); @@ -188,7 +188,7 @@ public HttpSecurityCustomizer warlockSecurityAuthHttpConfigure(WarlockSecurityPr for (Map.Entry> en : securityProp.getAuthority().entrySet()) { final String perm = en.getKey(); for (String url : en.getValue()) { - if (CommonPropHelper.hasValue(url)) { + if (PropHelper.hasValue(url)) { final Set st = urlPerm.computeIfAbsent(url, k -> new HashSet<>()); st.add(perm); } @@ -197,7 +197,7 @@ public HttpSecurityCustomizer warlockSecurityAuthHttpConfigure(WarlockSecurityPr // desc for (Map.Entry> en : urlPerm.descendingMap().entrySet()) { final String url = en.getKey(); - final Set pms = CommonPropHelper.onlyValue(en.getValue()); + final Set pms = PropHelper.onlyValue(en.getValue()); log.info("WarlockShadow conf HttpSecurity, bind url=" + url + ", any-permit=[" + String.join(",", pms) + "]"); conf.requestMatchers(url).hasAnyAuthority(pms.toArray(Null.StrArr)); } diff --git a/wings/warlock-shadow/src/main/java/pro/fessional/wings/warlock/spring/prop/WarlockSecurityProp.java b/wings/warlock-shadow/src/main/java/pro/fessional/wings/warlock/spring/prop/WarlockSecurityProp.java index b77437f16..a342c29be 100644 --- a/wings/warlock-shadow/src/main/java/pro/fessional/wings/warlock/spring/prop/WarlockSecurityProp.java +++ b/wings/warlock-shadow/src/main/java/pro/fessional/wings/warlock/spring/prop/WarlockSecurityProp.java @@ -2,7 +2,7 @@ import lombok.Data; import org.springframework.boot.context.properties.ConfigurationProperties; -import pro.fessional.wings.silencer.spring.help.CommonPropHelper; +import pro.fessional.wings.silencer.support.PropHelper; import pro.fessional.wings.slardar.context.TerminalContext; import pro.fessional.wings.warlock.enums.autogen.UserStatus; @@ -386,7 +386,7 @@ public Enum mapAuthTypeDefault() { public Map> mapAuthTypeEnum() { return authType.entrySet() .stream() - .filter(it -> CommonPropHelper.hasValue(it.getValue())) + .filter(it -> PropHelper.hasValue(it.getValue())) .collect(toMap(Map.Entry::getKey, en -> str2Enum(en.getValue()))); } diff --git a/wings/warlock/src/main/java/pro/fessional/wings/warlock/service/conf/RuntimeConfService.java b/wings/warlock/src/main/java/pro/fessional/wings/warlock/service/conf/RuntimeConfService.java index e3fa345a3..4b779111f 100644 --- a/wings/warlock/src/main/java/pro/fessional/wings/warlock/service/conf/RuntimeConfService.java +++ b/wings/warlock/src/main/java/pro/fessional/wings/warlock/service/conf/RuntimeConfService.java @@ -4,7 +4,7 @@ import org.springframework.core.ResolvableType; import org.springframework.core.convert.TypeDescriptor; import pro.fessional.mirana.cast.EnumConvertor; -import pro.fessional.wings.silencer.enhance.TypeSugar; +import pro.fessional.wings.silencer.support.TypeSugar; import java.util.List; import java.util.Map; diff --git a/wings/warlock/src/main/java/pro/fessional/wings/warlock/service/conf/impl/RuntimeConfServiceImpl.java b/wings/warlock/src/main/java/pro/fessional/wings/warlock/service/conf/impl/RuntimeConfServiceImpl.java index 9c63b6926..a41e231a4 100644 --- a/wings/warlock/src/main/java/pro/fessional/wings/warlock/service/conf/impl/RuntimeConfServiceImpl.java +++ b/wings/warlock/src/main/java/pro/fessional/wings/warlock/service/conf/impl/RuntimeConfServiceImpl.java @@ -18,7 +18,7 @@ import pro.fessional.wings.faceless.database.WingsTableCudHandler; import pro.fessional.wings.faceless.database.WingsTableCudHandler.Cud; import pro.fessional.wings.silencer.enhance.ThisLazy; -import pro.fessional.wings.silencer.enhance.TypeSugar; +import pro.fessional.wings.silencer.support.TypeSugar; import pro.fessional.wings.warlock.caching.CacheEventHelper; import pro.fessional.wings.warlock.database.autogen.tables.WinConfRuntimeTable; import pro.fessional.wings.warlock.database.autogen.tables.daos.WinConfRuntimeDao; diff --git a/wings/warlock/src/test/java/pro/fessional/wings/warlock/service/conf/RuntimeConfServiceTest.java b/wings/warlock/src/test/java/pro/fessional/wings/warlock/service/conf/RuntimeConfServiceTest.java index 3815e7be1..19b3d0016 100644 --- a/wings/warlock/src/test/java/pro/fessional/wings/warlock/service/conf/RuntimeConfServiceTest.java +++ b/wings/warlock/src/test/java/pro/fessional/wings/warlock/service/conf/RuntimeConfServiceTest.java @@ -11,7 +11,7 @@ import org.springframework.cache.CacheManager; import org.springframework.context.ApplicationContext; import pro.fessional.mirana.time.Sleep; -import pro.fessional.wings.silencer.enhance.TypeSugar; +import pro.fessional.wings.silencer.support.TypeSugar; import pro.fessional.wings.silencer.modulate.RunMode; import pro.fessional.wings.slardar.cache.SimpleCacheTemplate; import pro.fessional.wings.slardar.cache.WingsCacheHelper; From ccb70bce6cf889a4ca38cd40343efaccc9691bbd Mon Sep 17 00:00:00 2001 From: trydofor Date: Tue, 2 Jul 2024 10:37:18 +0800 Subject: [PATCH 11/51] =?UTF-8?q?=F0=9F=8E=A8=20tiny-mail=20IfSetter=20sug?= =?UTF-8?q?ar?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- observe/docs | 2 +- observe/mirana | 2 +- .../tiny/mail/sender/MailConfigProvider.java | 4 +- .../wings/tiny/mail/sender/MailNotice.java | 2 +- .../tiny/mail/sender/TinyMailConfig.java | 122 +++++++----------- .../tiny/mail/sender/TinyMailMessage.java | 52 ++++---- .../wings/tiny/mail/service/TinyMail.java | 11 +- .../tiny/mail/service/TinyMailPlain.java | 2 +- .../service/impl/TinyMailServiceImpl.java | 41 +++--- .../mail/sender/MailSenderManagerTest.java | 14 +- .../flywave/impl/DefaultRevisionManager.kt | 6 +- .../wings/silencer/support/PropHelper.java | 89 +++++++------ .../impl/WingsCookieInterceptorImpl.java | 4 +- .../bean/SlardarRemoteConfiguration.java | 6 +- .../bean/SlardarSwaggerConfiguration.java | 2 +- .../wings/slardar/notice/DingTalkConf.java | 57 ++++---- .../wings/slardar/notice/DingTalkNotice.java | 4 +- .../WarlockSecurityBeanConfiguration.java | 2 +- .../WarlockSecurityConfConfiguration.java | 10 +- .../spring/prop/WarlockSecurityProp.java | 2 +- 20 files changed, 203 insertions(+), 231 deletions(-) diff --git a/observe/docs b/observe/docs index e1df9bdee..9f703e514 160000 --- a/observe/docs +++ b/observe/docs @@ -1 +1 @@ -Subproject commit e1df9bdeefc83fdf5720de4b6bcf6b1ca075ae3d +Subproject commit 9f703e5147c23ea2840ac75233f83edad6739eb3 diff --git a/observe/mirana b/observe/mirana index 699fc3723..48abc9b94 160000 --- a/observe/mirana +++ b/observe/mirana @@ -1 +1 @@ -Subproject commit 699fc372399272fb68014c27028013841f1f83d6 +Subproject commit 48abc9b9441629850ef73730f875de739b913eb2 diff --git a/radiant/tiny-mail/src/main/java/pro/fessional/wings/tiny/mail/sender/MailConfigProvider.java b/radiant/tiny-mail/src/main/java/pro/fessional/wings/tiny/mail/sender/MailConfigProvider.java index c7e3a4e1a..6571db80f 100644 --- a/radiant/tiny-mail/src/main/java/pro/fessional/wings/tiny/mail/sender/MailConfigProvider.java +++ b/radiant/tiny-mail/src/main/java/pro/fessional/wings/tiny/mail/sender/MailConfigProvider.java @@ -54,8 +54,8 @@ public TinyMailConfig bynamedConfig(String name) { @Contract("_->new") public TinyMailConfig combineConfig(@Nullable TinyMailConfig that) { final TinyMailConfig newConf = new TinyMailConfig(); - newConf.adopt(that); - newConf.merge(configProp.getDefault()); + TinyMailConfig.ConfSetter.toAny(newConf, that); + TinyMailConfig.ConfSetter.toInvalid(newConf, configProp.getDefault()); return newConf; } } diff --git a/radiant/tiny-mail/src/main/java/pro/fessional/wings/tiny/mail/sender/MailNotice.java b/radiant/tiny-mail/src/main/java/pro/fessional/wings/tiny/mail/sender/MailNotice.java index 0cdff99a5..8828ce9cf 100644 --- a/radiant/tiny-mail/src/main/java/pro/fessional/wings/tiny/mail/sender/MailNotice.java +++ b/radiant/tiny-mail/src/main/java/pro/fessional/wings/tiny/mail/sender/MailNotice.java @@ -64,7 +64,7 @@ public TinyMailConfig provideConfig(@Nullable String name, boolean combine) { @Override public boolean send(TinyMailConfig config, String subject, String content) { TinyMailMessage message = new TinyMailMessage(); - message.adopt(config); + TinyMailConfig.ConfSetter.toAny(message, config); message.setSubject(subject); message.setContent(content); senderManager.singleSend(message); diff --git a/radiant/tiny-mail/src/main/java/pro/fessional/wings/tiny/mail/sender/TinyMailConfig.java b/radiant/tiny-mail/src/main/java/pro/fessional/wings/tiny/mail/sender/TinyMailConfig.java index aa3e5afec..023a812eb 100644 --- a/radiant/tiny-mail/src/main/java/pro/fessional/wings/tiny/mail/sender/TinyMailConfig.java +++ b/radiant/tiny-mail/src/main/java/pro/fessional/wings/tiny/mail/sender/TinyMailConfig.java @@ -5,12 +5,13 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.springframework.boot.autoconfigure.mail.MailProperties; +import pro.fessional.mirana.cond.IfSetter; import java.util.Arrays; import java.util.Objects; -import static pro.fessional.wings.silencer.support.PropHelper.mergeIfNon; -import static pro.fessional.wings.silencer.support.PropHelper.nonValue; +import static pro.fessional.wings.silencer.support.PropHelper.invalid; +import static pro.fessional.wings.silencer.support.PropHelper.mergeToInvalid; /** * hashCode and equals with @@ -101,82 +102,59 @@ public int hashCode() { return result; } - /** - * use all properties from that - */ - public void adopt(MailProperties that) { - if (that == null) return; - setHost(that.getHost()); - setPort(that.getPort()); - setUsername(that.getUsername()); - setPassword(that.getPassword()); - setProtocol(that.getProtocol()); - setDefaultEncoding(that.getDefaultEncoding()); - getProperties().putAll(that.getProperties()); - } + public static final IfSetter PropSetter = (thiz, that, absent, present) -> { + if (that == null) return thiz; + + if (absent == IfSetter.Absent.Invalid) { + if (invalid(thiz.getHost())) thiz.setHost(that.getHost()); + if (thiz.getPort() == null) thiz.setPort(that.getPort()); + if (invalid(thiz.getUsername())) thiz.setUsername(that.getUsername()); + if (invalid(thiz.getPassword())) thiz.setPassword(that.getPassword()); + if (invalid(thiz.getProtocol())) thiz.setProtocol(that.getProtocol()); + if (thiz.getDefaultEncoding() == null) thiz.setDefaultEncoding(that.getDefaultEncoding()); + mergeToInvalid(thiz.getProperties(), that.getProperties()); + } + else { + thiz.setHost(that.getHost()); + thiz.setPort(that.getPort()); + thiz.setUsername(that.getUsername()); + thiz.setPassword(that.getPassword()); + thiz.setProtocol(that.getProtocol()); + thiz.setDefaultEncoding(that.getDefaultEncoding()); + thiz.getProperties().putAll(that.getProperties()); + } - /** - * use all properties from that - */ - public void adopt(TinyMailConfig that) { - if (that == null) return; - adopt((MailProperties) that); - dryrun = that.dryrun; - name = that.name; - from = that.from; - to = that.to; - cc = that.cc; - bcc = that.bcc; - reply = that.reply; - html = that.html; - } + return thiz; + }; - /** - * if this.property is invalid, then use that.property. - * except for 'properties' which merge value only if key matches. - */ - public void merge(MailProperties that) { - if (that == null) return; + public static final IfSetter ConfSetter = (thiz, that, absent, present) -> { + if (that == null) return thiz; - if (nonValue(getHost())) { - setHost(that.getHost()); - } - if (getPort() == null) { - setPort(that.getPort()); - } - if (nonValue(getUsername())) { - setUsername(that.getUsername()); - } - final String password = getPassword(); - if (nonValue(password)) { - setPassword(that.getPassword()); - } - if (nonValue(getProtocol())) { - setProtocol(that.getProtocol()); + PropSetter.set(thiz, that, absent, present); + + if (absent == IfSetter.Absent.Invalid) { + if (thiz.dryrun == null) thiz.dryrun = that.dryrun; + if (invalid(thiz.name)) thiz.name = that.name; + if (invalid(thiz.from)) thiz.from = that.from; + if (thiz.to == null) thiz.to = that.to; + if (thiz.cc == null) thiz.cc = that.cc; + if (thiz.bcc == null) thiz.bcc = that.bcc; + if (invalid(thiz.reply)) thiz.reply = that.reply; + if (thiz.html == null) thiz.html = that.html; } - if (getDefaultEncoding() == null) { - setDefaultEncoding(that.getDefaultEncoding()); + else { + thiz.dryrun = that.dryrun; + thiz.name = that.name; + thiz.from = that.from; + thiz.to = that.to; + thiz.cc = that.cc; + thiz.bcc = that.bcc; + thiz.reply = that.reply; + thiz.html = that.html; } - mergeIfNon(getProperties(), that.getProperties()); - } - - /** - * if this.property is invalid, then use that.property. - */ - public void merge(TinyMailConfig that) { - if (that == null) return; - merge((MailProperties) that); - - if (dryrun == null) dryrun = that.dryrun; - if (nonValue(name)) name = that.name; - if (nonValue(from)) from = that.from; - if (to == null) to = that.to; - if (cc == null) cc = that.cc; - if (bcc == null) bcc = that.bcc; - if (nonValue(reply)) reply = that.reply; - if (html == null) html = that.html; - } + return thiz; + }; public interface Loader { /** diff --git a/radiant/tiny-mail/src/main/java/pro/fessional/wings/tiny/mail/sender/TinyMailMessage.java b/radiant/tiny-mail/src/main/java/pro/fessional/wings/tiny/mail/sender/TinyMailMessage.java index 7ec90bf13..be06f2fc9 100644 --- a/radiant/tiny-mail/src/main/java/pro/fessional/wings/tiny/mail/sender/TinyMailMessage.java +++ b/radiant/tiny-mail/src/main/java/pro/fessional/wings/tiny/mail/sender/TinyMailMessage.java @@ -3,6 +3,7 @@ import lombok.Data; import lombok.EqualsAndHashCode; import org.springframework.core.io.Resource; +import pro.fessional.mirana.cond.IfSetter; import pro.fessional.mirana.text.WhiteUtil; import java.util.Collections; @@ -60,33 +61,6 @@ public String toMainString() { return sb.toString(); } - /** - * Use all `that` values - */ - public void adopt(TinyMailMessage that) { - if (that == null) return; - super.adopt(that); - bizId = that.bizId; - bizMark = that.bizMark; - subject = that.subject; - content = that.content; - attachment = that.attachment; - } - - /** - * Use `that` value if `this` is invalid - */ - public void merge(TinyMailMessage that) { - if (that == null) return; - super.merge(that); - - if (bizId == null) bizId = that.bizId; - if (bizMark == null) bizMark = that.bizMark; - if (isEmpty(subject)) subject = that.subject; - if (isEmpty(content)) content = that.content; - if (attachment == null) attachment = that.attachment; - } - public boolean asHtml() { if (html != null) return html; return asHtml(content, true); @@ -104,4 +78,28 @@ public static boolean asHtml(String str, boolean elze) { return elze; } + + public static final IfSetter MessageSetter = (thiz, that, absent, present) -> { + if (that == null) return thiz; + + TinyMailConfig.ConfSetter.set(thiz,that,absent, present); + + if (absent == IfSetter.Absent.Invalid) { + if (thiz.bizId == null) thiz.bizId = that.bizId; + if (thiz.bizMark == null) thiz.bizMark = that.bizMark; + if (isEmpty(thiz.subject)) thiz.subject = that.subject; + if (isEmpty(thiz.content)) thiz.content = that.content; + if (thiz.attachment == null) thiz.attachment = that.attachment; + } + else { + thiz.bizId = that.bizId; + thiz.bizMark = that.bizMark; + thiz.subject = that.subject; + thiz.content = that.content; + thiz.attachment = that.attachment; + } + + return thiz; + }; + } diff --git a/radiant/tiny-mail/src/main/java/pro/fessional/wings/tiny/mail/service/TinyMail.java b/radiant/tiny-mail/src/main/java/pro/fessional/wings/tiny/mail/service/TinyMail.java index 7b5d1a5bb..344c69801 100644 --- a/radiant/tiny-mail/src/main/java/pro/fessional/wings/tiny/mail/service/TinyMail.java +++ b/radiant/tiny-mail/src/main/java/pro/fessional/wings/tiny/mail/service/TinyMail.java @@ -51,11 +51,7 @@ public void setBcc(String... bcc) { * Mail reply, use default if empty */ protected String reply; - /** - * Whether to send html mail (text/html), otherwise text mail(text/plain). - * use default if null - */ - protected Boolean html; + /** * Mail subject, use default if empty */ @@ -68,6 +64,11 @@ public void setBcc(String... bcc) { * Mail attachment, use default if null */ protected Map attachment = null; + /** + * Whether to send html mail (text/html), otherwise text mail(text/plain). + * use default if null + */ + protected Boolean html; /** * Business keyword ot mark, space seperated, use default if null */ diff --git a/radiant/tiny-mail/src/main/java/pro/fessional/wings/tiny/mail/service/TinyMailPlain.java b/radiant/tiny-mail/src/main/java/pro/fessional/wings/tiny/mail/service/TinyMailPlain.java index 4e4d3196d..7b20b8b5e 100644 --- a/radiant/tiny-mail/src/main/java/pro/fessional/wings/tiny/mail/service/TinyMailPlain.java +++ b/radiant/tiny-mail/src/main/java/pro/fessional/wings/tiny/mail/service/TinyMailPlain.java @@ -86,7 +86,7 @@ public class TinyMailPlain { private String mark; /** - * Mail timed delivery time, system time zone + * Schedule to send mail, system time zone */ private LocalDateTime date; diff --git a/radiant/tiny-mail/src/main/java/pro/fessional/wings/tiny/mail/service/impl/TinyMailServiceImpl.java b/radiant/tiny-mail/src/main/java/pro/fessional/wings/tiny/mail/service/impl/TinyMailServiceImpl.java index 0e1732775..295d401cd 100644 --- a/radiant/tiny-mail/src/main/java/pro/fessional/wings/tiny/mail/service/impl/TinyMailServiceImpl.java +++ b/radiant/tiny-mail/src/main/java/pro/fessional/wings/tiny/mail/service/impl/TinyMailServiceImpl.java @@ -19,7 +19,7 @@ import org.springframework.stereotype.Service; import pro.fessional.mirana.best.AssertArgs; import pro.fessional.mirana.cast.BoxedCastUtil; -import pro.fessional.mirana.data.Null; +import pro.fessional.mirana.cond.IfSetter; import pro.fessional.mirana.pain.ThrowableUtil; import pro.fessional.mirana.time.DateLocaling; import pro.fessional.mirana.time.ThreadNow; @@ -59,7 +59,7 @@ import static org.springframework.scheduling.annotation.ScheduledAnnotationBeanPostProcessor.DEFAULT_TASK_SCHEDULER_BEAN_NAME; import static pro.fessional.wings.silencer.support.PropHelper.commaArray; -import static pro.fessional.wings.silencer.support.PropHelper.nonValue; +import static pro.fessional.wings.silencer.support.PropHelper.invalid; /** * @author trydofor @@ -192,7 +192,7 @@ public long save(@NotNull TinyMailPlain msg) { } else { id = msg.getId(); - Null.notNull(msg.getNextSend(), po::setNextSend); + IfSetter.nonnull(po::setNextSend, msg.getNextSend()); } po.setId(id); @@ -211,12 +211,12 @@ public long save(@NotNull TinyMailPlain msg) { po.setMailMark(msg.getMark()); po.setMailDate(md); - Null.notNull(msg.getMaxFail(), po::setMaxFail); - Null.notNull(msg.getMaxDone(), po::setMaxDone); + IfSetter.nonnull(po::setMaxFail, msg.getMaxFail()); + IfSetter.nonnull(po::setMaxDone, msg.getMaxDone()); - Null.notNull(msg.getRefType(), po::setRefType); - Null.notNull(msg.getRefKey1(), po::setRefKey1); - Null.notNull(msg.getRefKey2(), po::setRefKey2); + IfSetter.nonnull(po::setRefType, msg.getRefType()); + IfSetter.nonnull(po::setRefKey1, msg.getRefKey1()); + IfSetter.nonnull(po::setRefKey2, msg.getRefKey2()); // try to check message format final TinyMailMessage tms = makeMailMessage(config, po, null); @@ -247,7 +247,7 @@ public int scan() { final List pos = winMailSenderDao .ctx() .selectFrom(t) - .where(t.NextSend.gt(min).and(t.NextSend.lt(max))) + .where(t.NextSend.ge(min).and(t.NextSend.lt(max))) .fetch() .into(WinMailSender.class) .stream() @@ -275,7 +275,7 @@ public void afterPropertiesSet() { private TinyMailMessage makeMailMessage(@NotNull TinyMailConfig config, @NotNull WinMailSender po, @Nullable TinyMail msg) { final TinyMailMessage message = new TinyMailMessage(); - message.adopt(config); + TinyMailConfig.ConfSetter.toAny(message, config); message.setBizId(po.getId()); if (msg == null) { @@ -294,12 +294,11 @@ private TinyMailMessage makeMailMessage(@NotNull TinyMailConfig config, @NotNull message.setBizMark(EmptySugar.emptyToNull(po.getMailMark())); } else { - if (msg.getFrom() != null) message.setFrom(msg.getFrom()); - if (msg.getTo() != null) message.setTo(msg.getTo()); - if (msg.getCc() != null) message.setCc(msg.getCc()); - if (msg.getBcc() != null) message.setBcc(msg.getBcc()); - if (msg.getReply() != null) message.setReply(msg.getReply()); - if (msg.getHtml() != null) message.setHtml(msg.getHtml()); + IfSetter.nonnull(message::setFrom, msg.getFrom()); + IfSetter.nonnull(message::setTo, msg.getTo()); + IfSetter.nonnull(message::setCc, msg.getCc()); + IfSetter.nonnull(message::setReply, msg.getReply()); + IfSetter.nonnull(message::setHtml, msg.getHtml()); message.setSubject(msg.getSubject()); message.setContent(msg.getContent()); message.setAttachment(msg.getAttachment()); @@ -335,9 +334,9 @@ private WinMailSender saveMailSender(@NotNull TinyMailConfig config, @NotNull Ti po.setMaxFail(BoxedCastUtil.orElse(msg.getMaxFail(), tinyMailServiceProp.getMaxFail())); po.setMaxDone(BoxedCastUtil.orElse(msg.getMaxDone(), tinyMailServiceProp.getMaxDone())); - Null.notNull(msg.getRefType(), po::setRefType); - Null.notNull(msg.getRefKey1(), po::setRefKey1); - Null.notNull(msg.getRefKey2(), po::setRefKey2); + IfSetter.nonnull(po::setRefType, msg.getRefType()); + IfSetter.nonnull(po::setRefKey1, msg.getRefKey1()); + IfSetter.nonnull(po::setRefKey2, msg.getRefKey2()); // Optimist lock po.setNextLock(0); @@ -692,7 +691,7 @@ private String toString(String[] arr, String[] elz) { @Nullable private String toString(String str, String[] elz) { - return nonValue(str) + return invalid(str) ? (elz == null || elz.length == 0 ? null : String.join(",", elz)) @@ -701,7 +700,7 @@ private String toString(String str, String[] elz) { @Nullable private String toString(String str, String elz) { - return nonValue(str) ? elz : str; + return invalid(str) ? elz : str; } @Nullable diff --git a/radiant/tiny-mail/src/test/java/pro/fessional/wings/tiny/mail/sender/MailSenderManagerTest.java b/radiant/tiny-mail/src/test/java/pro/fessional/wings/tiny/mail/sender/MailSenderManagerTest.java index f56bad44e..6093b322b 100644 --- a/radiant/tiny-mail/src/test/java/pro/fessional/wings/tiny/mail/sender/MailSenderManagerTest.java +++ b/radiant/tiny-mail/src/test/java/pro/fessional/wings/tiny/mail/sender/MailSenderManagerTest.java @@ -18,17 +18,17 @@ * @since 2023-01-06 */ @SpringBootTest(properties = { - "wings.tiny.mail.service.boot-scan=0", - "logging.level.root=INFO", + "wings.tiny.mail.service.boot-scan=0", + "logging.level.root=INFO", }) @Slf4j public class MailSenderManagerTest { - @Setter(onMethod_ = {@Autowired}) + @Setter(onMethod_ = { @Autowired }) protected MailSenderManager mailSenderManager; - @Setter(onMethod_ = {@Autowired}) + @Setter(onMethod_ = { @Autowired }) protected MailConfigProvider mailConfigProvider; /** @@ -61,7 +61,7 @@ public void timeLoopAndBatch() { try (final StopWatch.Watch ignored = stopWatch.start("single")) { for (int i = 0; i < size; i++) { TinyMailMessage message = new TinyMailMessage(); - message.adopt(config); + TinyMailConfig.ConfSetter.toAny(message, config); String text = "test single tiny mail " + i; message.setSubject(TestingMailUtil.dryrun(text, dryrun)); message.setContent(text); @@ -76,7 +76,7 @@ public void timeLoopAndBatch() { List messages = new ArrayList<>(size); for (int i = 0; i < size; i++) { TinyMailMessage message = new TinyMailMessage(); - message.adopt(config); + TinyMailConfig.ConfSetter.toAny(message, config); String text = "test batch tiny mail " + i; message.setSubject(TestingMailUtil.dryrun(text, dryrun)); message.setContent(text); @@ -109,7 +109,7 @@ public void batchMailDryrun() { List messages = new ArrayList<>(); for (int i = 0; i < 2; i++) { TinyMailMessage message = new TinyMailMessage(); - message.adopt(config); + TinyMailConfig.ConfSetter.toAny(message, config); message.setSubject(TestingMailUtil.dryrun("test batch tiny mail " + i)); message.setContent("test batch tiny mail " + i); messages.add(message); diff --git a/wings/faceless-flywave/src/main/kotlin/pro/fessional/wings/faceless/flywave/impl/DefaultRevisionManager.kt b/wings/faceless-flywave/src/main/kotlin/pro/fessional/wings/faceless/flywave/impl/DefaultRevisionManager.kt index cc3ad4195..3e77999d3 100644 --- a/wings/faceless-flywave/src/main/kotlin/pro/fessional/wings/faceless/flywave/impl/DefaultRevisionManager.kt +++ b/wings/faceless-flywave/src/main/kotlin/pro/fessional/wings/faceless/flywave/impl/DefaultRevisionManager.kt @@ -154,7 +154,7 @@ class DefaultRevisionManager( // check and handle boundary if (isUptoSql) { // revision is from low to high, inconsistent and non-exist are important - if (reviText.last.first != revision) { + if (reviText.last().first != revision) { interactive.log(WARN, here, "skip the diff upgrade end point, db-revi=$plainRevi, to-revi=$revision, db=$plainName") continue } @@ -164,7 +164,7 @@ class DefaultRevisionManager( continue } } else { // revision is from high to low - if (reviText.last.first != revision) { + if (reviText.last().first != revision) { interactive.log(WARN, here, "skip the diff downgrade end point, db-revi=$plainRevi, to-revi=$revision, db=$plainName") continue } @@ -364,7 +364,7 @@ class DefaultRevisionManager( continue } - val reviSql = applySqls.first + val reviSql = applySqls.first() val notAppd = isUnapply(reviSql.second) val msgAly = applyMessage(reviSql.second) diff --git a/wings/silencer/src/main/java/pro/fessional/wings/silencer/support/PropHelper.java b/wings/silencer/src/main/java/pro/fessional/wings/silencer/support/PropHelper.java index 720d24df0..2b3e6c6dd 100644 --- a/wings/silencer/src/main/java/pro/fessional/wings/silencer/support/PropHelper.java +++ b/wings/silencer/src/main/java/pro/fessional/wings/silencer/support/PropHelper.java @@ -31,48 +31,74 @@ public class PropHelper { public static final String MaskingValue = "*****"; /** - * true if empty or DisabledValue or MaskingValue + * invalid if null/blank/DisabledValue/MaskingValue */ - public static boolean nonValue(String str) { + public static boolean invalid(String str) { return str == null || str.isBlank() || DisabledValue.equals(str) || MaskingValue.equals(str); } /** - * true if not non-value + * true if not invalid */ - public static boolean hasValue(String value) { - return !nonValue(value); + public static boolean valid(String value) { + return !invalid(value); } /** - * uniq and remove non-value + * uniq and remove invalid */ @NotNull - public static LinkedHashSet onlyValue(Collection values) { + public static LinkedHashSet onlyValid(Collection values) { if (values == null) return new LinkedHashSet<>(); - final LinkedHashSet set = new LinkedHashSet<>(values); - set.removeIf(PropHelper::nonValue); + final LinkedHashSet set = new LinkedHashSet<>(values.size()); + for (String value : values) { + if (valid(value)) set.add(value); + } + return set; } /** - * remove item that has non-value + * remain the entry if its value is valid */ @NotNull - public static LinkedHashMap onlyValue(Map values) { + public static LinkedHashMap onlyValid(Map values) { if (values == null) return new LinkedHashMap<>(); - final LinkedHashMap map = new LinkedHashMap<>(); + final LinkedHashMap map = new LinkedHashMap<>(values.size()); for (Map.Entry en : values.entrySet()) { final String value = en.getValue(); - if (!nonValue(value)) { + if (valid(value)) { map.put(en.getKey(), value); } } return map; } + /** + * if this.value is invalid, then use that.value by key + * + * @param thiz this map + * @param that that map + */ + public static void mergeToInvalid(@NotNull Map thiz, @Nullable Map that) { + if (that == null || that.isEmpty()) return; + + if (thiz.isEmpty()) { + thiz.putAll(that); + } + else { + for (Map.Entry en : thiz.entrySet()) { + final String thisVal = en.getValue(); + if (invalid(thisVal)) { + final String thatVal = that.get(en.getKey()); + en.setValue(thatVal); + } + } + } + } + /** * Use 'classpath:' format for ClassPathResource and getURL().toExternalForm() for the rest * @@ -95,29 +121,6 @@ public static Resource resourceString(String url, @NotNull ResourceLoader resour return resourceLoader.getResource(url); } - /** - * if this.value is non-value, then use that.value by key - * - * @param thiz this map - * @param that that map - */ - public static void mergeIfNon(@NotNull Map thiz, @Nullable Map that) { - if (that == null || that.isEmpty()) return; - - if (thiz.isEmpty()) { - thiz.putAll(that); - } - else { - for (Map.Entry en : thiz.entrySet()) { - final String v = en.getValue(); - if (nonValue(v)) { - final String tv = that.get(en.getKey()); - en.setValue(tv); - } - } - } - } - /** * parse comma-delimited-list string, no strip item, no drop */ @@ -168,7 +171,7 @@ public static String delimitedString(Collection items, String delimiter, bool String str = obj.toString(); if (strip) str = str.strip(); - if (!(drop && nonValue(str))) { + if (!(drop && invalid(str))) { empty = false; sb.append(delimiter).append(str); } @@ -177,7 +180,7 @@ public static String delimitedString(Collection items, String delimiter, bool } /** - * parse comma-delimited-list string, strip item, drop non-value + * parse comma-delimited-list string, strip item, drop invalid */ @NotNull public static String[] commaArray(String commaString) { @@ -185,7 +188,7 @@ public static String[] commaArray(String commaString) { } /** - * parse comma-delimited-list string, whether to strip item, whether to drop non-value + * parse comma-delimited-list string, whether to strip item, whether to drop invalid */ @NotNull public static String[] commaArray(String commaString, boolean strip, boolean drop) { @@ -194,7 +197,7 @@ public static String[] commaArray(String commaString, boolean strip, boolean dro } /** - * parse comma-delimited-list string, strip item, drop non-value + * parse comma-delimited-list string, strip item, drop invalid */ @NotNull public static List commaList(String commaString) { @@ -202,7 +205,7 @@ public static List commaList(String commaString) { } /** - * parse comma-delimited-list string, whether to strip item, whether to drop non-value + * parse comma-delimited-list string, whether to strip item, whether to drop invalid */ @NotNull public static List commaList(String commaString, boolean strip, boolean drop) { @@ -210,7 +213,7 @@ public static List commaList(String commaString, boolean strip, boolean } /** - * parse delimiter(comma if empty) delimited-list string, whether to strip item, whether to drop non-value + * parse delimiter(comma if empty) delimited-list string, whether to strip item, whether to drop invalid */ @NotNull public static List delimitedList(String delimitedString, String delimiter, boolean strip, boolean drop) { @@ -236,7 +239,7 @@ public static List delimitedList(String delimitedString, String delimite private static void addValue(List result, String str, boolean strip, boolean drop) { if (strip) str = str.strip(); - if (drop && nonValue(str)) return; + if (drop && invalid(str)) return; result.add(str); } } diff --git a/wings/slardar-webmvc/src/main/java/pro/fessional/wings/slardar/servlet/cookie/impl/WingsCookieInterceptorImpl.java b/wings/slardar-webmvc/src/main/java/pro/fessional/wings/slardar/servlet/cookie/impl/WingsCookieInterceptorImpl.java index f8055379d..e05ff9a81 100644 --- a/wings/slardar-webmvc/src/main/java/pro/fessional/wings/slardar/servlet/cookie/impl/WingsCookieInterceptorImpl.java +++ b/wings/slardar-webmvc/src/main/java/pro/fessional/wings/slardar/servlet/cookie/impl/WingsCookieInterceptorImpl.java @@ -17,7 +17,7 @@ import java.util.Map; import java.util.Set; -import static pro.fessional.wings.silencer.support.PropHelper.nonValue; +import static pro.fessional.wings.silencer.support.PropHelper.invalid; /** * Designed for non-runtime tuning, so no write protection is provided. @@ -205,7 +205,7 @@ public void addAlias(Map alias) { for (Map.Entry en : alias.entrySet()) { final String k = en.getKey(); final String v = en.getValue(); - if (k.equals(v) || nonValue(v)) { + if (k.equals(v) || invalid(v)) { continue; } aliasEnc.put(k, v); diff --git a/wings/slardar-webmvc/src/main/java/pro/fessional/wings/slardar/spring/bean/SlardarRemoteConfiguration.java b/wings/slardar-webmvc/src/main/java/pro/fessional/wings/slardar/spring/bean/SlardarRemoteConfiguration.java index 01e3c08b1..fd1d7f090 100644 --- a/wings/slardar-webmvc/src/main/java/pro/fessional/wings/slardar/spring/bean/SlardarRemoteConfiguration.java +++ b/wings/slardar-webmvc/src/main/java/pro/fessional/wings/slardar/spring/bean/SlardarRemoteConfiguration.java @@ -24,9 +24,9 @@ public class SlardarRemoteConfiguration { public WingsRemoteResolver wingsRemoteResolver(SlardarRemoteProp conf) { log.info("SlardarWebmvc spring-bean wingsRemoteResolver"); final WingsRemoteResolver resolver = new WingsRemoteResolver(); - resolver.addInnerIp(PropHelper.onlyValue(conf.getInnerIp().values())); - resolver.addAgentHeader(PropHelper.onlyValue(conf.getAgentHeader().values())); - resolver.addIpHeader(PropHelper.onlyValue(conf.getIpHeader().values())); + resolver.addInnerIp(PropHelper.onlyValid(conf.getInnerIp().values())); + resolver.addAgentHeader(PropHelper.onlyValid(conf.getAgentHeader().values())); + resolver.addIpHeader(PropHelper.onlyValid(conf.getIpHeader().values())); return resolver; } } diff --git a/wings/slardar-webmvc/src/main/java/pro/fessional/wings/slardar/spring/bean/SlardarSwaggerConfiguration.java b/wings/slardar-webmvc/src/main/java/pro/fessional/wings/slardar/spring/bean/SlardarSwaggerConfiguration.java index becc13061..48ae760d0 100644 --- a/wings/slardar-webmvc/src/main/java/pro/fessional/wings/slardar/spring/bean/SlardarSwaggerConfiguration.java +++ b/wings/slardar-webmvc/src/main/java/pro/fessional/wings/slardar/spring/bean/SlardarSwaggerConfiguration.java @@ -62,7 +62,7 @@ public OpenApiCustomizer slardarOpenApiCustomizer(SlardarSwaggerProp slardarSwag } final Map params = slardarSwaggerProp.toComPara(); - final Map accepts = PropHelper.onlyValue(slardarSwaggerProp.getAccept()); + final Map accepts = PropHelper.onlyValid(slardarSwaggerProp.getAccept()); if (params.isEmpty() && accepts.isEmpty()) return; openApi.getPaths().values() diff --git a/wings/slardar/src/main/java/pro/fessional/wings/slardar/notice/DingTalkConf.java b/wings/slardar/src/main/java/pro/fessional/wings/slardar/notice/DingTalkConf.java index f475e0702..a5327ae30 100644 --- a/wings/slardar/src/main/java/pro/fessional/wings/slardar/notice/DingTalkConf.java +++ b/wings/slardar/src/main/java/pro/fessional/wings/slardar/notice/DingTalkConf.java @@ -3,15 +3,14 @@ import lombok.Data; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import pro.fessional.mirana.cond.IfSetter; import pro.fessional.wings.silencer.encrypt.SecretProvider; +import pro.fessional.wings.silencer.support.PropHelper; import pro.fessional.wings.slardar.jackson.AesString; import java.util.HashMap; import java.util.Map; -import static pro.fessional.wings.silencer.support.PropHelper.mergeIfNon; -import static pro.fessional.wings.silencer.support.PropHelper.nonValue; - /** * @author trydofor * @since 2023-02-21 @@ -72,36 +71,30 @@ public String getValidWebhook() { } } - /** - * use all properties from that - */ - public void adopt(DingTalkConf that) { - if (that == null) return; - - dryrun = that.dryrun; - webhookUrl = that.webhookUrl; - digestSecret = that.digestSecret; - accessToken = that.accessToken; - noticeKeyword = that.noticeKeyword; - msgType = that.msgType; - noticeMobiles.putAll(that.noticeMobiles); - } + public static final IfSetter ConfSetter = (thiz, that, absent, present) -> { + if (that == null) return thiz; + + if (absent == IfSetter.Absent.Invalid) { + if (thiz.dryrun == null) thiz.dryrun = that.dryrun; + if (PropHelper.invalid(thiz.webhookUrl)) thiz.webhookUrl = that.webhookUrl; + if (PropHelper.invalid(thiz.digestSecret)) thiz.digestSecret = that.digestSecret; + if (PropHelper.invalid(thiz.accessToken)) thiz.accessToken = that.accessToken; + if (PropHelper.invalid(thiz.noticeKeyword)) thiz.noticeKeyword = that.noticeKeyword; + if (PropHelper.invalid(thiz.msgType)) thiz.msgType = that.msgType; + PropHelper.mergeToInvalid(thiz.noticeMobiles, that.noticeMobiles); + } + else { + thiz.dryrun = that.dryrun; + thiz.webhookUrl = that.webhookUrl; + thiz.digestSecret = that.digestSecret; + thiz.accessToken = that.accessToken; + thiz.noticeKeyword = that.noticeKeyword; + thiz.msgType = that.msgType; + thiz.noticeMobiles.putAll(that.noticeMobiles); + } - /** - * if this.property is invalid, then use that.property. - * except for 'noticeMobiles' which merge value only if key matches. - */ - public void merge(DingTalkConf that) { - if (that == null) return; - - if (dryrun == null) dryrun = that.dryrun; - if (nonValue(webhookUrl)) webhookUrl = that.webhookUrl; - if (nonValue(digestSecret)) digestSecret = that.digestSecret; - if (nonValue(accessToken)) accessToken = that.accessToken; - if (nonValue(noticeKeyword)) noticeKeyword = that.noticeKeyword; - if (nonValue(msgType)) msgType = that.msgType; - mergeIfNon(noticeMobiles, that.noticeMobiles); - } + return thiz; + }; public interface Loader { /** diff --git a/wings/slardar/src/main/java/pro/fessional/wings/slardar/notice/DingTalkNotice.java b/wings/slardar/src/main/java/pro/fessional/wings/slardar/notice/DingTalkNotice.java index 42bfd5cad..054bdc366 100644 --- a/wings/slardar/src/main/java/pro/fessional/wings/slardar/notice/DingTalkNotice.java +++ b/wings/slardar/src/main/java/pro/fessional/wings/slardar/notice/DingTalkNotice.java @@ -64,8 +64,8 @@ public DingTalkConf defaultConfig() { @Override public DingTalkConf combineConfig(@Nullable DingTalkConf that) { final DingTalkConf newConf = new DingTalkConf(); - newConf.adopt(that); - newConf.merge(configProp.getDefault()); + DingTalkConf.ConfSetter.toAny(newConf, that); + DingTalkConf.ConfSetter.toInvalid(newConf, configProp.getDefault()); return newConf; } diff --git a/wings/warlock-shadow/src/main/java/pro/fessional/wings/warlock/spring/bean/WarlockSecurityBeanConfiguration.java b/wings/warlock-shadow/src/main/java/pro/fessional/wings/warlock/spring/bean/WarlockSecurityBeanConfiguration.java index 332dbf1c6..049ec342a 100644 --- a/wings/warlock-shadow/src/main/java/pro/fessional/wings/warlock/spring/bean/WarlockSecurityBeanConfiguration.java +++ b/wings/warlock-shadow/src/main/java/pro/fessional/wings/warlock/spring/bean/WarlockSecurityBeanConfiguration.java @@ -393,7 +393,7 @@ public WingsAuthDetailsSource wingsAuthDetailsSource(ObjectProvider aesProvider) { log.info("WarlockShadow spring-bean authStateBuilder"); - final AuthStateBuilder bean = new AuthStateBuilder(PropHelper.onlyValue(prop.getSafeState())); + final AuthStateBuilder bean = new AuthStateBuilder(PropHelper.onlyValid(prop.getSafeState())); final Aes aes = aesProvider.getIfAvailable(); if (aes != null) { bean.setAes(aes); diff --git a/wings/warlock-shadow/src/main/java/pro/fessional/wings/warlock/spring/bean/WarlockSecurityConfConfiguration.java b/wings/warlock-shadow/src/main/java/pro/fessional/wings/warlock/spring/bean/WarlockSecurityConfConfiguration.java index aa3122363..1b3511a82 100644 --- a/wings/warlock-shadow/src/main/java/pro/fessional/wings/warlock/spring/bean/WarlockSecurityConfConfiguration.java +++ b/wings/warlock-shadow/src/main/java/pro/fessional/wings/warlock/spring/bean/WarlockSecurityConfConfiguration.java @@ -72,7 +72,7 @@ public WebSecurityCustomizer warlockWebCustomizer(WarlockSecurityProp securityPr // https://github.com/spring-projects/spring-security/issues/10938 final Map webIgnore = securityProp.getWebIgnore(); if (!webIgnore.isEmpty()) { - final Set ignores = PropHelper.onlyValue(webIgnore.values()); + final Set ignores = PropHelper.onlyValid(webIgnore.values()); log.info("WarlockShadow conf WebSecurity, ignoring=" + String.join("\n,", ignores)); web.ignoring().requestMatchers(ignores.toArray(String[]::new)); } @@ -168,14 +168,14 @@ public HttpSecurityCustomizer warlockSecurityAuthHttpConfigure(WarlockSecurityPr return http -> http.authorizeHttpRequests(conf -> { // 1 PermitAll - final Set permed = PropHelper.onlyValue(securityProp.getPermitAll().values()); + final Set permed = PropHelper.onlyValid(securityProp.getPermitAll().values()); if (!permed.isEmpty()) { log.info("WarlockShadow conf HttpSecurity, bind PermitAll=" + String.join("\n,", permed)); conf.requestMatchers(permed.toArray(String[]::new)).permitAll(); } // 2 Authenticated - final Set authed = PropHelper.onlyValue(securityProp.getAuthenticated().values()); + final Set authed = PropHelper.onlyValid(securityProp.getAuthenticated().values()); if (!authed.isEmpty()) { log.info("WarlockShadow conf HttpSecurity, bind Authenticated=" + String.join("\n,", authed)); conf.requestMatchers(authed.toArray(String[]::new)).authenticated(); @@ -188,7 +188,7 @@ public HttpSecurityCustomizer warlockSecurityAuthHttpConfigure(WarlockSecurityPr for (Map.Entry> en : securityProp.getAuthority().entrySet()) { final String perm = en.getKey(); for (String url : en.getValue()) { - if (PropHelper.hasValue(url)) { + if (PropHelper.valid(url)) { final Set st = urlPerm.computeIfAbsent(url, k -> new HashSet<>()); st.add(perm); } @@ -197,7 +197,7 @@ public HttpSecurityCustomizer warlockSecurityAuthHttpConfigure(WarlockSecurityPr // desc for (Map.Entry> en : urlPerm.descendingMap().entrySet()) { final String url = en.getKey(); - final Set pms = PropHelper.onlyValue(en.getValue()); + final Set pms = PropHelper.onlyValid(en.getValue()); log.info("WarlockShadow conf HttpSecurity, bind url=" + url + ", any-permit=[" + String.join(",", pms) + "]"); conf.requestMatchers(url).hasAnyAuthority(pms.toArray(Null.StrArr)); } diff --git a/wings/warlock-shadow/src/main/java/pro/fessional/wings/warlock/spring/prop/WarlockSecurityProp.java b/wings/warlock-shadow/src/main/java/pro/fessional/wings/warlock/spring/prop/WarlockSecurityProp.java index a342c29be..ec4289a2e 100644 --- a/wings/warlock-shadow/src/main/java/pro/fessional/wings/warlock/spring/prop/WarlockSecurityProp.java +++ b/wings/warlock-shadow/src/main/java/pro/fessional/wings/warlock/spring/prop/WarlockSecurityProp.java @@ -386,7 +386,7 @@ public Enum mapAuthTypeDefault() { public Map> mapAuthTypeEnum() { return authType.entrySet() .stream() - .filter(it -> PropHelper.hasValue(it.getValue())) + .filter(it -> PropHelper.valid(it.getValue())) .collect(toMap(Map.Entry::getKey, en -> str2Enum(en.getValue()))); } From adecb9b516c53b5ac5eab21439f2dffa25c184c3 Mon Sep 17 00:00:00 2001 From: trydofor Date: Wed, 3 Jul 2024 18:16:26 +0800 Subject: [PATCH 12/51] =?UTF-8?q?=F0=9F=92=A5=20JournalService=20elapse,?= =?UTF-8?q?=20alive=20#266?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- WingsBoot.t.md | 1 + observe/docs | 2 +- .../wings/faceless/flywave/WingsRevision.java | 5 +- .../sample/TestJooqDslAndDaoSample.java | 72 ++++---- .../commitjournal/CommitJournalModify.java | 9 + .../impl/CommitJournalModifyJdbc.java | 9 +- .../service/journal/JournalService.java | 166 +++++++++++++++++- .../journal/impl/DefaultJournalService.java | 146 +++++++++++---- .../spring/bean/FacelessConfiguration.java | 10 +- .../faceless/spring/prop/JournalProp.java | 36 ++++ .../wings-conf/wings-journal-79.properties | 8 + .../2021-10-26u05-journal-elapse.sql | 3 + .../2021-10-26v05-journal-elapse.sql | 3 + .../01-light/2019-05-20v01-light-commit.sql | 2 + .../impl/DefaultJournalServiceTest.java | 32 +++- .../app/controller/TestAsyncController.java | 2 +- .../slardar/webmvc/AsyncControllerTest.java | 14 +- .../slardar/webmvc/DateTimeConverterTest.java | 120 ++++++------- .../warlock/app/TestPlainAsyncConfigurer.java | 35 ++++ .../app/controller/TestJournalController.java | 58 ++++++ .../warlock/webmvc/JournalControllerTest.java | 79 +++++++++ .../service/other/TerminalJournalService.java | 18 +- .../bean/WarlockJournalConfiguration.java | 9 +- 23 files changed, 687 insertions(+), 152 deletions(-) create mode 100644 wings/faceless/src/main/java/pro/fessional/wings/faceless/spring/prop/JournalProp.java create mode 100644 wings/faceless/src/main/resources/wings-conf/wings-journal-79.properties create mode 100644 wings/faceless/src/main/resources/wings-flywave/branch/somefix/05-journal-elapse/2021-10-26u05-journal-elapse.sql create mode 100644 wings/faceless/src/main/resources/wings-flywave/branch/somefix/05-journal-elapse/2021-10-26v05-journal-elapse.sql create mode 100644 wings/warlock-shadow/src/test/java/pro/fessional/wings/warlock/app/TestPlainAsyncConfigurer.java create mode 100644 wings/warlock-shadow/src/test/java/pro/fessional/wings/warlock/app/controller/TestJournalController.java create mode 100644 wings/warlock-shadow/src/test/java/pro/fessional/wings/warlock/webmvc/JournalControllerTest.java diff --git a/WingsBoot.t.md b/WingsBoot.t.md index af2032dfb..309429233 100644 --- a/WingsBoot.t.md +++ b/WingsBoot.t.md @@ -412,6 +412,7 @@ Use `t.md` as local [Test Management](https://www.jetbrains.com/help/idea/test-m * 14083 DatabaseShard0Test: clean and init shard_0 schema * 14084 DatabaseShard1Test: clean and init shard_1 schema * 14085 ExceptionStackTest: MessageException is stackless by default +* 14086 JournalControllerTest: ttl/plain context check ## 15 Tiny diff --git a/observe/docs b/observe/docs index 9f703e514..8032fd046 160000 --- a/observe/docs +++ b/observe/docs @@ -1 +1 @@ -Subproject commit 9f703e5147c23ea2840ac75233f83edad6739eb3 +Subproject commit 8032fd046fa1a726ed471625ea34d7ed8fe4a634 diff --git a/wings/faceless-flywave/src/main/java/pro/fessional/wings/faceless/flywave/WingsRevision.java b/wings/faceless-flywave/src/main/java/pro/fessional/wings/faceless/flywave/WingsRevision.java index 77ac1407a..e935b525a 100644 --- a/wings/faceless-flywave/src/main/java/pro/fessional/wings/faceless/flywave/WingsRevision.java +++ b/wings/faceless-flywave/src/main/java/pro/fessional/wings/faceless/flywave/WingsRevision.java @@ -21,11 +21,14 @@ public enum WingsRevision implements RevisionRegister { V06_20_1026_01_TinyTask(2020_1026_01L, "tiny task", "master/06-task", "radiant/tiny-task/src/main/resources/wings-flywave"), V07_20_1027_01_TinyMail(2020_1027_01L, "tiny mail", "master/07-mail", "radiant/tiny-mail/src/main/resources/wings-flywave"), + // upgrade V01_21_0918_01_FixAuthn(2021_0918_01L, "fix authn", "branch/somefix/01-authn-fix", "wings/warlock/src/main/resources/wings-flywave"), V02_21_1220_01_Fix242(2021_1220_01L, "fix v242.201", "branch/somefix/02-v242-201", "wings/faceless-flywave/src/main/resources/wings-flywave"), V03_21_1026_02_FixTaskTune(2021_1026_02L, "fix task tune", "branch/somefix/03-task-tune", "radiant/tiny-task/src/main/resources/wings-flywave"), - V01_21_1026_03_FixConfSize(2021_1026_03L, "fix conf size", "branch/somefix/04-conf-size", "wings/warlock/src/main/resources/wings-flywave"), + V04_21_1026_03_FixConfSize(2021_1026_03L, "fix conf size", "branch/somefix/04-conf-size", "wings/warlock/src/main/resources/wings-flywave"), + V05_21_1026_05_FixJournal(2021_1026_05L, "fix journal elapse", "branch/somefix/05-journal-elapse", "wings/faceless/src/main/resources/wings-flywave"), + // testing V90_22_0601_01_TestSchema(2022_0601_01L, "test v1 schema", "master", "wings/testing-faceless/src/main/resources/wings-flywave/"), V90_22_0601_02_TestRecord(2022_0601_02L, "test v2 record", "master", "wings/testing-faceless/src/main/resources/wings-flywave/"), V91_22_0222_01_ExampleInit(2022_0222_01L, "example demo", "master/00-init", "example/winx-common/src/main/resources/wings-flywave/"), diff --git a/wings/faceless-jooq/src/test/java/pro/fessional/wings/faceless/sample/TestJooqDslAndDaoSample.java b/wings/faceless-jooq/src/test/java/pro/fessional/wings/faceless/sample/TestJooqDslAndDaoSample.java index ea72b859a..20f1a4f63 100644 --- a/wings/faceless-jooq/src/test/java/pro/fessional/wings/faceless/sample/TestJooqDslAndDaoSample.java +++ b/wings/faceless-jooq/src/test/java/pro/fessional/wings/faceless/sample/TestJooqDslAndDaoSample.java @@ -50,9 +50,9 @@ @SpringBootTest(properties = { - "logging.level.root=DEBUG", // AssertionLogger - "wings.faceless.jooq.conf.auto-qualify=true", - "wings.faceless.jooq.conf.render-table=ALWAYS", + "logging.level.root=DEBUG", // AssertionLogger + "wings.faceless.jooq.conf.auto-qualify=true", + "wings.faceless.jooq.conf.render-table=ALWAYS", // "wings.faceless.jooq.conf.auto-qualify=false", // "wings.faceless.jooq.conf.render-table=WHEN_MULTIPLE_TABLES", }) @@ -61,16 +61,16 @@ @Slf4j public class TestJooqDslAndDaoSample { - @Setter(onMethod_ = {@Autowired}) + @Setter(onMethod_ = { @Autowired }) private SchemaRevisionManager schemaRevisionManager; - @Setter(onMethod_ = {@Autowired}) + @Setter(onMethod_ = { @Autowired }) private TestingDatabaseHelper testingDatabaseHelper; - @Setter(onMethod_ = {@Autowired}) + @Setter(onMethod_ = { @Autowired }) private TstShardingDao tstShardingDao; - @Setter(onMethod_ = {@Autowired}) + @Setter(onMethod_ = { @Autowired }) private FacelessJooqConfProp prop; @Test @@ -87,8 +87,8 @@ public void test0Init() { public void test1Dao() { final TestingLoggerAssert al = TestingLoggerAssert.install(); final Pattern alias = prop.isAutoQualify() - ? Pattern.compile("from `tst_sharding` as `(\\w+)` where \\(`\\1`.`id` > \\? and `\\1`.`commit_id` < \\?\\)") - : Pattern.compile("from `tst_sharding` as `(\\w+)` where \\(`id` > \\? and `commit_id` < \\?\\)"); + ? Pattern.compile("from `tst_sharding` as `(\\w+)` where \\(`\\1`.`id` > \\? and `\\1`.`commit_id` < \\?\\)") + : Pattern.compile("from `tst_sharding` as `(\\w+)` where \\(`id` > \\? and `commit_id` < \\?\\)"); al.rule("alias-count", event -> alias.matcher(event.getFormattedMessage()).find()); al.rule("table-select", event -> event.getFormattedMessage().contains("from `tst_sharding` where (`id` > ? and `commit_id` < ?)")); al.rule("table-update1", event -> event.getFormattedMessage().contains("update `tst_sharding` set `commit_id` = (`id` + ?), `login_info` = ? where `id` = ?")); @@ -106,10 +106,10 @@ public void test1Dao() { log.info("============count {}, ft2'size={}", i, ft1.size()); // testcaseNotice("select `id`, `commit_id` from `tst_sharding` where (`id` > ? and `commit_id` < ?) order by `id` desc limit ? offset ?"); final var ft2 = tstShardingDao.fetch((t, w) -> w - .where(t.Id.gt(1L).and(t.CommitId.lt(200L))) - .select(t.Id, t.CommitId) - .order(t.Id.desc()) - .limit(2) + .where(t.Id.gt(1L).and(t.CommitId.lt(200L))) + .select(t.Id, t.CommitId) + .order(t.Id.desc()) + .limit(2) ); log.info("============count {}, ft2'size={}", i, ft2.size()); @@ -163,24 +163,24 @@ public void test2Dsl() { final var t1 = TstShardingTable.TstSharding.as("t1"); final var t2 = TstShardingTable.TstSharding.as("t2"); String j1 = dsl - .select(t1.Id, t2.CommitId) - .from(t1, t2) - .where(t1.Id.eq(t2.CommitId)) - .getSQL(); + .select(t1.Id, t2.CommitId) + .from(t1, t2) + .where(t1.Id.eq(t2.CommitId)) + .getSQL(); String j2 = dsl - .select(t1.Id) - .from(t1) - .where(t1.CommitId.in(dsl.select(t2.CommitId).from(t2).where(t2.Id.eq(t1.Id)))) - .getSQL(); + .select(t1.Id) + .from(t1) + .where(t1.CommitId.in(dsl.select(t2.CommitId).from(t2).where(t2.Id.eq(t1.Id)))) + .getSQL(); String j3 = dsl - .select(t1.Id, t2.Id) - .from(t1) - .join(t2) - .on(t1.Id.eq(t2.Id).and(t1.CommitId.eq(t2.CommitId))) - .where(t1.Id.eq(1L)) - .getSQL(); + .select(t1.Id, t2.Id) + .from(t1) + .join(t2) + .on(t1.Id.eq(t2.Id).and(t1.CommitId.eq(t2.CommitId))) + .where(t1.Id.eq(1L)) + .getSQL(); log.info(j1); log.info(j2); @@ -193,7 +193,7 @@ public void test3Journal() { testcaseNotice("Journal Feature"); final var now = LocalDateTime.now(); - final var journal = new Journal(1L, now, "", "", "", ""); + final var journal = new Journal(1L, now, 0, System.currentTimeMillis(), "", "", "", ""); final var s1 = new HashMap<>(); final var t = TstShardingTable.TstSharding; @@ -296,8 +296,8 @@ public void test5DiffDao() { Assertions.assertEquals(t.getName(), d3.getTable()); Assertions.assertEquals(Arrays.asList(t.Id.getName(), t.LoginInfo.getName(), t.OtherInfo.getName()), d3.getColumn()); Assertions.assertEquals(Arrays.asList( - id, "login by diff update", "other by diff insert", - id + 1, "login by diff update", "other by diff insert" + id, "login by diff update", "other by diff insert", + id + 1, "login by diff update", "other by diff insert" ), d3.getValue1()); Assertions.assertTrue(d3.getValue2().isEmpty()); } @@ -333,12 +333,12 @@ public void test5DiffDsl() { Assertions.assertEquals(Arrays.asList(id, now, DATE_TIME, DATE_TIME, id, "login by diff insert", "other by diff insert", ZH_CN), d0.getValue2()); final JournalDiff d2 = JournalDiffHelper.diffUpdate(t, query, () -> - dsl.update(t) - .set(t.CommitId, t.CommitId.add(1)) - .set(t.LoginInfo, "login by diff update") - .set(t.ModifyDt, now) - .where(t.Id.eq(id)) - .execute()); + dsl.update(t) + .set(t.CommitId, t.CommitId.add(1)) + .set(t.LoginInfo, "login by diff update") + .set(t.ModifyDt, now) + .where(t.Id.eq(id)) + .execute()); log.warn("diffUpdate2={}", d2); Assertions.assertNotNull(d2); Assertions.assertEquals(1, d2.getCount()); diff --git a/wings/faceless/src/main/java/pro/fessional/wings/faceless/database/manual/single/modify/commitjournal/CommitJournalModify.java b/wings/faceless/src/main/java/pro/fessional/wings/faceless/database/manual/single/modify/commitjournal/CommitJournalModify.java index 7714a8947..a98c2fd7a 100644 --- a/wings/faceless/src/main/java/pro/fessional/wings/faceless/database/manual/single/modify/commitjournal/CommitJournalModify.java +++ b/wings/faceless/src/main/java/pro/fessional/wings/faceless/database/manual/single/modify/commitjournal/CommitJournalModify.java @@ -7,5 +7,14 @@ * @since 2019-09-12 */ public interface CommitJournalModify { + + /** + * insert new journal + */ int insert(JournalService.Journal journal); + + /** + * update elapse mills by id + */ + int elapse(long mills, long id); } diff --git a/wings/faceless/src/main/java/pro/fessional/wings/faceless/database/manual/single/modify/commitjournal/impl/CommitJournalModifyJdbc.java b/wings/faceless/src/main/java/pro/fessional/wings/faceless/database/manual/single/modify/commitjournal/impl/CommitJournalModifyJdbc.java index cf8abc860..71e1616f7 100644 --- a/wings/faceless/src/main/java/pro/fessional/wings/faceless/database/manual/single/modify/commitjournal/impl/CommitJournalModifyJdbc.java +++ b/wings/faceless/src/main/java/pro/fessional/wings/faceless/database/manual/single/modify/commitjournal/impl/CommitJournalModifyJdbc.java @@ -16,16 +16,23 @@ public class CommitJournalModifyJdbc implements CommitJournalModify { private final JdbcTemplate template; - private static final String INS_SQL = "INSERT INTO sys_commit_journal (id, create_dt, event_name, target_key, login_info, other_info) VALUES (?,?,?,?,?,?)"; + private static final String INS_SQL = "INSERT INTO sys_commit_journal (id, create_dt, parent_id, event_name, target_key, login_info, other_info) VALUES (?,?,?,?,?,?,?)"; + private static final String ELS_SQL = "UPDATE sys_commit_journal SET elapse_ms = ? WHERE id = ?"; @Override public int insert(JournalService.Journal vo) { return template.update(INS_SQL, vo.getId(), vo.getCommitDt(), + vo.getParentId(), nullToEmpty(vo.getEventName()), nullToEmpty(vo.getTargetKey()), nullToEmpty(vo.getLoginInfo()), nullToEmpty(vo.getOtherInfo())); } + + @Override + public int elapse(long mills, long id) { + return template.update(ELS_SQL, mills, id); + } } diff --git a/wings/faceless/src/main/java/pro/fessional/wings/faceless/service/journal/JournalService.java b/wings/faceless/src/main/java/pro/fessional/wings/faceless/service/journal/JournalService.java index 95907d8bc..162a1e976 100644 --- a/wings/faceless/src/main/java/pro/fessional/wings/faceless/service/journal/JournalService.java +++ b/wings/faceless/src/main/java/pro/fessional/wings/faceless/service/journal/JournalService.java @@ -27,6 +27,8 @@ public interface JournalService { class Journal { private final long commitId; private final LocalDateTime commitDt; + private final long parentId; + private final long commitMs; private final String eventName; private final String targetKey; private final String loginInfo; @@ -78,9 +80,30 @@ public long getId() { } } + /** + * set and return elapse mills of the journal, can ignore error. + * SHOULD use the default connection without an explicit transaction. + * NOTE: submit/commit auto elapse, but create not. + */ + long elapse(@NotNull Journal journal); + + /** + * create new Journal without the context. + * SHOULD create journal in REQUIRES_NEW. + * + * @param parentId parent id, default 0; + * @param eventName event name + * @param loginInfo login info ,eg. userId, ip + * @param targetKey key/id of target + * @param otherInfo other info of operation + * @return Journal without the context + */ + @NotNull + Journal create(long parentId, @NotNull String eventName, @Nullable String loginInfo, @Nullable String targetKey, @Nullable String otherInfo); + /** * Submit the operation (event) with journal and return some result. - * Should with Transactional Propagation.REQUIRES_NEW + * SHOULD create journal in REQUIRES_NEW, but not affect commitSet * * @param eventName event name * @param loginInfo login info ,eg. userId, ip @@ -93,6 +116,7 @@ public long getId() { /** * Commit the operation (event) with journal and return the journal. + * SHOULD create journal in REQUIRES_NEW, but not affect commitSet * * @param eventName event name * @param loginInfo login info ,eg. userId, ip @@ -109,8 +133,28 @@ default Journal commit(@NotNull String eventName, @Nullable String loginInfo, @N }); } + /** + * create new Journal without the context. + * SHOULD create journal in REQUIRES_NEW. + * + * @param parentId parent id, default 0; + * @param eventClass use Class.getName as eventName + * @param loginInfo login info ,eg. userId, ip + * @param targetKey key/id of target + * @param otherInfo other info of operation + * @return Journal without the context + */ + @NotNull + default Journal create(long parentId, @NotNull Class eventClass, @Nullable String loginInfo, @Nullable Object targetKey, @Nullable Object otherInfo) { + String lgn = loginInfo == null ? EmptyValue.VARCHAR : loginInfo; + String key = targetKey == null ? EmptyValue.VARCHAR : String.valueOf(targetKey); + String oth = otherInfo == null ? EmptyValue.VARCHAR : String.valueOf(otherInfo); + return create(parentId, eventClass.getName(), lgn, key, oth); + } + /** * Submit the operation (event) with journal and return some result. + * SHOULD create journal in REQUIRES_NEW, but not affect commitSet * It is recommended to `Override` to create targetKey/OtherInfo in Json * * @param eventClass use Class.getName as eventName @@ -130,6 +174,7 @@ default R submit(@NotNull Class eventClass, @Nullable String loginInfo, @ /** * Commit the operation (event) with journal and return the journal. + * SHOULD create journal in REQUIRES_NEW, but not affect commitSet * It is recommended to `Override` to create targetKey/OtherInfo in Json * * @param eventClass use Class.getName as eventName @@ -147,8 +192,24 @@ default Journal commit(@NotNull Class eventClass, @Nullable String loginInfo, }); } + /** + * create new Journal without the context. + * SHOULD create journal in REQUIRES_NEW. + * + * @param parentId parent id, default 0; + * @param eventClass use Class.getName as eventName + * @param targetKey key/id of target + * @param otherInfo other info of operation + * @return Journal without the context + */ + @NotNull + default Journal create(long parentId, @NotNull Class eventClass, @Nullable Object targetKey, @Nullable Object otherInfo) { + return create(parentId, eventClass, null, targetKey, otherInfo); + } + /** * Submit the operation (event) with journal and return some result. + * SHOULD create journal in REQUIRES_NEW, but not affect commitSet * It is recommended to `Override` to get loginInfo in TerminalContext/SecurityContext * * @param eventClass use Class.getName as eventName @@ -164,6 +225,7 @@ default R submit(@NotNull Class eventClass, @Nullable Object targetKey, @ /** * Commit the operation (event) with journal and return the journal. + * SHOULD create journal in REQUIRES_NEW, but not affect commitSet * It is recommended to `Override` to get loginInfo in TerminalContext/SecurityContext * * @param eventClass use Class.getName as eventName @@ -177,8 +239,23 @@ default Journal commit(@NotNull Class eventClass, @Nullable Object targetKey, return commit(eventClass, null, targetKey, otherInfo, commitSet); } + /** + * create new Journal without the context. + * SHOULD create journal in REQUIRES_NEW. + * + * @param parentId parent id, default 0; + * @param eventClass use Class.getName as eventName + * @param targetKey key/id of target + * @return Journal without the context + */ + @NotNull + default Journal create(long parentId, @NotNull Class eventClass, @Nullable Object targetKey) { + return create(parentId, eventClass, null, targetKey, null); + } + /** * Submit the operation (event) with journal and return some result. + * SHOULD create journal in REQUIRES_NEW, but not affect commitSet * It is recommended to `Override` to get loginInfo in TerminalContext/SecurityContext * * @param eventClass use Class.getName as eventName @@ -193,6 +270,7 @@ default R submit(@NotNull Class eventClass, @Nullable Object targetKey, @ /** * Commit the operation (event) with journal and return the journal. + * SHOULD create journal in REQUIRES_NEW, but not affect commitSet * It is recommended to `Override` to get loginInfo in TerminalContext/SecurityContext * * @param eventClass use Class.getName as eventName @@ -205,8 +283,22 @@ default Journal commit(@NotNull Class eventClass, @Nullable Object targetKey, return commit(eventClass, null, targetKey, null, commitSet); } + /** + * create new Journal without the context. + * SHOULD create journal in REQUIRES_NEW. + * + * @param parentId parent id, default 0; + * @param eventClass use Class.getName as eventName + * @return Journal without the context + */ + @NotNull + default Journal create(long parentId, @NotNull Class eventClass) { + return create(parentId, eventClass, null, null, null); + } + /** * Submit the operation (event) with journal and return some result. + * SHOULD create journal in REQUIRES_NEW, but not affect commitSet * It is recommended to `Override` to get loginInfo in TerminalContext/SecurityContext * * @param eventClass use Class.getName as eventName @@ -220,6 +312,7 @@ default R submit(@NotNull Class eventClass, @NotNull Function /** * Commit the operation (event) with journal and return the journal. + * SHOULD create journal in REQUIRES_NEW, but not affect commitSet * It is recommended to `Override` to get loginInfo in TerminalContext/SecurityContext * * @param eventClass use Class.getName as eventName @@ -231,8 +324,29 @@ default Journal commit(@NotNull Class eventClass, @NotNull Consumer return commit(eventClass, null, null, null, commitSet); } + + /** + * create new Journal without the context. + * SHOULD create journal in REQUIRES_NEW. + * + * @param parentId parent id, default 0; + * @param eventEnum convert enum with EnumConvertor + * @param loginInfo login info ,eg. userId, ip + * @param targetKey key/id of target + * @param otherInfo other info of operation + * @return Journal without the context + */ + @NotNull + default Journal create(long parentId, @NotNull Enum eventEnum, @Nullable String loginInfo, @Nullable Object targetKey, @Nullable Object otherInfo) { + String lgn = loginInfo == null ? EmptyValue.VARCHAR : loginInfo; + String key = targetKey == null ? EmptyValue.VARCHAR : String.valueOf(targetKey); + String oth = otherInfo == null ? EmptyValue.VARCHAR : String.valueOf(otherInfo); + return create(parentId, EnumConvertor.enum2Str(eventEnum), lgn, key, oth); + } + /** * Submit the operation (event) with journal and return some result. + * SHOULD create journal in REQUIRES_NEW, but not affect commitSet * It is recommended to `Override` to create targetKey/OtherInfo in Json * * @param eventEnum convert enum with EnumConvertor @@ -252,6 +366,7 @@ default R submit(@NotNull Enum eventEnum, @Nullable String loginInfo, @Nu /** * Commit the operation (event) with journal and return the journal. + * SHOULD create journal in REQUIRES_NEW, but not affect commitSet * It is recommended to `Override` to create targetKey/OtherInfo in Json * * @param eventEnum convert enum with EnumConvertor @@ -269,8 +384,24 @@ default Journal commit(@NotNull Enum eventEnum, @Nullable String loginInfo, @ }); } + /** + * create new Journal without the context. + * SHOULD create journal in REQUIRES_NEW. + * + * @param parentId parent id, default 0; + * @param eventEnum convert enum with EnumConvertor + * @param targetKey key/id of target + * @param otherInfo other info of operation + * @return Journal without the context + */ + @NotNull + default Journal create(long parentId, @NotNull Enum eventEnum, @Nullable Object targetKey, @Nullable Object otherInfo) { + return create(parentId, eventEnum, null, targetKey, otherInfo); + } + /** * Submit the operation (event) with journal and return some result. + * SHOULD create journal in REQUIRES_NEW, but not affect commitSet * It is recommended to `Override` to get loginInfo in TerminalContext/SecurityContext * * @param eventEnum convert enum with EnumConvertor @@ -286,6 +417,7 @@ default R submit(@NotNull Enum eventEnum, @Nullable Object targetKey, @Nu /** * Commit the operation (event) with journal and return the journal. + * SHOULD create journal in REQUIRES_NEW, but not affect commitSet * It is recommended to `Override` to get loginInfo in TerminalContext/SecurityContext * * @param eventEnum convert enum with EnumConvertor @@ -299,8 +431,23 @@ default Journal commit(@NotNull Enum eventEnum, @Nullable Object targetKey, @ return commit(eventEnum, null, targetKey, otherInfo, commitSet); } + /** + * create new Journal without the context. + * SHOULD create journal in REQUIRES_NEW. + * + * @param parentId parent id, default 0; + * @param eventEnum convert enum with EnumConvertor + * @param targetKey key/id of target + * @return Journal without the context + */ + @NotNull + default Journal create(long parentId, @NotNull Enum eventEnum, @Nullable Object targetKey) { + return create(parentId, eventEnum, null, targetKey); + } + /** * Submit the operation (event) with journal and return some result. + * SHOULD create journal in REQUIRES_NEW, but not affect commitSet * It is recommended to `Override` to get loginInfo in TerminalContext/SecurityContext * * @param eventEnum convert enum with EnumConvertor @@ -315,6 +462,7 @@ default R submit(@NotNull Enum eventEnum, @Nullable Object targetKey, @No /** * Commit the operation (event) with journal and return the journal. + * SHOULD create journal in REQUIRES_NEW, but not affect commitSet * It is recommended to `Override` to get loginInfo in TerminalContext/SecurityContext * * @param eventEnum convert enum with EnumConvertor @@ -327,8 +475,23 @@ default Journal commit(@NotNull Enum eventEnum, @Nullable Object targetKey, @ return commit(eventEnum, null, targetKey, null, commitSet); } + + /** + * create new Journal without the context. + * SHOULD create journal in REQUIRES_NEW. + * + * @param parentId parent id, default 0; + * @param eventEnum convert enum with EnumConvertor + * @return Journal without the context + */ + @NotNull + default Journal create(long parentId, @NotNull Enum eventEnum) { + return create(parentId, eventEnum, null, null); + } + /** * Submit the operation (event) with journal and return some result. + * SHOULD create journal in REQUIRES_NEW, but not affect commitSet * It is recommended to `Override` to get loginInfo in TerminalContext/SecurityContext * * @param eventEnum convert enum with EnumConvertor @@ -342,6 +505,7 @@ default R submit(@NotNull Enum eventEnum, @NotNull Function c /** * Commit the operation (event) with journal and return the journal. + * SHOULD create journal in REQUIRES_NEW, but not affect commitSet * It is recommended to `Override` to get loginInfo in TerminalContext/SecurityContext * * @param eventEnum convert enum with EnumConvertor diff --git a/wings/faceless/src/main/java/pro/fessional/wings/faceless/service/journal/impl/DefaultJournalService.java b/wings/faceless/src/main/java/pro/fessional/wings/faceless/service/journal/impl/DefaultJournalService.java index 61df27aa1..556c3215d 100644 --- a/wings/faceless/src/main/java/pro/fessional/wings/faceless/service/journal/impl/DefaultJournalService.java +++ b/wings/faceless/src/main/java/pro/fessional/wings/faceless/service/journal/impl/DefaultJournalService.java @@ -3,9 +3,12 @@ import com.alibaba.ttl.TransmittableThreadLocal; import lombok.RequiredArgsConstructor; import lombok.Setter; +import lombok.extern.slf4j.Slf4j; +import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.springframework.transaction.annotation.Propagation; +import pro.fessional.mirana.time.DateLocaling; import pro.fessional.mirana.time.ThreadNow; import pro.fessional.wings.faceless.convention.EmptyValue; import pro.fessional.wings.faceless.database.helper.DaoAssert; @@ -15,7 +18,7 @@ import pro.fessional.wings.faceless.service.lightid.BlockIdProvider; import pro.fessional.wings.faceless.service.lightid.LightIdService; -import java.util.Objects; +import java.util.concurrent.atomic.AtomicLong; import java.util.function.Function; /** @@ -23,12 +26,14 @@ * @since 2019-09-11 */ @RequiredArgsConstructor +@Slf4j public class DefaultJournalService implements JournalService { public static final String SEQ_JOURNAL = "sys_commit_journal"; /** no leak, for try-finally */ private final TransmittableThreadLocal context = new TransmittableThreadLocal<>(); + private final LightIdService lightIdService; private final BlockIdProvider blockIdProvider; private final CommitJournalModify journalModify; @@ -37,44 +42,125 @@ public class DefaultJournalService implements JournalService { private Propagation propagation = Propagation.REQUIRES_NEW; /** - * programmatic Propagation.REQUIRES_NEW + * create journal by dummyLightId getAndIncrement + */ + @Setter + private AtomicLong dummyLightId = null; + + /** + *
+     * create new journal if the existing to alive,
+     * * negative - use the old
+     * * zero - new one every time
+     * * positive - new one if older
+     * 
+ */ + @Setter + private int aliveSecond = 300; + + /** + * For internal debugging purposes, insert records with a new transaction (REQUIRES_NEW) if not using a dummy connection. */ @NotNull - @Override - public R submit(@NotNull String eventName, @Nullable String loginInfo, @Nullable String targetKey, @Nullable String otherInfo, @NotNull Function commitSet) { - // not null - R result = TransactionHelper.template(propagation).execute(ignore -> - execute(eventName, loginInfo, targetKey, otherInfo, commitSet) + @ApiStatus.Internal + public Journal create(long parentId, AtomicLong dummyId, long nowUtc, @NotNull String eventName, @Nullable String loginInfo, @Nullable String targetKey, @Nullable String otherInfo) { + if (nowUtc <= 0) nowUtc = ThreadNow.millis(); + + final long id = dummyId == null + ? lightIdService.getId(SEQ_JOURNAL, blockIdProvider.getBlockId()) + : dummyId.getAndIncrement(); + + final Journal journal = new Journal(id, DateLocaling.sysLdt(nowUtc), parentId, nowUtc, eventName, + targetKey == null ? EmptyValue.VARCHAR : targetKey, + loginInfo == null ? EmptyValue.VARCHAR : loginInfo, + otherInfo == null ? EmptyValue.VARCHAR : otherInfo ); - return Objects.requireNonNull(result); + + if (dummyId == null) { + TransactionHelper.template(propagation).executeWithoutResult(ignore -> { + int rc = journalModify.insert(journal); + DaoAssert.assertEq1(rc, "failed to insert Journal={}", journal); + }); + } + else { + log.warn("dummyLightId id={}", id); + } + + return journal; } + /** + * For internal debugging purposes, insert records with a new transaction (REQUIRES_NEW) if not using a dummy connection. + * However, update the elapsed time using the default connection without an explicit transaction. + */ @NotNull - private R execute(@NotNull String eventName, @Nullable String loginInfo, @Nullable String targetKey, @Nullable String otherInfo, @NotNull Function commitSet) { - final Journal commit = context.get(); - if (commit == null) { - long id = lightIdService.getId(SEQ_JOURNAL, blockIdProvider.getBlockId()); - - Journal journal = new Journal(id, ThreadNow.localDateTime(), eventName, - targetKey == null ? EmptyValue.VARCHAR : targetKey, - loginInfo == null ? EmptyValue.VARCHAR : loginInfo, - otherInfo == null ? EmptyValue.VARCHAR : otherInfo - ); - - int rc = journalModify.insert(journal); - DaoAssert.assertEq1(rc, "failed to insert Journal={}", journal); - - // Who created, who destroy - context.set(journal); - try { - return commitSet.apply(journal); + @ApiStatus.Internal + public R submit(int aliveSd, AtomicLong dummyId, @NotNull String eventName, @Nullable String loginInfo, @Nullable String targetKey, @Nullable String otherInfo, @NotNull Function commitSet) { + long now = 0; + long pid = 0; + final Journal oldOne = context.get(); + if (oldOne != null) { + if (aliveSd < 0) { + return commitSet.apply(oldOne); } - finally { - context.remove(); + else if (aliveSd > 0) { + now = ThreadNow.millis(); + long live = (now - oldOne.getCommitMs()) / 1000; + if (live <= aliveSd) { + return commitSet.apply(oldOne); + } + else { + pid = oldOne.getId(); + log.warn("renew timeout journal id={}, for alive={}, but live={}", pid, aliveSd, live); + } } } - else { - return commitSet.apply(commit); + + final Journal newOne = create(pid, dummyId, now, eventName, loginInfo, targetKey, otherInfo); + // Who created, who destroy + context.set(newOne); + try { + return commitSet.apply(newOne); } + finally { + context.remove(); + elapse(newOne); + } + } + + /** + * For internal debugging purposes, using the default connection without an explicit transaction, can ignore error. + */ + @ApiStatus.Internal + public long elapse(AtomicLong dummyId, @NotNull Journal journal) { + final long cost = ThreadNow.millis() - journal.getCommitMs(); + + if (dummyId == null) { + try { + // using the default connection without an explicit transaction. + journalModify.elapse(cost, journal.getId()); + } + catch (Exception e) { + log.warn("fail to update elapse=" + cost + ", id=" + journal.getId(), e); + } + } + return cost; + } + + @Override + public long elapse(@NotNull Journal journal) { + return elapse(dummyLightId, journal); + } + + @Override + @NotNull + public Journal create(long parentId, @NotNull String eventName, @Nullable String loginInfo, @Nullable String targetKey, @Nullable String otherInfo) { + return create(parentId, dummyLightId, 0, eventName, loginInfo, targetKey, otherInfo); + } + + @NotNull + @Override + public R submit(@NotNull String eventName, @Nullable String loginInfo, @Nullable String targetKey, @Nullable String otherInfo, @NotNull Function commitSet) { + return submit(aliveSecond, dummyLightId, eventName, loginInfo, targetKey, otherInfo, commitSet); } } diff --git a/wings/faceless/src/main/java/pro/fessional/wings/faceless/spring/bean/FacelessConfiguration.java b/wings/faceless/src/main/java/pro/fessional/wings/faceless/spring/bean/FacelessConfiguration.java index d58c78b0b..5692589d6 100644 --- a/wings/faceless/src/main/java/pro/fessional/wings/faceless/spring/bean/FacelessConfiguration.java +++ b/wings/faceless/src/main/java/pro/fessional/wings/faceless/spring/bean/FacelessConfiguration.java @@ -17,6 +17,7 @@ import pro.fessional.wings.faceless.service.lightid.LightIdService; import pro.fessional.wings.faceless.service.wini18n.impl.StandardI18nServiceJdbc; import pro.fessional.wings.faceless.spring.prop.FacelessEnabledProp; +import pro.fessional.wings.faceless.spring.prop.JournalProp; import pro.fessional.wings.silencer.spring.boot.ConditionalWingsEnabled; import javax.sql.DataSource; @@ -81,8 +82,11 @@ public CommitJournalModifyJdbc commitJournalModify(JdbcTemplate jdbcTemplate) { @Bean @ConditionalWingsEnabled(abs = FacelessEnabledProp.Key$simpleJournal) - public DefaultJournalService journalService(LightIdService lightIdService, BlockIdProvider blockIdProvider, CommitJournalModify journalModify) { - log.info("Faceless spring-bean journalService"); - return new DefaultJournalService(lightIdService, blockIdProvider, journalModify); + public DefaultJournalService journalService(JournalProp journalProp, LightIdService lightIdService, BlockIdProvider blockIdProvider, CommitJournalModify journalModify) { + DefaultJournalService bean = new DefaultJournalService(lightIdService, blockIdProvider, journalModify); + bean.setPropagation(journalProp.getPropagation()); + bean.setAliveSecond(journalProp.getAlive()); + log.info("Faceless spring-bean journalService, propagation=" + journalProp.getPropagation() + ", alive=" + journalProp.getAlive()); + return bean; } } diff --git a/wings/faceless/src/main/java/pro/fessional/wings/faceless/spring/prop/JournalProp.java b/wings/faceless/src/main/java/pro/fessional/wings/faceless/spring/prop/JournalProp.java new file mode 100644 index 000000000..3e59d30b1 --- /dev/null +++ b/wings/faceless/src/main/java/pro/fessional/wings/faceless/spring/prop/JournalProp.java @@ -0,0 +1,36 @@ +package pro.fessional.wings.faceless.spring.prop; + +import lombok.Data; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.transaction.annotation.Propagation; + +/** + * @author trydofor + * @since 2024-07-05 + */ +@Data +@ConfigurationProperties(JournalProp.Key) +public class JournalProp { + public static final String Key = "wings.faceless.journal"; + + /** + * transaction to create new Journal + * + * @see #Key$propagation + */ + private Propagation propagation = Propagation.REQUIRES_NEW; + public static final String Key$propagation = Key + ".propagation"; + + /** + *
+     * create new journal if the existing is older than alive,
+     * * negative - use the old
+     * * zero - new one every time
+     * * positive - new one if older
+     * 
+ * + * @see #Key$alive + */ + private int alive = 300; + public static final String Key$alive = Key + ".alive"; +} diff --git a/wings/faceless/src/main/resources/wings-conf/wings-journal-79.properties b/wings/faceless/src/main/resources/wings-conf/wings-journal-79.properties new file mode 100644 index 000000000..2114b111a --- /dev/null +++ b/wings/faceless/src/main/resources/wings-conf/wings-journal-79.properties @@ -0,0 +1,8 @@ +## transaction to create new Journal +wings.faceless.journal.propagation=REQUIRES_NEW + +## create new journal if the existing is older than alive seconds, +## - `<0` - use the old +## - `0` - new one every time +## - `>0` - new one if older +wings.faceless.journal.alive=300 diff --git a/wings/faceless/src/main/resources/wings-flywave/branch/somefix/05-journal-elapse/2021-10-26u05-journal-elapse.sql b/wings/faceless/src/main/resources/wings-flywave/branch/somefix/05-journal-elapse/2021-10-26u05-journal-elapse.sql new file mode 100644 index 000000000..ab780dbe8 --- /dev/null +++ b/wings/faceless/src/main/resources/wings-flywave/branch/somefix/05-journal-elapse/2021-10-26u05-journal-elapse.sql @@ -0,0 +1,3 @@ +ALTER TABLE `sys_commit_journal` + DROP COLUMN `parent_id`, + DROP COLUMN `elapse_ms`; \ No newline at end of file diff --git a/wings/faceless/src/main/resources/wings-flywave/branch/somefix/05-journal-elapse/2021-10-26v05-journal-elapse.sql b/wings/faceless/src/main/resources/wings-flywave/branch/somefix/05-journal-elapse/2021-10-26v05-journal-elapse.sql new file mode 100644 index 000000000..06771a36f --- /dev/null +++ b/wings/faceless/src/main/resources/wings-flywave/branch/somefix/05-journal-elapse/2021-10-26v05-journal-elapse.sql @@ -0,0 +1,3 @@ +ALTER TABLE `sys_commit_journal` + ADD COLUMN `parent_id` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'parent id if renew' AFTER `create_dt`, + ADD COLUMN `elapse_ms` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'elapse mills' AFTER `parent_id`; \ No newline at end of file diff --git a/wings/faceless/src/main/resources/wings-flywave/master/01-light/2019-05-20v01-light-commit.sql b/wings/faceless/src/main/resources/wings-flywave/master/01-light/2019-05-20v01-light-commit.sql index cceb2eb66..d956bbfa7 100644 --- a/wings/faceless/src/main/resources/wings-flywave/master/01-light/2019-05-20v01-light-commit.sql +++ b/wings/faceless/src/main/resources/wings-flywave/master/01-light/2019-05-20v01-light-commit.sql @@ -11,6 +11,8 @@ CREATE TABLE `sys_light_sequence` ( CREATE TABLE `sys_commit_journal` ( `id` BIGINT(20) NOT NULL COMMENT 'primary key', `create_dt` DATETIME(3) NOT NULL DEFAULT NOW(3) COMMENT 'created datetime', + `parent_id` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'parent id if renew', + `elapse_ms` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'elapse mills', `event_name` VARCHAR(200) NOT NULL COMMENT 'event name', `target_key` VARCHAR(200) NOT NULL DEFAULT '' COMMENT 'target data', `login_info` TEXT NULL COMMENT 'login info: agent, terminal', diff --git a/wings/faceless/src/test/java/pro/fessional/wings/faceless/service/journal/impl/DefaultJournalServiceTest.java b/wings/faceless/src/test/java/pro/fessional/wings/faceless/service/journal/impl/DefaultJournalServiceTest.java index ccf7c07c1..69e5fe786 100644 --- a/wings/faceless/src/test/java/pro/fessional/wings/faceless/service/journal/impl/DefaultJournalServiceTest.java +++ b/wings/faceless/src/test/java/pro/fessional/wings/faceless/service/journal/impl/DefaultJournalServiceTest.java @@ -11,6 +11,7 @@ import org.springframework.transaction.PlatformTransactionManager; import org.springframework.transaction.TransactionStatus; import org.springframework.transaction.annotation.Propagation; +import pro.fessional.mirana.time.Sleep; import pro.fessional.wings.faceless.database.helper.TransactionHelper; import pro.fessional.wings.faceless.service.journal.JournalService.Journal; @@ -23,7 +24,8 @@ */ @SpringBootTest(properties = { "logging.level.org.springframework.jdbc=DEBUG", - "logging.level.org.springframework.transaction=DEBUG" + "logging.level.org.springframework.transaction=DEBUG", + "wings.faceless.journal.alive=1" }) @Slf4j class DefaultJournalServiceTest { @@ -53,7 +55,7 @@ void commit() { // default required new TransactionStatus status = TransactionHelper.begin(); journalService.commit(CallLevel.L1, j1 -> { - journalService.commit(CallLevel.L1, j2 -> { + journalService.commit(CallLevel.L2, j2 -> { journalService.commit(CallLevel.L3, journalRef::set); }); }); @@ -66,21 +68,39 @@ void commit() { Long id = jdbcTemplate.queryForObject("SELECT id FROM sys_commit_journal WHERE id = ?", Long.class, jn.getId()); Assertions.assertEquals(jn.getId(), id); + Assertions.assertEquals(0, jn.getParentId()); } { journalService.setPropagation(Propagation.REQUIRED); + try { + TransactionStatus status = TransactionHelper.begin(); + journalService.commit(CallLevel.L1, j1 -> { + journalService.commit(CallLevel.L1, j2 -> { + journalService.commit(CallLevel.L3, journalRef::set); + }); + }); + TransactionHelper.rollback(status); + Journal jn = journalRef.get(); + List id = jdbcTemplate.queryForList("SELECT id FROM sys_commit_journal WHERE id = ?", Long.class, jn.getId()); + Assertions.assertTrue(id.isEmpty()); + Assertions.assertEquals(0, jn.getParentId()); + } + finally { + journalService.setPropagation(Propagation.REQUIRES_NEW); + } + } - TransactionStatus status = TransactionHelper.begin(); + { journalService.commit(CallLevel.L1, j1 -> { journalService.commit(CallLevel.L1, j2 -> { + Sleep.ignoreInterrupt(2500); journalService.commit(CallLevel.L3, journalRef::set); }); }); - TransactionHelper.rollback(status); + Journal jn = journalRef.get(); - List id = jdbcTemplate.queryForList("SELECT id FROM sys_commit_journal WHERE id = ?", Long.class, jn.getId()); - Assertions.assertTrue(id.isEmpty()); + Assertions.assertTrue(jn.getParentId() != 0); } } } \ No newline at end of file diff --git a/wings/slardar-webmvc/src/test/java/pro/fessional/wings/slardar/app/controller/TestAsyncController.java b/wings/slardar-webmvc/src/test/java/pro/fessional/wings/slardar/app/controller/TestAsyncController.java index 293b054ee..b3bad027f 100644 --- a/wings/slardar-webmvc/src/test/java/pro/fessional/wings/slardar/app/controller/TestAsyncController.java +++ b/wings/slardar-webmvc/src/test/java/pro/fessional/wings/slardar/app/controller/TestAsyncController.java @@ -23,7 +23,7 @@ @RestController public class TestAsyncController { - @Setter(onMethod_ = {@Autowired}) + @Setter(onMethod_ = { @Autowired }) protected TestAsyncService testAsyncService; @RequestMapping(value = "/test/asyn-type.json") diff --git a/wings/slardar-webmvc/src/test/java/pro/fessional/wings/slardar/webmvc/AsyncControllerTest.java b/wings/slardar-webmvc/src/test/java/pro/fessional/wings/slardar/webmvc/AsyncControllerTest.java index 879d6fd03..3dbfcdc70 100644 --- a/wings/slardar-webmvc/src/test/java/pro/fessional/wings/slardar/webmvc/AsyncControllerTest.java +++ b/wings/slardar-webmvc/src/test/java/pro/fessional/wings/slardar/webmvc/AsyncControllerTest.java @@ -33,13 +33,13 @@ @AutoConfigureMockMvc public class AsyncControllerTest { - @Setter(onMethod_ = {@Value("http://localhost:${local.server.port}")}) + @Setter(onMethod_ = { @Value("http://localhost:${local.server.port}") }) private String host; - @Setter(onMethod_ = {@Autowired}) + @Setter(onMethod_ = { @Autowired }) private RestTemplate restTemplate; - @Setter(onMethod_ = {@Autowired}) + @Setter(onMethod_ = { @Autowired }) private MockMvc mockMvc; @Test @@ -85,10 +85,10 @@ private void testMock(String url, String type, boolean err) throws Exception { log.info("mock rul={}, type={}, err={}", url, type, err); MvcResult mvcResult = mockMvc - .perform(get(url).param("err", type)) - .andExpect(request().asyncStarted()) - .andDo(MockMvcResultHandlers.log()) - .andReturn(); + .perform(get(url).param("err", type)) + .andExpect(request().asyncStarted()) + .andDo(MockMvcResultHandlers.log()) + .andReturn(); try { mockMvc.perform(asyncDispatch(mvcResult)) diff --git a/wings/slardar-webmvc/src/test/java/pro/fessional/wings/slardar/webmvc/DateTimeConverterTest.java b/wings/slardar-webmvc/src/test/java/pro/fessional/wings/slardar/webmvc/DateTimeConverterTest.java index 4cda4e6cd..1e744b339 100644 --- a/wings/slardar-webmvc/src/test/java/pro/fessional/wings/slardar/webmvc/DateTimeConverterTest.java +++ b/wings/slardar-webmvc/src/test/java/pro/fessional/wings/slardar/webmvc/DateTimeConverterTest.java @@ -20,14 +20,14 @@ * @since 2020-06-03 */ @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, - properties = {"wings.silencer.i18n.zoneid=" + DateTimeConverterTest.SYS_TZ, "wings.slardar.datetime.zoned.auto=true"}) + properties = { "wings.silencer.i18n.zoneid=" + DateTimeConverterTest.SYS_TZ, "wings.slardar.datetime.zoned.auto=true" }) @AutoConfigureMockMvc public class DateTimeConverterTest { public static final String SYS_TZ = "Asia/Shanghai"; public static final String SYS_OZ = "+08:00"; - @Setter(onMethod_ = {@Autowired}) + @Setter(onMethod_ = { @Autowired }) private MockMvc mockMvc; /** @@ -137,14 +137,14 @@ public void testLdtZdt() throws Exception { */ private void testLdtZdt(String udt, String cdt, String zdt, String utz) throws Exception { final MockHttpServletRequestBuilder builder = post("/test/ldt-zdt.json?d=" + udt) - .header("Zone-Id", utz); + .header("Zone-Id", utz); mockMvc.perform(builder) .andDo(print()) .andExpect(content().json( - "{\"zdt\":\"" + zdt + " " + utz - + "\",\"ldt\":\"" + cdt - + "\",\"sdt\":\"" + cdt + " " + SYS_TZ + "\"}", - true)); + "{\"zdt\":\"" + zdt + " " + utz + + "\",\"ldt\":\"" + cdt + + "\",\"sdt\":\"" + cdt + " " + SYS_TZ + "\"}", + true)); } /** @@ -170,16 +170,16 @@ public void testLdtZdtBody() throws Exception { */ private void testLdtZdtBody(String udt, String cdt, String zdt, String utz) throws Exception { final MockHttpServletRequestBuilder builder = post("/test/ldt-zdt-body.json") - .header("Zone-Id", utz) - .contentType(MediaType.APPLICATION_JSON) - .content("{\"ldt\":\"" + udt + "\"}"); + .header("Zone-Id", utz) + .contentType(MediaType.APPLICATION_JSON) + .content("{\"ldt\":\"" + udt + "\"}"); mockMvc.perform(builder) .andDo(print()) .andExpect(content().json( - "{\"zdt\":\"" + zdt + " " + utz - + "\",\"ldt\":\"" + cdt - + "\",\"sdt\":\"" + cdt + " " + SYS_TZ + "\"}", - true)); + "{\"zdt\":\"" + zdt + " " + utz + + "\",\"ldt\":\"" + cdt + + "\",\"sdt\":\"" + cdt + " " + SYS_TZ + "\"}", + true)); } /** @@ -204,14 +204,14 @@ public void testZdtLdt() throws Exception { */ private void testZdtLdt(String udt, String zdt, String cdt, String utz) throws Exception { final MockHttpServletRequestBuilder builder = get("/test/zdt-ldt.json?d=" + udt) - .header("Zone-Id", utz); + .header("Zone-Id", utz); mockMvc.perform(builder) .andDo(print()) .andExpect(content().json( - "{\"zdt\":\"" + zdt + " " + utz - + "\",\"ldt\":\"" + cdt - + "\",\"sdt\":\"" + cdt + " " + SYS_TZ + "\"}", - true)); + "{\"zdt\":\"" + zdt + " " + utz + + "\",\"ldt\":\"" + cdt + + "\",\"sdt\":\"" + cdt + " " + SYS_TZ + "\"}", + true)); } /** @@ -236,16 +236,16 @@ public void testZdtLdtBody() throws Exception { */ private void testZdtLdtBody(String udt, String zdt, String cdt, String utz) throws Exception { final MockHttpServletRequestBuilder builder = get("/test/zdt-ldt-body.json") - .header("Zone-Id", utz) - .contentType(MediaType.APPLICATION_JSON) - .content("{\"zdt\":\"" + udt + "\"}"); + .header("Zone-Id", utz) + .contentType(MediaType.APPLICATION_JSON) + .content("{\"zdt\":\"" + udt + "\"}"); mockMvc.perform(builder) .andDo(print()) .andExpect(content().json( - "{\"zdt\":\"" + zdt + " " + utz - + "\",\"ldt\":\"" + cdt - + "\",\"sdt\":\"" + cdt + " " + SYS_TZ + "\"}" - , true)); + "{\"zdt\":\"" + zdt + " " + utz + + "\",\"ldt\":\"" + cdt + + "\",\"sdt\":\"" + cdt + " " + SYS_TZ + "\"}" + , true)); } /** @@ -272,14 +272,14 @@ public void testLdtOdt() throws Exception { */ private void testLdtOdt(String udt, String ldt, String odt, String utz, String otz) throws Exception { final MockHttpServletRequestBuilder builder = post("/test/ldt-odt.json?d=" + udt) - .header("Zone-Id", utz); + .header("Zone-Id", utz); mockMvc.perform(builder) .andDo(print()) .andExpect(content().json( - "{\"odt\":\"" + odt + " " + otz - + "\",\"ldt\":\"" + ldt - + "\",\"sdt\":\"" + ldt + " " + SYS_OZ + "\"}", - true)); + "{\"odt\":\"" + odt + " " + otz + + "\",\"ldt\":\"" + ldt + + "\",\"sdt\":\"" + ldt + " " + SYS_OZ + "\"}", + true)); } /** @@ -307,16 +307,16 @@ public void testLdtOdtBody() throws Exception { */ private void testLdtOdtBody(String udt, String ldt, String odt, String utz, String otz) throws Exception { final MockHttpServletRequestBuilder builder = post("/test/ldt-odt-body.json") - .header("Zone-Id", utz) - .contentType(MediaType.APPLICATION_JSON) - .content("{\"ldt\":\"" + udt + "\"}"); + .header("Zone-Id", utz) + .contentType(MediaType.APPLICATION_JSON) + .content("{\"ldt\":\"" + udt + "\"}"); mockMvc.perform(builder) .andDo(print()) .andExpect(content().json( - "{\"odt\":\"" + odt + " " + otz - + "\",\"ldt\":\"" + ldt - + "\",\"sdt\":\"" + ldt + " " + SYS_OZ + "\"}" - , true)); + "{\"odt\":\"" + odt + " " + otz + + "\",\"ldt\":\"" + ldt + + "\",\"sdt\":\"" + ldt + " " + SYS_OZ + "\"}" + , true)); } /** @@ -342,14 +342,14 @@ public void testOdtLdt() throws Exception { */ private void testOdtLdt(String udt, String odt, String cdt, String utz, String otz) throws Exception { final MockHttpServletRequestBuilder builder = get("/test/odt-ldt.json?d=" + udt) - .header("Zone-Id", utz); + .header("Zone-Id", utz); mockMvc.perform(builder) .andDo(print()) .andExpect(content().json( - "{\"odt\":\"" + odt + " " + otz - + "\",\"ldt\":\"" + cdt - + "\",\"sdt\":\"" + cdt + " " + SYS_OZ + "\"}", - true)); + "{\"odt\":\"" + odt + " " + otz + + "\",\"ldt\":\"" + cdt + + "\",\"sdt\":\"" + cdt + " " + SYS_OZ + "\"}", + true)); } /** @@ -375,16 +375,16 @@ public void testOdtLdtBody() throws Exception { */ private void testOdtLdtBody(String udt, String odt, String cdt, String utz, String otz) throws Exception { final MockHttpServletRequestBuilder builder = get("/test/odt-ldt-body.json") - .header("Zone-Id", utz) - .contentType(MediaType.APPLICATION_JSON) - .content("{\"odt\":\"" + udt + "\"}"); + .header("Zone-Id", utz) + .contentType(MediaType.APPLICATION_JSON) + .content("{\"odt\":\"" + udt + "\"}"); mockMvc.perform(builder) .andDo(print()) .andExpect(content().json( - "{\"odt\":\"" + odt + " " + otz - + "\",\"ldt\":\"" + cdt - + "\",\"sdt\":\"" + cdt + " " + SYS_OZ + "\"}" - , true)); + "{\"odt\":\"" + odt + " " + otz + + "\",\"ldt\":\"" + cdt + + "\",\"sdt\":\"" + cdt + " " + SYS_OZ + "\"}" + , true)); } @Test @@ -398,8 +398,8 @@ public void testLdLdBody() throws Exception { private void testLdLdBody(String d, String v) throws Exception { final MockHttpServletRequestBuilder builder = post("/test/ld-ld-body.json") - .contentType(MediaType.APPLICATION_JSON) - .content("{\"ld\":\"" + d + "\"}"); + .contentType(MediaType.APPLICATION_JSON) + .content("{\"ld\":\"" + d + "\"}"); mockMvc.perform(builder) .andDo(print()) @@ -417,8 +417,8 @@ public void testLtLtBody() throws Exception { private void testLtLtBody(String d, String v) throws Exception { final MockHttpServletRequestBuilder builder = post("/test/lt-lt-body.json") - .contentType(MediaType.APPLICATION_JSON) - .content("{\"lt\":\"" + d + "\"}"); + .contentType(MediaType.APPLICATION_JSON) + .content("{\"lt\":\"" + d + "\"}"); mockMvc.perform(builder) .andDo(print()) @@ -431,16 +431,16 @@ public void testLdxAuto1() throws Exception { final String utz = "Asia/Tokyo"; // User +9 zone, 12 o'clock, convert to system +8 zone, 11 o'clock final MockHttpServletRequestBuilder b1q = post("/test/ldx-body-req.json") - .header("Zone-Id", utz) - .contentType(MediaType.APPLICATION_JSON) - .content("{\"ldt\":\"2022-10-03T12:34:56\"}"); + .header("Zone-Id", utz) + .contentType(MediaType.APPLICATION_JSON) + .content("{\"ldt\":\"2022-10-03T12:34:56\"}"); mockMvc.perform(b1q) .andDo(print()) .andExpect(content().string("2022-10-03T11:34:56")); // system +8 zone, 12 o'clock, convert to user +9 zone, 13 o'clock final MockHttpServletRequestBuilder b1s = post("/test/ldx-body-res.json?d=2022-10-03T12:34:56") - .header("Zone-Id", utz); + .header("Zone-Id", utz); mockMvc.perform(b1s) .andDo(print()) .andExpect(content().json("{\"ldt\":\"2022-10-03 13:34:56\"}", true)); @@ -453,7 +453,7 @@ public void testLdxAuto2() throws Exception { // Use +9 zone, 12 o'clock, convert to system +8 zone, 11 o'clock final MockHttpServletRequestBuilder b2q = post("/test/ldt-para-req.json?d=2022-10-03T12:34:56") - .header("Zone-Id", utz); + .header("Zone-Id", utz); mockMvc.perform(b2q) .andDo(print()) .andExpect(content().string("2022-10-03T11:34:56")); @@ -462,7 +462,7 @@ public void testLdxAuto2() throws Exception { // need to use BodyAdvice, which is heavy. // This usage is not common, so this scenario is not supported. final MockHttpServletRequestBuilder b2s = post("/test/ldt-para-res.json?d=2022-10-03T12:34:56") - .header("Zone-Id", utz); + .header("Zone-Id", utz); mockMvc.perform(b2s) .andDo(print()) .andExpect(content().string("\"2022-10-03 12:34:56\"")); diff --git a/wings/warlock-shadow/src/test/java/pro/fessional/wings/warlock/app/TestPlainAsyncConfigurer.java b/wings/warlock-shadow/src/test/java/pro/fessional/wings/warlock/app/TestPlainAsyncConfigurer.java new file mode 100644 index 000000000..af8fc87db --- /dev/null +++ b/wings/warlock-shadow/src/test/java/pro/fessional/wings/warlock/app/TestPlainAsyncConfigurer.java @@ -0,0 +1,35 @@ +package pro.fessional.wings.warlock.app; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.scheduling.annotation.AsyncConfigurer; +import org.springframework.scheduling.annotation.EnableAsync; +import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; +import pro.fessional.wings.silencer.spring.boot.ConditionalWingsEnabled; + +import java.util.concurrent.ThreadPoolExecutor; + +/** + * @author trydofor + * @since 2024-07-02 + */ +@Configuration +@EnableAsync +@ConditionalWingsEnabled(abs = "test.plain-async", value = false) +public class TestPlainAsyncConfigurer implements AsyncConfigurer { + + @Bean("plainPoolTaskExecutor") + public ThreadPoolTaskExecutor plainPoolTaskExecutor() { + ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor(); + taskExecutor.setCorePoolSize(5); + taskExecutor.setMaxPoolSize(5); + taskExecutor.setQueueCapacity(10); + taskExecutor.setKeepAliveSeconds(60); + taskExecutor.setThreadNamePrefix("raw-"); + taskExecutor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy()); + taskExecutor.setWaitForTasksToCompleteOnShutdown(true); + taskExecutor.setAwaitTerminationSeconds(60); + taskExecutor.initialize(); + return taskExecutor; + } +} diff --git a/wings/warlock-shadow/src/test/java/pro/fessional/wings/warlock/app/controller/TestJournalController.java b/wings/warlock-shadow/src/test/java/pro/fessional/wings/warlock/app/controller/TestJournalController.java new file mode 100644 index 000000000..1bc45258c --- /dev/null +++ b/wings/warlock-shadow/src/test/java/pro/fessional/wings/warlock/app/controller/TestJournalController.java @@ -0,0 +1,58 @@ +package pro.fessional.wings.warlock.app.controller; + +import lombok.Setter; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; +import pro.fessional.mirana.pain.MessageException; +import pro.fessional.mirana.time.Sleep; +import pro.fessional.wings.faceless.service.journal.impl.DefaultJournalService; +import pro.fessional.wings.slardar.async.AsyncHelper; + +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.atomic.AtomicLong; + +/** + * @author trydofor + * @since 2024-05-07 + */ +@Slf4j +@RestController +public class TestJournalController { + + @Setter(onMethod_ = { @Autowired }) + protected DefaultJournalService defaultJournalService; + + @Setter(onMethod_ = { @Autowired(required = false), @Qualifier("plainPoolTaskExecutor") }) + protected ThreadPoolTaskExecutor plainPoolTaskExecutor; + + private final AtomicLong dummyLightId = new AtomicLong(1); + private int aliveSecond = -1; + + @RequestMapping(value = "/test/ttl-journal.json") + public CompletableFuture testTtlContext(@RequestParam("i") int i, @RequestParam("t") boolean t) { + return t ? AsyncHelper.Async(() -> recurExecute(i)) + : plainPoolTaskExecutor.submitCompletable(() -> recurExecute(i)); + } + + private Long recurExecute(int t) { + if (t % 5 != 0) { + return defaultJournalService.submit(aliveSecond, dummyLightId, "", null, null, null, d -> { + recurExecute(t - 1); + return d.getId(); + }); + } + else { + return defaultJournalService.submit(aliveSecond, dummyLightId, "", null, null, null, d -> { + Sleep.ignoreInterrupt(500); + if (t % 7 == 0) throw new MessageException("error7=" + t); + return d.getId(); + }); + } + } + +} diff --git a/wings/warlock-shadow/src/test/java/pro/fessional/wings/warlock/webmvc/JournalControllerTest.java b/wings/warlock-shadow/src/test/java/pro/fessional/wings/warlock/webmvc/JournalControllerTest.java new file mode 100644 index 000000000..3884f5950 --- /dev/null +++ b/wings/warlock-shadow/src/test/java/pro/fessional/wings/warlock/webmvc/JournalControllerTest.java @@ -0,0 +1,79 @@ +package pro.fessional.wings.warlock.webmvc; + +import io.qameta.allure.TmsLink; +import lombok.Setter; +import lombok.extern.slf4j.Slf4j; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.web.client.RestTemplate; +import pro.fessional.mirana.best.DummyBlock; + +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.regex.Pattern; + + +/** + * @author trydofor + * @since 2022-12-03 + */ +@Slf4j +@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, + properties = "test.plain-async=true") +@AutoConfigureMockMvc +public class JournalControllerTest { + + @Setter(onMethod_ = { @Value("http://localhost:${local.server.port}") }) + private String host; + + @Setter(onMethod_ = { @Autowired }) + private RestTemplate restTemplate; + + @Test + @TmsLink("C14086") + public void testTtlContext() throws InterruptedException { + + final ExecutorService executorService = Executors.newFixedThreadPool(50); + + final Pattern number = Pattern.compile("\\d+"); + final int total = 1000; + final AtomicInteger error = new AtomicInteger(0); + + final ConcurrentHashMap normal = new ConcurrentHashMap<>(); + + for (int i = 0; i < total; i++) { + final String ix = String.valueOf(i); + final boolean ttl = i % 2 == 0; + executorService.submit(() -> { + final String id = restTemplate.getForObject( + host + + "/test/ttl-journal.json?t=" + + ttl + "&i=" + ix, String.class); + if (number.matcher(id).matches()) { + normal.compute(id, (k, v) -> v == null ? 1 : v + 1); + } + else { + error.incrementAndGet(); + } + }); + } + executorService.shutdown(); + while (!executorService.awaitTermination(60, TimeUnit.SECONDS)) { + DummyBlock.empty(); + } + + for (Map.Entry en : normal.entrySet()) { + Assertions.assertEquals(1, en.getValue(), en.getKey()); + } + log.info("normal={}, error={}, total={}", normal.size(), error.get(), total); + Assertions.assertEquals(total, error.get() + normal.size()); + } +} diff --git a/wings/warlock/src/main/java/pro/fessional/wings/warlock/service/other/TerminalJournalService.java b/wings/warlock/src/main/java/pro/fessional/wings/warlock/service/other/TerminalJournalService.java index cafd4f0ed..2d4c72528 100644 --- a/wings/warlock/src/main/java/pro/fessional/wings/warlock/service/other/TerminalJournalService.java +++ b/wings/warlock/src/main/java/pro/fessional/wings/warlock/service/other/TerminalJournalService.java @@ -22,8 +22,19 @@ public TerminalJournalService(LightIdService ids, BlockIdProvider bid, CommitJou } @Override - public @NotNull R submit(@NotNull String eventName, @Nullable String loginInfo, @Nullable String targetKey, @Nullable String otherInfo, @NotNull Function commitSet) { - if (loginInfo == null || loginInfo.isEmpty()) { + @NotNull + public Journal create(long parentId, @NotNull String eventName, @Nullable String loginInfo, @Nullable String targetKey, @Nullable String otherInfo) { + return super.create(parentId, eventName, terminal(loginInfo), targetKey, otherInfo); + } + + @Override + @NotNull + public R submit(@NotNull String eventName, @Nullable String loginInfo, @Nullable String targetKey, @Nullable String otherInfo, @NotNull Function commitSet) { + return super.submit(eventName, terminal(loginInfo), targetKey, otherInfo, commitSet); + } + + private String terminal(String loginInfo) { + if (loginInfo == null || loginInfo.isBlank()) { final TerminalContext.Context ctx = TerminalContext.get(false); if (!ctx.isNull()) { loginInfo = JsonTemplate.obj(obj -> { @@ -35,6 +46,7 @@ public TerminalJournalService(LightIdService ids, BlockIdProvider bid, CommitJou }); } } - return super.submit(eventName, loginInfo, targetKey, otherInfo, commitSet); + + return loginInfo; } } diff --git a/wings/warlock/src/main/java/pro/fessional/wings/warlock/spring/bean/WarlockJournalConfiguration.java b/wings/warlock/src/main/java/pro/fessional/wings/warlock/spring/bean/WarlockJournalConfiguration.java index 0b79247c7..53ff5c04f 100644 --- a/wings/warlock/src/main/java/pro/fessional/wings/warlock/spring/bean/WarlockJournalConfiguration.java +++ b/wings/warlock/src/main/java/pro/fessional/wings/warlock/spring/bean/WarlockJournalConfiguration.java @@ -7,6 +7,7 @@ import pro.fessional.wings.faceless.database.manual.single.modify.commitjournal.CommitJournalModify; import pro.fessional.wings.faceless.service.lightid.BlockIdProvider; import pro.fessional.wings.faceless.service.lightid.LightIdService; +import pro.fessional.wings.faceless.spring.prop.JournalProp; import pro.fessional.wings.silencer.spring.boot.ConditionalWingsEnabled; import pro.fessional.wings.warlock.service.other.TerminalJournalService; @@ -26,11 +27,15 @@ public class WarlockJournalConfiguration { @Bean @ConditionalWingsEnabled public TerminalJournalService terminalJournalService( + JournalProp journalProp, @SuppressWarnings("all") LightIdService lightIdService, @SuppressWarnings("all") BlockIdProvider blockIdProvider, @SuppressWarnings("all") CommitJournalModify journalModify ) { - log.info("WarlockShadow spring-bean terminalJournalService Overriding"); - return new TerminalJournalService(lightIdService, blockIdProvider, journalModify); + TerminalJournalService bean = new TerminalJournalService(lightIdService, blockIdProvider, journalModify); + bean.setPropagation(journalProp.getPropagation()); + bean.setAliveSecond(journalProp.getAlive()); + log.info("WarlockShadow spring-bean terminalJournalService Overriding, propagation=" + journalProp.getPropagation() + ", alive=" + journalProp.getAlive()); + return bean; } } From a3d85ba1339e3e996827b9a38a9af1b382d353bb Mon Sep 17 00:00:00 2001 From: trydofor Date: Thu, 4 Jul 2024 20:20:49 +0800 Subject: [PATCH 13/51] =?UTF-8?q?=E2=9C=A8=20Prop=20Resource=20with=20opti?= =?UTF-8?q?onal=20#267?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- WingsBoot.t.md | 1 + .../tiny/mail/sender/MailSenderManager.java | 17 +++++- .../tiny/mail/sender/TinyMailConfig.java | 3 + .../tiny/mail/sender/TinyMailMessage.java | 4 +- .../wings/tiny/mail/service/TinyMail.java | 17 +++++- .../spring/help/ApplicationContextHelper.java | 7 +++ .../wings/silencer/support/PropHelper.java | 55 ++++++++++++++++++- .../silencer/support/PropHelperTest.java | 25 +++++++++ 8 files changed, 123 insertions(+), 6 deletions(-) diff --git a/WingsBoot.t.md b/WingsBoot.t.md index 309429233..48f4511b0 100644 --- a/WingsBoot.t.md +++ b/WingsBoot.t.md @@ -40,6 +40,7 @@ Use `t.md` as local [Test Management](https://www.jetbrains.com/help/idea/test-m * 11034 ThisLazyProxyTest: thisLazy with default jdk proxy * 11035 TypedClassTest: ResolvableType sugar * 11036 CommonPropHelperTest: comma delimited string +* 11037 CommonPropHelperTest: resource string ## 12 Faceless diff --git a/radiant/tiny-mail/src/main/java/pro/fessional/wings/tiny/mail/sender/MailSenderManager.java b/radiant/tiny-mail/src/main/java/pro/fessional/wings/tiny/mail/sender/MailSenderManager.java index 4349474b1..4d55809e4 100644 --- a/radiant/tiny-mail/src/main/java/pro/fessional/wings/tiny/mail/sender/MailSenderManager.java +++ b/radiant/tiny-mail/src/main/java/pro/fessional/wings/tiny/mail/sender/MailSenderManager.java @@ -17,6 +17,7 @@ import pro.fessional.mirana.time.Sleep; import pro.fessional.mirana.time.ThreadNow; import pro.fessional.wings.faceless.convention.EmptySugar; +import pro.fessional.wings.silencer.support.PropHelper; import pro.fessional.wings.tiny.mail.spring.prop.TinyMailSenderProp; import java.math.BigDecimal; @@ -368,9 +369,19 @@ private MimeMessage prepareMimeMessage(TinyMailMessage message, MimeMessagePrepa } final Map files = message.getAttachment(); - if (files != null) { - for (Map.Entry en : files.entrySet()) { - helper.addAttachment(en.getKey(), en.getValue()); + for (Map.Entry en : files.entrySet()) { + final String name = en.getKey(); + final String n1 = PropHelper.removeOptional(name, null); + if (n1 != null) { + try { + helper.addAttachment(n1, en.getValue()); + } + catch (Exception e) { + log.warn("ignore error of optional resource, name=" + name); + } + } + else { + helper.addAttachment(name, en.getValue()); } } diff --git a/radiant/tiny-mail/src/main/java/pro/fessional/wings/tiny/mail/sender/TinyMailConfig.java b/radiant/tiny-mail/src/main/java/pro/fessional/wings/tiny/mail/sender/TinyMailConfig.java index 023a812eb..ee8e3ebdf 100644 --- a/radiant/tiny-mail/src/main/java/pro/fessional/wings/tiny/mail/sender/TinyMailConfig.java +++ b/radiant/tiny-mail/src/main/java/pro/fessional/wings/tiny/mail/sender/TinyMailConfig.java @@ -40,14 +40,17 @@ public class TinyMailConfig extends MailProperties { /** * default mail to */ + @NotNull protected String[] to; /** * default mail cc */ + @Nullable protected String[] cc; /** * default mail bcc */ + @Nullable protected String[] bcc; /** * default mail reply diff --git a/radiant/tiny-mail/src/main/java/pro/fessional/wings/tiny/mail/sender/TinyMailMessage.java b/radiant/tiny-mail/src/main/java/pro/fessional/wings/tiny/mail/sender/TinyMailMessage.java index be06f2fc9..f799a970f 100644 --- a/radiant/tiny-mail/src/main/java/pro/fessional/wings/tiny/mail/sender/TinyMailMessage.java +++ b/radiant/tiny-mail/src/main/java/pro/fessional/wings/tiny/mail/sender/TinyMailMessage.java @@ -2,6 +2,7 @@ import lombok.Data; import lombok.EqualsAndHashCode; +import org.jetbrains.annotations.NotNull; import org.springframework.core.io.Resource; import pro.fessional.mirana.cond.IfSetter; import pro.fessional.mirana.text.WhiteUtil; @@ -39,10 +40,11 @@ public class TinyMailMessage extends TinyMailConfig { protected String content; /** - * Mail attachments and its names + * Mail attachments and its names (can prefix `optional:`) */ protected Map attachment = null; + @NotNull public Map getAttachment() { return attachment != null ? attachment : Collections.emptyMap(); } diff --git a/radiant/tiny-mail/src/main/java/pro/fessional/wings/tiny/mail/service/TinyMail.java b/radiant/tiny-mail/src/main/java/pro/fessional/wings/tiny/mail/service/TinyMail.java index 344c69801..499f32b4c 100644 --- a/radiant/tiny-mail/src/main/java/pro/fessional/wings/tiny/mail/service/TinyMail.java +++ b/radiant/tiny-mail/src/main/java/pro/fessional/wings/tiny/mail/service/TinyMail.java @@ -1,9 +1,13 @@ package pro.fessional.wings.tiny.mail.service; import lombok.Data; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import org.springframework.core.io.Resource; +import pro.fessional.wings.silencer.support.PropHelper; import java.time.LocalDateTime; +import java.util.LinkedHashMap; import java.util.Map; /** @@ -23,6 +27,7 @@ public class TinyMail { /** * Mail to, use default if null */ + @Nullable protected String[] to; public void setTo(String... to) { @@ -32,6 +37,7 @@ public void setTo(String... to) { /** * Mail cc, use default if null */ + @Nullable protected String[] cc; public void setCc(String... cc) { @@ -41,6 +47,7 @@ public void setCc(String... cc) { /** * Mail bcc, use default if null */ + @Nullable protected String[] bcc; public void setBcc(String... bcc) { @@ -61,8 +68,9 @@ public void setBcc(String... bcc) { */ protected String content; /** - * Mail attachment, use default if null + * Mail attachment and its name (can prefix `optional:`), use default if null */ + @Nullable protected Map attachment = null; /** * Whether to send html mail (text/html), otherwise text mail(text/plain). @@ -119,4 +127,11 @@ public void setContentHtml(String content, Boolean html) { this.content = content; this.html = html; } + + public void putAttachment(@NotNull String name, @NotNull Resource resource, boolean optional) { + if (attachment == null) attachment = new LinkedHashMap<>(); + if (optional) name = PropHelper.prefixOptional(name); + + attachment.put(name, resource); + } } diff --git a/wings/silencer/src/main/java/pro/fessional/wings/silencer/spring/help/ApplicationContextHelper.java b/wings/silencer/src/main/java/pro/fessional/wings/silencer/spring/help/ApplicationContextHelper.java index 0a75402c8..c44febfbb 100644 --- a/wings/silencer/src/main/java/pro/fessional/wings/silencer/spring/help/ApplicationContextHelper.java +++ b/wings/silencer/src/main/java/pro/fessional/wings/silencer/spring/help/ApplicationContextHelper.java @@ -38,6 +38,13 @@ protected ApplicationContextHelper(ConfigurableApplicationContext ctx) { environment = Objects.requireNonNull(ctx.getEnvironment()); } + /** + * whether the ApplicationContext is prepared + */ + public static boolean isPrepared() { + return context != null; + } + /** * Get the value of spring.application.name (if not empty) or context#getApplicationName by default. */ diff --git a/wings/silencer/src/main/java/pro/fessional/wings/silencer/support/PropHelper.java b/wings/silencer/src/main/java/pro/fessional/wings/silencer/support/PropHelper.java index 2b3e6c6dd..c118c53db 100644 --- a/wings/silencer/src/main/java/pro/fessional/wings/silencer/support/PropHelper.java +++ b/wings/silencer/src/main/java/pro/fessional/wings/silencer/support/PropHelper.java @@ -5,10 +5,12 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.springframework.core.io.ClassPathResource; +import org.springframework.core.io.DefaultResourceLoader; import org.springframework.core.io.Resource; import org.springframework.core.io.ResourceLoader; import org.springframework.util.ResourceUtils; import pro.fessional.mirana.data.Null; +import pro.fessional.wings.silencer.spring.help.ApplicationContextHelper; import java.util.ArrayList; import java.util.Arrays; @@ -19,6 +21,7 @@ import java.util.List; import java.util.Map; +import static org.springframework.boot.context.config.ConfigDataLocation.OPTIONAL_PREFIX; import static org.springframework.util.ResourceUtils.CLASSPATH_URL_PREFIX; /** @@ -116,9 +119,59 @@ public static String stringResource(Resource resource) { return resource.getURL().toExternalForm(); } + /** + * make sure prefix `optional:` + */ + @NotNull + public static String prefixOptional(@NotNull String url) { + return url.startsWith(OPTIONAL_PREFIX) + ? url + : OPTIONAL_PREFIX + url; + } + + /** + * remove prefix `optional:`, return elz if no prefix + */ + @Contract("_,!null->!null") + public static String removeOptional(@NotNull String url, String elz) { + boolean ok = false; + while (url.startsWith(OPTIONAL_PREFIX)) { + url = url.substring(9); + ok = true; + } + return ok ? url : elz; + } + + /** + * `optional:` prefix will return null if exception. + * use ApplicationContext(if prepared) or DefaultResourceLoader as loader by default. + */ + @Nullable + public static Resource resourceString(String url) { + ResourceLoader resourceLoader = ApplicationContextHelper.isPrepared() ? + ApplicationContextHelper.getContext() : new DefaultResourceLoader(); + return resourceString(url, resourceLoader); + } + + /** + * `optional:` prefix will return null if exception + */ + @Nullable public static Resource resourceString(String url, @NotNull ResourceLoader resourceLoader) { if (url == null || url.isBlank()) return null; - return resourceLoader.getResource(url); + + String u1 = removeOptional(url, null); + if (u1 != null) { + try { + return resourceLoader.getResource(u1); + } + catch (Exception e) { + return null; + } + } + else { + return resourceLoader.getResource(url); + } } /** diff --git a/wings/silencer/src/test/java/pro/fessional/wings/silencer/support/PropHelperTest.java b/wings/silencer/src/test/java/pro/fessional/wings/silencer/support/PropHelperTest.java index 3d761be55..477f9d409 100644 --- a/wings/silencer/src/test/java/pro/fessional/wings/silencer/support/PropHelperTest.java +++ b/wings/silencer/src/test/java/pro/fessional/wings/silencer/support/PropHelperTest.java @@ -3,6 +3,9 @@ import io.qameta.allure.TmsLink; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.core.io.ClassPathResource; +import org.springframework.core.io.Resource; import java.util.List; @@ -10,6 +13,7 @@ * @author trydofor * @since 2024-06-28 */ +@SpringBootTest class PropHelperTest { @Test @@ -41,4 +45,25 @@ void testCommaList() { Assertions.assertEquals("1", PropHelper.commaString(List.of("", "", "1 ", "- "), true, true)); Assertions.assertEquals("1 ,- ", PropHelper.commaString(List.of("", "", "1 ", "- "), false, true)); } + + @Test + @TmsLink("C11037") + void testResourceString() { + ClassPathResource app = new ClassPathResource("application.properties"); + Assertions.assertTrue(app.exists()); + String res1 = PropHelper.stringResource(app); + Assertions.assertEquals("classpath:application.properties", res1); + + Resource res2 = PropHelper.resourceString("classpath:application.properties"); + Assertions.assertTrue(res2.exists()); + + Resource res3 = PropHelper.resourceString("optional:classpath:application.properties"); + Assertions.assertTrue(res3.exists()); + + Resource res4 = PropHelper.resourceString("optional:classpath:application.properties-404"); + Assertions.assertFalse(res4.exists()); + + Resource res5 = PropHelper.resourceString("optional:file:./application.properties-404"); + Assertions.assertFalse(res5.exists()); + } } \ No newline at end of file From 8cff4602fab4745140ae919e1b6a7dbb822e1ba6 Mon Sep 17 00:00:00 2001 From: trydofor Date: Fri, 5 Jul 2024 20:59:56 +0800 Subject: [PATCH 14/51] =?UTF-8?q?=E2=9C=A8=20prepared=20method=20to=20subc?= =?UTF-8?q?lass-init=20helper=20#268?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../spring/help/ApplicationContextHelper.java | 8 +-- .../bean/HazelcastServiceConfiguration.java | 2 +- .../SlardarHazelSessionConfiguration.java | 4 +- .../bean/SlardarJacksonWebConfiguration.java | 12 +++-- .../wings/slardar/async/AsyncHelper.java | 30 +++++++---- .../slardar/async/TaskSchedulerHelper.java | 30 ++++++++--- .../wings/slardar/cache/WingsCacheHelper.java | 49 +++++++++++------- .../cache/spring/WingsCacheAnnoOprSource.java | 2 +- .../slardar/event/EventPublishHelper.java | 50 ++++++++++++++----- .../wings/slardar/jackson/JacksonHelper.java | 26 ++++++---- .../bean/SlardarAsyncConfiguration.java | 10 +--- .../bean/SlardarCacheConfiguration.java | 2 +- .../bean/SlardarEventConfiguration.java | 4 +- .../bean/WarlockTableChangeConfiguration.java | 14 +----- 14 files changed, 149 insertions(+), 94 deletions(-) diff --git a/wings/silencer/src/main/java/pro/fessional/wings/silencer/spring/help/ApplicationContextHelper.java b/wings/silencer/src/main/java/pro/fessional/wings/silencer/spring/help/ApplicationContextHelper.java index c44febfbb..f8c96f8a7 100644 --- a/wings/silencer/src/main/java/pro/fessional/wings/silencer/spring/help/ApplicationContextHelper.java +++ b/wings/silencer/src/main/java/pro/fessional/wings/silencer/spring/help/ApplicationContextHelper.java @@ -32,17 +32,19 @@ public class ApplicationContextHelper { private static ConfigurableApplicationContext context; private static ConfigurableEnvironment environment; + private static boolean helperPrepared = false; - protected ApplicationContextHelper(ConfigurableApplicationContext ctx) { + protected ApplicationContextHelper(@NotNull ConfigurableApplicationContext ctx) { context = Objects.requireNonNull(ctx); environment = Objects.requireNonNull(ctx.getEnvironment()); + helperPrepared = true; } /** - * whether the ApplicationContext is prepared + * whether this helper is prepared */ public static boolean isPrepared() { - return context != null; + return helperPrepared; } /** diff --git a/wings/slardar-hazel-caching/src/main/java/pro/fessional/wings/slardar/spring/bean/HazelcastServiceConfiguration.java b/wings/slardar-hazel-caching/src/main/java/pro/fessional/wings/slardar/spring/bean/HazelcastServiceConfiguration.java index 82b46bec7..170c766be 100644 --- a/wings/slardar-hazel-caching/src/main/java/pro/fessional/wings/slardar/spring/bean/HazelcastServiceConfiguration.java +++ b/wings/slardar-hazel-caching/src/main/java/pro/fessional/wings/slardar/spring/bean/HazelcastServiceConfiguration.java @@ -32,7 +32,7 @@ public static class GlobalPublisherWired { @Autowired public void auto(HazelcastInstance instance, ApplicationEventPublisher publisher) { HazelcastSyncPublisher global = new HazelcastSyncPublisher(instance, publisher); - EventPublishHelper.setGlobalPublisher(global); + EventPublishHelper.prepareGlobalPublisher(global); log.info("SlardarHazelCaching spring-auto initHazelcastSyncPublisher, uuid=" + global.getMessageListenerUuid()); } } diff --git a/wings/slardar-hazel-session/src/main/java/pro/fessional/wings/slardar/spring/bean/SlardarHazelSessionConfiguration.java b/wings/slardar-hazel-session/src/main/java/pro/fessional/wings/slardar/spring/bean/SlardarHazelSessionConfiguration.java index aa977640b..2e5ac9bed 100644 --- a/wings/slardar-hazel-session/src/main/java/pro/fessional/wings/slardar/spring/bean/SlardarHazelSessionConfiguration.java +++ b/wings/slardar-hazel-session/src/main/java/pro/fessional/wings/slardar/spring/bean/SlardarHazelSessionConfiguration.java @@ -39,10 +39,10 @@ public SpringSessionBackedSessionRegistry sessionRegistry(FindByIndexNameSess public HazelcastSessionHelper wingsSessionHelper( FindByIndexNameSessionRepository sessionRepository, HazelcastInstance hazelcastInstance, - @Value("${spring.session.hazelcast.map-name:spring:session:sessions}") String mapName) { + @Value("${spring.session.hazelcast.map-name:spring:session:sessions}") String sessionMapName) { log.info("SlardarHazelSession spring-bean wingsSessionHelper"); - return new HazelcastSessionHelper(sessionRepository, hazelcastInstance, mapName); + return new HazelcastSessionHelper(sessionRepository, hazelcastInstance, sessionMapName); } /** diff --git a/wings/slardar-webmvc/src/main/java/pro/fessional/wings/slardar/spring/bean/SlardarJacksonWebConfiguration.java b/wings/slardar-webmvc/src/main/java/pro/fessional/wings/slardar/spring/bean/SlardarJacksonWebConfiguration.java index 85d80c03f..ce7ef33af 100644 --- a/wings/slardar-webmvc/src/main/java/pro/fessional/wings/slardar/spring/bean/SlardarJacksonWebConfiguration.java +++ b/wings/slardar-webmvc/src/main/java/pro/fessional/wings/slardar/spring/bean/SlardarJacksonWebConfiguration.java @@ -275,14 +275,18 @@ public ApplicationStartedEventRunner jacksonHelperRunner(ApplicationContext cont var builder = context.getBean(Jackson2ObjectMapperBuilder.class); // wings - bindXmlWings(builder.createXmlMapper(true).build()); - bindJsonWings(builder.createXmlMapper(false).build()); + prepareWings( + builder.createXmlMapper(false).build(), + builder.createXmlMapper(true).build() + ); // bean var jsonBean = context.getBeanProvider(ObjectMapper.class); - bindJsonBean(jsonBean.getIfAvailable(() -> context.getBean(ObjectMapper.class))); var xmlBean = context.getBeanProvider(XmlMapper.class); - bindXmlBean(xmlBean.getIfAvailable(() -> builder.createXmlMapper(true).build())); + prepareBean( + jsonBean.getIfAvailable(() -> builder.createXmlMapper(false).build()), + xmlBean.getIfAvailable(() -> builder.createXmlMapper(true).build()) + ); // at last, restore createXmlMapper to false builder.createXmlMapper(false); diff --git a/wings/slardar/src/main/java/pro/fessional/wings/slardar/async/AsyncHelper.java b/wings/slardar/src/main/java/pro/fessional/wings/slardar/async/AsyncHelper.java index c78499f30..8a9cdbd9d 100644 --- a/wings/slardar/src/main/java/pro/fessional/wings/slardar/async/AsyncHelper.java +++ b/wings/slardar/src/main/java/pro/fessional/wings/slardar/async/AsyncHelper.java @@ -5,6 +5,7 @@ import org.springframework.boot.task.ThreadPoolTaskExecutorBuilder; import org.springframework.core.task.AsyncTaskExecutor; +import java.util.Objects; import java.util.concurrent.CompletableFuture; import java.util.concurrent.Executor; import java.util.function.Supplier; @@ -18,12 +19,26 @@ */ public class AsyncHelper { - protected static Executor AsyncExecutor; - protected static AsyncTaskExecutor AppTaskExecutor; + private static Executor AsyncExecutor = null; + private static AsyncTaskExecutor AppTaskExecutor = null; + private static ThreadPoolTaskExecutorBuilder ExecutorBuilder; + private static AsyncTaskExecutor LiteExecutor; + private static boolean helperPrepared = false; - protected AsyncHelper(Executor asy, AsyncTaskExecutor app) { - AsyncExecutor = asy; - AppTaskExecutor = app; + protected AsyncHelper(@NotNull Executor async, @NotNull AsyncTaskExecutor appTask, + @NotNull ThreadPoolTaskExecutorBuilder builder, @NotNull AsyncTaskExecutor lite) { + AsyncExecutor = Objects.requireNonNull(async); + AppTaskExecutor = Objects.requireNonNull(appTask); + ExecutorBuilder = Objects.requireNonNull(builder); + LiteExecutor = Objects.requireNonNull(lite); + helperPrepared = true; + } + + /** + * whether this helper is prepared + */ + public static boolean isPrepared() { + return helperPrepared; } /** @@ -63,11 +78,6 @@ public static AsyncTaskExecutor AppTask() { return AppTaskExecutor; } - - protected static ThreadPoolTaskExecutorBuilder ExecutorBuilder; - protected static AsyncTaskExecutor LiteExecutor; - - /** * @see org.springframework.scheduling.annotation.AsyncAnnotationBeanPostProcessor#DEFAULT_TASK_EXECUTOR_BEAN_NAME */ diff --git a/wings/slardar/src/main/java/pro/fessional/wings/slardar/async/TaskSchedulerHelper.java b/wings/slardar/src/main/java/pro/fessional/wings/slardar/async/TaskSchedulerHelper.java index 697059b8d..64c768c16 100644 --- a/wings/slardar/src/main/java/pro/fessional/wings/slardar/async/TaskSchedulerHelper.java +++ b/wings/slardar/src/main/java/pro/fessional/wings/slardar/async/TaskSchedulerHelper.java @@ -7,6 +7,7 @@ import pro.fessional.mirana.time.ThreadNow; import java.time.Instant; +import java.util.Objects; import java.util.concurrent.ScheduledFuture; /** @@ -15,12 +16,28 @@ */ public class TaskSchedulerHelper { - protected static ThreadPoolTaskScheduler FastScheduler; - protected static ThreadPoolTaskScheduler ScheduledScheduler; + private static ThreadPoolTaskScheduler FastScheduler; + private static ThreadPoolTaskScheduler ScheduledScheduler; + private static ThreadPoolTaskSchedulerBuilder FastBuilder; + private static ThreadPoolTaskSchedulerBuilder ScheduledBuilder; + private static boolean helperPrepared = false; - protected TaskSchedulerHelper(ThreadPoolTaskScheduler fast, ThreadPoolTaskScheduler scheduled) { - FastScheduler = fast; - ScheduledScheduler = scheduled; + + protected TaskSchedulerHelper(@NotNull ThreadPoolTaskScheduler fast, @NotNull ThreadPoolTaskScheduler scheduled, + @NotNull ThreadPoolTaskSchedulerBuilder fastBuilder, @NotNull ThreadPoolTaskSchedulerBuilder scheduledBuilder) { + FastScheduler = Objects.requireNonNull(fast); + ScheduledScheduler = Objects.requireNonNull(scheduled); + FastBuilder = Objects.requireNonNull(fastBuilder); + ScheduledBuilder = Objects.requireNonNull(scheduledBuilder); + helperPrepared = true; + } + + + /** + * whether this helper is prepared + */ + public static boolean isPrepared() { + return helperPrepared; } /** @@ -89,9 +106,6 @@ public static ScheduledFuture Scheduled(Trigger trigger, @NotNull Runnable ta return Scheduled().schedule(task, trigger); } - protected static ThreadPoolTaskSchedulerBuilder FastBuilder; - protected static ThreadPoolTaskSchedulerBuilder ScheduledBuilder; - /** * Get Light ThreadPoolTaskSchedulerBuilder, IllegalStateException if nonull but null. */ diff --git a/wings/slardar/src/main/java/pro/fessional/wings/slardar/cache/WingsCacheHelper.java b/wings/slardar/src/main/java/pro/fessional/wings/slardar/cache/WingsCacheHelper.java index 7362e3110..5b8da98bb 100644 --- a/wings/slardar/src/main/java/pro/fessional/wings/slardar/cache/WingsCacheHelper.java +++ b/wings/slardar/src/main/java/pro/fessional/wings/slardar/cache/WingsCacheHelper.java @@ -29,8 +29,34 @@ public class WingsCacheHelper { private static final Map NameManager = new ConcurrentHashMap<>(); private static final Map> ManagerName = new ConcurrentHashMap<>(); - private static CacheManager MemoryManager; - private static CacheManager ServerManager; + private static CacheManager MemoryManager = null; + private static CacheManager ServerManager = null; + private static boolean helperPrepared = false; + + + /** + * Set CacheManager name and its Resolver + */ + protected WingsCacheHelper(Map mngs) { + NameManager.putAll(mngs); + + MemoryManager = NameManager.get(WingsCache.Manager.Memory); + ServerManager = NameManager.get(WingsCache.Manager.Server); + + ManagerName.clear(); + for (Map.Entry en : NameManager.entrySet()) { + ManagerName.computeIfAbsent(en.getValue(), k -> new HashSet<>()) + .add(en.getKey()); + } + helperPrepared = true; + } + + /** + * whether this helper is prepared + */ + public static boolean isPrepared() { + return helperPrepared; + } @Nullable public static CacheManager getCacheManager(String name) { @@ -68,22 +94,6 @@ public static Cache getServerCache(String name) { return cache; } - /** - * Set CacheManager name and its Resolver - */ - public static void putManagers(Map mngs) { - NameManager.putAll(mngs); - - MemoryManager = NameManager.get(WingsCache.Manager.Memory); - ServerManager = NameManager.get(WingsCache.Manager.Server); - - ManagerName.clear(); - for (Map.Entry en : NameManager.entrySet()) { - ManagerName.computeIfAbsent(en.getValue(), k -> new HashSet<>()) - .add(en.getKey()); - } - } - @NotNull public static CacheManager getMemory() { AssertState.notNull(MemoryManager, "Memory CacheManager is null"); @@ -212,8 +222,9 @@ public static Map> getCaches(Class claz, String method) { return mt == null ? emptyMap() : mt.getCaches(); } - public static void setOperation(Method method, Collection opr) { + public static void prepareOperation(Method method, Collection opr) { if (opr == null || opr.isEmpty()) return; + final Map entry = ClassCacheMeta.computeIfAbsent(method.getDeclaringClass(), k -> new ConcurrentHashMap<>()); final Meta top = entry.computeIfAbsent(Null.Str, k -> new Meta()); final Meta mod = entry.computeIfAbsent(method.getName(), k -> new Meta()); diff --git a/wings/slardar/src/main/java/pro/fessional/wings/slardar/cache/spring/WingsCacheAnnoOprSource.java b/wings/slardar/src/main/java/pro/fessional/wings/slardar/cache/spring/WingsCacheAnnoOprSource.java index 87c282e9f..6ddcef48e 100644 --- a/wings/slardar/src/main/java/pro/fessional/wings/slardar/cache/spring/WingsCacheAnnoOprSource.java +++ b/wings/slardar/src/main/java/pro/fessional/wings/slardar/cache/spring/WingsCacheAnnoOprSource.java @@ -17,7 +17,7 @@ public class WingsCacheAnnoOprSource extends AnnotationCacheOperationSource { @Override protected Collection findCacheOperations(@NotNull Method method) { final Collection ops = super.findCacheOperations(method); - WingsCacheHelper.setOperation(method, ops); + WingsCacheHelper.prepareOperation(method, ops); return ops; } } diff --git a/wings/slardar/src/main/java/pro/fessional/wings/slardar/event/EventPublishHelper.java b/wings/slardar/src/main/java/pro/fessional/wings/slardar/event/EventPublishHelper.java index 6ac0728be..455c688ef 100644 --- a/wings/slardar/src/main/java/pro/fessional/wings/slardar/event/EventPublishHelper.java +++ b/wings/slardar/src/main/java/pro/fessional/wings/slardar/event/EventPublishHelper.java @@ -49,7 +49,7 @@ public class EventPublishHelper { *

* throws IllegalStateException if no globalPublisher * - * @see #hasAsyncGlobal + * @see #isPreparedGlobal */ public static final ApplicationEventPublisher AsyncGlobal = new GlobalPub(true); @@ -61,24 +61,48 @@ public class EventPublishHelper { */ public static final ApplicationEventPublisher AsyncWidely = new GlobalPub(false); - private static Executor executor; + private static Executor asyncExecutor; private static ApplicationEventPublisher springPublisher; private static ApplicationEventPublisher globalPublisher; - public static void setGlobalPublisher(ApplicationEventPublisher globalPublisher) { - EventPublishHelper.globalPublisher = globalPublisher; + public static void prepareAsyncExecutor(@NotNull Executor async) { + asyncExecutor = async; } - public static void setExecutor(Executor executor) { - EventPublishHelper.executor = executor; + public static void prepareSpringPublisher(@NotNull ApplicationEventPublisher spring) { + springPublisher = spring; } - public static void setSpringPublisher(ApplicationEventPublisher springPublisher) { - EventPublishHelper.springPublisher = springPublisher; + public static void prepareGlobalPublisher(@NotNull ApplicationEventPublisher global) { + globalPublisher = global; } - public static boolean hasAsyncGlobal() { - return globalPublisher != null; + /** + * whether global is prepared + */ + public static boolean isPreparedGlobal() { + return globalPublisher != null && asyncExecutor != null; + } + + /** + * whether app async is prepared + */ + public static boolean isPreparedAsync() { + return springPublisher != null && asyncExecutor != null; + } + + /** + * whether app sync is prepared + */ + public static boolean isPreparedSync() { + return springPublisher != null; + } + + /** + * whether this helper is fully prepared + */ + public static boolean isPrepared() { + return springPublisher != null && globalPublisher != null && asyncExecutor != null; } private static class SyncPub implements ApplicationEventPublisher { @@ -93,7 +117,7 @@ private static class AsyncPub implements ApplicationEventPublisher { @Override public void publishEvent(@NotNull Object event) { - executor.execute(() -> springPublisher.publishEvent(event)); + asyncExecutor.execute(() -> springPublisher.publishEvent(event)); } } @@ -105,7 +129,7 @@ private static class GlobalPub implements ApplicationEventPublisher { @Override public void publishEvent(@NotNull Object event) { if (globalPublisher != null) { - executor.execute(() -> globalPublisher.publishEvent(event)); + asyncExecutor.execute(() -> globalPublisher.publishEvent(event)); } else { if (strict) { @@ -114,7 +138,7 @@ public void publishEvent(@NotNull Object event) { else { log.warn("no globalPublisher, publish by spring async in no strict"); } - executor.execute(() -> springPublisher.publishEvent(event)); + asyncExecutor.execute(() -> springPublisher.publishEvent(event)); } } } diff --git a/wings/slardar/src/main/java/pro/fessional/wings/slardar/jackson/JacksonHelper.java b/wings/slardar/src/main/java/pro/fessional/wings/slardar/jackson/JacksonHelper.java index 97dc507cb..79a31d93a 100644 --- a/wings/slardar/src/main/java/pro/fessional/wings/slardar/jackson/JacksonHelper.java +++ b/wings/slardar/src/main/java/pro/fessional/wings/slardar/jackson/JacksonHelper.java @@ -204,26 +204,32 @@ public static T buildWings(@NotNull T mapper) { private static ObjectMapper JsonWings = JsonPlain; private static XmlMapper XmlWings = XmlPlain; + private static boolean wingsPrepared = false; - protected static void bindJsonWings(@NotNull ObjectMapper mapper) { - JsonWings = buildWings(mapper); + protected static void prepareWings(@NotNull ObjectMapper json, @NotNull XmlMapper xml) { + JsonWings = buildWings(json); + XmlWings = buildWings(xml); + wingsPrepared = true; } - protected static void bindXmlWings(@NotNull XmlMapper mapper) { - XmlWings = buildWings(mapper); - } private static ObjectMapper JsonBean = null; private static XmlMapper XmlBean = null; + private static boolean beanPrepared = false; - protected static void bindJsonBean(@NotNull ObjectMapper mapper) { - JsonBean = mapper; + protected static void prepareBean(@NotNull ObjectMapper json, @NotNull XmlMapper xml) { + JsonBean = json; + XmlBean = xml; + beanPrepared = true; } - protected static void bindXmlBean(@NotNull XmlMapper mapper) { - XmlBean = mapper; + public static boolean isPrepared(@NotNull Style style) { + return switch (style) { + case Plain -> true; + case Wings -> wingsPrepared; + case Bean -> beanPrepared; + }; } - //// /** diff --git a/wings/slardar/src/main/java/pro/fessional/wings/slardar/spring/bean/SlardarAsyncConfiguration.java b/wings/slardar/src/main/java/pro/fessional/wings/slardar/spring/bean/SlardarAsyncConfiguration.java index 23b9d4ac6..d266b4065 100644 --- a/wings/slardar/src/main/java/pro/fessional/wings/slardar/spring/bean/SlardarAsyncConfiguration.java +++ b/wings/slardar/src/main/java/pro/fessional/wings/slardar/spring/bean/SlardarAsyncConfiguration.java @@ -123,10 +123,7 @@ public TaskSchedulerHelper taskSchedulerHelper( @Qualifier(DEFAULT_TASK_SCHEDULER_BEAN_NAME) ThreadPoolTaskScheduler scheduled, ThreadPoolTaskSchedulerBuilder scheduledBuilder) { log.info("Slardar spring-bean taskSchedulerHelper"); - return new TaskSchedulerHelper(scheduled, fast) {{ - FastBuilder = fastSchedulerBuilder; - ScheduledBuilder = scheduledBuilder; - }}; + return new TaskSchedulerHelper(scheduled, fast, fastSchedulerBuilder, scheduledBuilder) {}; } @Bean @@ -143,9 +140,6 @@ public AsyncHelper asyncHelper( final Executor exec = TtlExecutors.getTtlExecutor(executor); AsyncTaskExecutor liteExecutor = new ConcurrentTaskExecutor(exec); - return new AsyncHelper(asyncExec, appExec) {{ - ExecutorBuilder = executorBuilder; - LiteExecutor = liteExecutor; - }}; + return new AsyncHelper(asyncExec, appExec, executorBuilder, liteExecutor) {}; } } diff --git a/wings/slardar/src/main/java/pro/fessional/wings/slardar/spring/bean/SlardarCacheConfiguration.java b/wings/slardar/src/main/java/pro/fessional/wings/slardar/spring/bean/SlardarCacheConfiguration.java index bbbcecd39..e31d24d9e 100644 --- a/wings/slardar/src/main/java/pro/fessional/wings/slardar/spring/bean/SlardarCacheConfiguration.java +++ b/wings/slardar/src/main/java/pro/fessional/wings/slardar/spring/bean/SlardarCacheConfiguration.java @@ -125,7 +125,7 @@ public CacheManager cacheManager() { } // name or resolver name - WingsCacheHelper.putManagers(managerMap); + new WingsCacheHelper(managerMap){}; CacheManager pre = null; String cnm = null; diff --git a/wings/slardar/src/main/java/pro/fessional/wings/slardar/spring/bean/SlardarEventConfiguration.java b/wings/slardar/src/main/java/pro/fessional/wings/slardar/spring/bean/SlardarEventConfiguration.java index f38106ad9..b03c59212 100644 --- a/wings/slardar/src/main/java/pro/fessional/wings/slardar/spring/bean/SlardarEventConfiguration.java +++ b/wings/slardar/src/main/java/pro/fessional/wings/slardar/spring/bean/SlardarEventConfiguration.java @@ -64,9 +64,9 @@ public ApplicationStartedEventRunner eventPublishHelperRunner( @Qualifier(slardarEventExecutor) Executor executor) { log.info("Slardar spring-runs eventPublishHelperRunner"); return new ApplicationStartedEventRunner(WingsOrdered.Lv4Application, ignored -> { - EventPublishHelper.setExecutor(executor); + EventPublishHelper.prepareAsyncExecutor(executor); log.info("Slardar conf eventPublishHelper ApplicationEventPublisher=" + publisher.getClass()); - EventPublishHelper.setSpringPublisher(publisher); + EventPublishHelper.prepareSpringPublisher(publisher); log.info("Slardar conf eventPublishHelper ApplicationEventMulticaster=" + multicaster.getClass()); if (multicaster instanceof SimpleApplicationEventMulticaster mc) { try { diff --git a/wings/warlock/src/main/java/pro/fessional/wings/warlock/spring/bean/WarlockTableChangeConfiguration.java b/wings/warlock/src/main/java/pro/fessional/wings/warlock/spring/bean/WarlockTableChangeConfiguration.java index 747d9390a..30f535b23 100644 --- a/wings/warlock/src/main/java/pro/fessional/wings/warlock/spring/bean/WarlockTableChangeConfiguration.java +++ b/wings/warlock/src/main/java/pro/fessional/wings/warlock/spring/bean/WarlockTableChangeConfiguration.java @@ -2,7 +2,6 @@ import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; -import org.springframework.context.ApplicationEventPublisher; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import pro.fessional.wings.faceless.spring.bean.FacelessJooqCudConfiguration; @@ -25,17 +24,8 @@ public class WarlockTableChangeConfiguration { @Bean @ConditionalWingsEnabled public TableChangePublisherImpl tableChangePublisher() { - log.info("Warlock spring-bean tableChangePublisher"); - final ApplicationEventPublisher publisher; - if (EventPublishHelper.hasAsyncGlobal()) { - publisher = EventPublishHelper.AsyncGlobal; - log.info("Warlock conf tableChangePublisher with async global"); - } - else { - publisher = EventPublishHelper.AsyncSpring; - log.info("Warlock conf tableChangePublisher with async spring"); - } - return new TableChangePublisherImpl(publisher); + log.info("Warlock spring-bean tableChangePublisher with AsyncWidely Publisher"); + return new TableChangePublisherImpl(EventPublishHelper.AsyncWidely); } @Bean From e606e6a9459214d0fb4f68e129eed6bf9665f825 Mon Sep 17 00:00:00 2001 From: trydofor Date: Sat, 6 Jul 2024 12:20:56 +0800 Subject: [PATCH 15/51] =?UTF-8?q?=E2=9C=A8=20inspect=20DatabaseChecker=20r?= =?UTF-8?q?evision=20#259?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../faceless/spring/prop/FlywaveVerProp.java | 2 +- .../flywave/impl/MySqlStatementParser.kt | 16 +++--------- .../database/helper/DatabaseChecker.java | 26 +++++++++++++++---- .../database/helper/JdbcTemplateHelper.java | 13 +++++++++- .../spring/bean/FacelessConfiguration.java | 4 +-- .../helper/JdbcTemplateHelperTest.java | 4 +++ .../bean/SilencerCurseConfiguration.java | 15 ++++++----- .../bean/WarlockAutoRunConfiguration.java | 6 ++--- 8 files changed, 54 insertions(+), 32 deletions(-) diff --git a/wings/faceless-flywave/src/main/java/pro/fessional/wings/faceless/spring/prop/FlywaveVerProp.java b/wings/faceless-flywave/src/main/java/pro/fessional/wings/faceless/spring/prop/FlywaveVerProp.java index c7d91ead8..07e3a3a76 100644 --- a/wings/faceless-flywave/src/main/java/pro/fessional/wings/faceless/spring/prop/FlywaveVerProp.java +++ b/wings/faceless-flywave/src/main/java/pro/fessional/wings/faceless/spring/prop/FlywaveVerProp.java @@ -31,7 +31,7 @@ public class FlywaveVerProp { * @see #Key$schemaVersionTable */ private String schemaVersionTable = "sys_schema_version"; - public static final String Key$schemaVersionTable = Key + ".schema-version-table"; + public static final String Key$schemaVersionTable = Key + ".schema-version-table"; // refer by database checker /** * table name of journal. diff --git a/wings/faceless-flywave/src/main/kotlin/pro/fessional/wings/faceless/flywave/impl/MySqlStatementParser.kt b/wings/faceless-flywave/src/main/kotlin/pro/fessional/wings/faceless/flywave/impl/MySqlStatementParser.kt index 512bed891..7a19a7be7 100644 --- a/wings/faceless-flywave/src/main/kotlin/pro/fessional/wings/faceless/flywave/impl/MySqlStatementParser.kt +++ b/wings/faceless-flywave/src/main/kotlin/pro/fessional/wings/faceless/flywave/impl/MySqlStatementParser.kt @@ -4,6 +4,7 @@ import org.slf4j.LoggerFactory import pro.fessional.mirana.bits.Bytes import pro.fessional.mirana.data.Null import pro.fessional.mirana.time.DateFormatter +import pro.fessional.wings.faceless.database.helper.JdbcTemplateHelper import pro.fessional.wings.faceless.flywave.SqlStatementParser import java.time.LocalDate import java.time.LocalDateTime @@ -94,7 +95,7 @@ class MySqlStatementParser : SqlStatementParser { } override fun parseTypeAndTable(sql: String): SqlStatementParser.SqlType { - if(sql.startsWith("SELECT ",true)) { + if (sql.startsWith("SELECT ", true)) { return SqlStatementParser.SqlType.Other } @@ -124,18 +125,7 @@ class MySqlStatementParser : SqlStatementParser { return SqlStatementParser.SqlType.Other } - override fun safeName(str: String): String { - val i1 = str.indexOf('`') - if (i1 >= 0) { - val i2 = str.lastIndexOf('`') - return if (i1 == 0 && i2 == str.length - 1) { - str - } else { - "`${str.replaceAfter("`", "")}`" - } - } - return "`$str`" - } + override fun safeName(str: String): String = JdbcTemplateHelper.safeName(str) // https://dev.mysql.com/doc/refman/8.0/en/string-literals.html#character-escape-sequences override fun safeValue(obj: Any?): String { diff --git a/wings/faceless/src/main/java/pro/fessional/wings/faceless/database/helper/DatabaseChecker.java b/wings/faceless/src/main/java/pro/fessional/wings/faceless/database/helper/DatabaseChecker.java index 93e908214..fcd678bcf 100644 --- a/wings/faceless/src/main/java/pro/fessional/wings/faceless/database/helper/DatabaseChecker.java +++ b/wings/faceless/src/main/java/pro/fessional/wings/faceless/database/helper/DatabaseChecker.java @@ -2,13 +2,16 @@ import lombok.SneakyThrows; import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; import org.jetbrains.annotations.NotNull; import org.springframework.dao.DataAccessException; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.jdbc.support.JdbcUtils; +import pro.fessional.mirana.best.DummyBlock; import pro.fessional.mirana.time.DateFormatter; import pro.fessional.mirana.time.DateParser; import pro.fessional.wings.faceless.database.DataSourceContext; +import pro.fessional.wings.silencer.spring.help.ApplicationContextHelper; import javax.sql.DataSource; import java.sql.Connection; @@ -113,7 +116,9 @@ public static void timezone(DataSource ds, int off, boolean fail) { sb.append("\njvm-zone-offset=").append(ZoneOffset.ofTotalSeconds(jvOff)); if (Math.abs(jvOff) <= Math.abs(off) && Math.abs(dbOff) <= Math.abs(off)) { - log.info(sb.substring(1).replace("\n", ", ")); + for (String s : sb.substring(1).split("\n")) { + log.info(s); + } return; } @@ -137,18 +142,29 @@ public static void timezone(DataSource ds, int off, boolean fail) { } /** - * output the database version in the log + * output the database version in the log, return flywave revision if found */ - public static long version(DataSource ds) { final JdbcTemplate tmpl = new JdbcTemplate(ds); + log.info("jdbcurl={}", DataSourceContext.extractUrl(ds)); final String ver = isH2(ds) ? "H2VERSION()" : "VERSION()"; tmpl.query("SELECT " + ver + " FROM dual", rs -> { - log.info("{}={}, primary={}", ver, rs.getString(1), DataSourceContext.extractUrl(ds)); + log.info("database {}={}", ver, rs.getString(1)); }); - String sql = "SELECT MAX(revision) FROM sys_schema_version WHERE apply_dt > '1111-11-11'"; + String reviTable = null; + try { + reviTable = ApplicationContextHelper.getProperties("wings.faceless.flywave.ver.schema-version-table"); + } + catch (Exception e) { + DummyBlock.ignore(e); + } + if (StringUtils.isBlank(reviTable)) { + reviTable = "sys_schema_version"; + } + + String sql = "SELECT MAX(revision) FROM " + JdbcTemplateHelper.safeName(reviTable) + " WHERE apply_dt > '1111-11-11'"; Long rev = null; try { rev = tmpl.query(sql, JdbcTemplateHelper.FirstLongOrNull); diff --git a/wings/faceless/src/main/java/pro/fessional/wings/faceless/database/helper/JdbcTemplateHelper.java b/wings/faceless/src/main/java/pro/fessional/wings/faceless/database/helper/JdbcTemplateHelper.java index e347558da..cf3290272 100644 --- a/wings/faceless/src/main/java/pro/fessional/wings/faceless/database/helper/JdbcTemplateHelper.java +++ b/wings/faceless/src/main/java/pro/fessional/wings/faceless/database/helper/JdbcTemplateHelper.java @@ -76,7 +76,18 @@ public static String safeWhere(String where) { * in mysql (not ANSI_QUOTES), return `table` */ @NotNull - protected static Function Quotes = (String name) -> "`" + name + "`"; + protected static Function Quotes = (String name) -> { + int pos0 = name.indexOf('`'); + if (pos0 >= 0) { + int pos1 = name.lastIndexOf('`'); + if(pos0 == 0 && pos1 == name.length() -1) { + int pos = name.indexOf('`', pos0 + 1, pos1); + if(pos < 0) return name; + } + name = name.replace("`",""); + } + return "`" + name + "`"; + }; public static void initSafeTable(JdbcTemplate tmpl) { tmpl.query(ShowTableSql, rs -> { diff --git a/wings/faceless/src/main/java/pro/fessional/wings/faceless/spring/bean/FacelessConfiguration.java b/wings/faceless/src/main/java/pro/fessional/wings/faceless/spring/bean/FacelessConfiguration.java index 5692589d6..31ed50c89 100644 --- a/wings/faceless/src/main/java/pro/fessional/wings/faceless/spring/bean/FacelessConfiguration.java +++ b/wings/faceless/src/main/java/pro/fessional/wings/faceless/spring/bean/FacelessConfiguration.java @@ -49,10 +49,10 @@ public DataSourceContext dataSourceContext(DataSource current, List if (md) break; } - log.info("Faceless🦄 database-current-url=" + ctx.cacheJdbcUrl(ctx.getCurrent())); + log.info("Faceless🦄 database Current-jdbcurl=" + ctx.cacheJdbcUrl(ctx.getCurrent())); Map backends = ctx.getBackends(); for (Map.Entry e : backends.entrySet()) { - log.info("Faceless🦄 initSafeTable database-" + e.getKey() + "-url=" + ctx.cacheJdbcUrl(e.getValue())); + log.info("Faceless🦄 initSafeTable database " + e.getKey() + "-jdbcurl=" + ctx.cacheJdbcUrl(e.getValue())); JdbcTemplateHelper.initSafeTable(new JdbcTemplate(e.getValue())); } diff --git a/wings/faceless/src/test/java/pro/fessional/wings/faceless/database/helper/JdbcTemplateHelperTest.java b/wings/faceless/src/test/java/pro/fessional/wings/faceless/database/helper/JdbcTemplateHelperTest.java index 997ead8f4..c174f4eee 100644 --- a/wings/faceless/src/test/java/pro/fessional/wings/faceless/database/helper/JdbcTemplateHelperTest.java +++ b/wings/faceless/src/test/java/pro/fessional/wings/faceless/database/helper/JdbcTemplateHelperTest.java @@ -25,6 +25,10 @@ class JdbcTemplateHelperTest { @Test @TmsLink("12148") void safeTable() { + assertEquals("`sys_light_sequence`",JdbcTemplateHelper.safeName("sys_light_sequence")); + assertEquals("`sys_light_sequence`",JdbcTemplateHelper.safeName("`sys_light_sequence`")); + assertEquals("`sys_light_sequence`",JdbcTemplateHelper.safeName("`sys_light``_sequence`")); + // init the context assertNotNull(sourceContext); diff --git a/wings/silencer-curse/src/main/java/pro/fessional/wings/silencer/spring/bean/SilencerCurseConfiguration.java b/wings/silencer-curse/src/main/java/pro/fessional/wings/silencer/spring/bean/SilencerCurseConfiguration.java index f0a0bcdcd..f291720c4 100644 --- a/wings/silencer-curse/src/main/java/pro/fessional/wings/silencer/spring/bean/SilencerCurseConfiguration.java +++ b/wings/silencer-curse/src/main/java/pro/fessional/wings/silencer/spring/bean/SilencerCurseConfiguration.java @@ -21,10 +21,10 @@ import pro.fessional.wings.silencer.spring.WingsOrdered; import pro.fessional.wings.silencer.spring.boot.ConditionalWingsEnabled; import pro.fessional.wings.silencer.spring.help.ApplicationContextHelper; -import pro.fessional.wings.silencer.support.InspectHelper; import pro.fessional.wings.silencer.spring.prop.SilencerAutoLogProp; import pro.fessional.wings.silencer.spring.prop.SilencerEnabledProp; import pro.fessional.wings.silencer.spring.prop.SilencerRuntimeProp; +import pro.fessional.wings.silencer.support.InspectHelper; import java.util.ArrayList; import java.util.HashSet; @@ -84,12 +84,6 @@ public ApplicationInspectRunner auditPropRunner() { public ApplicationInspectRunner infoGitJvmRunner(ApplicationContext context) { log.info("Silencer spring-runs infoGitJvmRunner"); return new ApplicationInspectRunner(WingsOrdered.Lv1Config, args -> { - - - log.info("jvm-name=" + InspectHelper.jvmName()); - log.info("jvm-version=" + InspectHelper.jvmVersion()); - log.info("jvm-vendor=" + InspectHelper.jvmVendor()); - var git = context.getBean(GitProperties.class); log.info("git-branch=" + InspectHelper.branch(git)); log.info("git-id=" + InspectHelper.commitId(git)); @@ -97,6 +91,13 @@ public ApplicationInspectRunner infoGitJvmRunner(ApplicationContext context) { log.info("git-build=" + InspectHelper.buildDateTime(git)); log.info("git-version=" + InspectHelper.buildVersion(git)); log.info("git-message=" + InspectHelper.commitMessage(git)); + + log.info("jvm-name=" + InspectHelper.jvmName()); + log.info("jvm-version=" + InspectHelper.jvmVersion()); + log.info("jvm-vendor=" + InspectHelper.jvmVendor()); + + log.info("app-ApiMode=" + RuntimeMode.getApiMode()); + log.info("app-RunMode=" + RuntimeMode.getRunMode()); }); } diff --git a/wings/warlock/src/main/java/pro/fessional/wings/warlock/spring/bean/WarlockAutoRunConfiguration.java b/wings/warlock/src/main/java/pro/fessional/wings/warlock/spring/bean/WarlockAutoRunConfiguration.java index e1f8733fa..cb7ed45cc 100644 --- a/wings/warlock/src/main/java/pro/fessional/wings/warlock/spring/bean/WarlockAutoRunConfiguration.java +++ b/wings/warlock/src/main/java/pro/fessional/wings/warlock/spring/bean/WarlockAutoRunConfiguration.java @@ -10,8 +10,8 @@ import pro.fessional.wings.faceless.enums.StandardLanguageEnum; import pro.fessional.wings.faceless.enums.StandardTimezoneEnum; import pro.fessional.wings.faceless.enums.TimezoneEnumUtil; +import pro.fessional.wings.silencer.runner.ApplicationInspectRunner; import pro.fessional.wings.silencer.runner.ApplicationStartedEventRunner; -import pro.fessional.wings.silencer.runner.CommandLineRunnerOrdered; import pro.fessional.wings.silencer.spring.WingsOrdered; import pro.fessional.wings.silencer.spring.boot.ConditionalWingsEnabled; import pro.fessional.wings.warlock.spring.prop.WarlockCheckProp; @@ -34,9 +34,9 @@ public class WarlockAutoRunConfiguration { */ @Bean @ConditionalWingsEnabled - public CommandLineRunnerOrdered databaseCheckerRunner(DataSource dataSource, WarlockCheckProp prop) { + public ApplicationInspectRunner databaseCheckerRunner(DataSource dataSource, WarlockCheckProp prop) { log.info("Warlock spring-runs databaseCheckerRunner"); - return new CommandLineRunnerOrdered(WingsOrdered.Lv2Resource, ignored -> { + return new ApplicationInspectRunner(WingsOrdered.Lv2Resource, ignored -> { DatabaseChecker.version(dataSource); DatabaseChecker.timezone(dataSource, prop.getTzOffset(), prop.isTzFail()); }); From 170c3783c14aba8f4f36571ce89d653bd7bef2e2 Mon Sep 17 00:00:00 2001 From: trydofor Date: Sun, 7 Jul 2024 19:58:56 +0800 Subject: [PATCH 16/51] =?UTF-8?q?=E2=9C=A8=20flywave=20PROCEDURE=20for=20r?= =?UTF-8?q?evi=20#269?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../master/00-init/2022-0222u01-demo-init.sql | 2 ++ .../master/00-init/2022-0222v01-demo-init.sql | 2 ++ observe/docs | 2 +- .../07-mail/2020-10-27u01-tiny_mail.sql | 1 + .../07-mail/2020-10-27v01-tiny_mail.sql | 2 ++ .../03-task-tune/2021-10-26u02-task-tune.sql | 2 ++ .../03-task-tune/2021-10-26v02-task-tune.sql | 2 ++ .../06-task/2020-10-26u01-tiny_task.sql | 1 + .../06-task/2020-10-26v01-tiny_task.sql | 2 ++ .../2019-05-12u02-version-add-column.sql | 2 ++ .../2019-05-12v02-version-add-column.sql | 2 ++ .../2021-12-20u01-journal-trg-insert.sql | 2 ++ .../2021-12-20v01-journal-trg-insert.sql | 2 ++ .../manual-revision-procedure.sql | 21 +++++++++++++++++++ .../00-init/2019-05-12v01-version-journal.sql | 8 +++---- .../01-enum-i18n/2019-05-21u01-enum-i18n.sql | 2 ++ .../01-enum-i18n/2019-05-21v01-enum-i18n.sql | 2 ++ .../2021-10-26u05-journal-elapse.sql | 4 +++- .../2021-10-26v05-journal-elapse.sql | 4 +++- .../01-light/2019-05-20u01-light-commit.sql | 2 ++ .../01-light/2019-05-20v01-light-commit.sql | 2 ++ .../master/2022-0601u01-test.sql | 2 ++ .../master/2022-0601u02-test.sql | 2 ++ .../master/2022-0601v01-test.sql | 2 ++ .../master/2022-0601v02-test.sql | 2 ++ .../2021-09-18u01-rename-authn.sql | 2 ++ .../2021-09-18v01-rename-authn.sql | 2 ++ .../04-conf-size/2021-10-26u03-conf-size.sql | 2 ++ .../04-conf-size/2021-10-26v03-conf-size.sql | 2 ++ .../03-enum/2020-10-23v01-auth_enum.sql | 2 ++ .../04-auth/2020-10-24u01-user_login.sql | 2 ++ .../04-auth/2020-10-24u02-role_permit.sql | 2 ++ .../04-auth/2020-10-24v01-user_login.sql | 2 ++ .../04-auth/2020-10-24v02-role_permit.sql | 2 ++ .../05-conf/2020-10-25u01-conf_runtime.sql | 1 + .../05-conf/2020-10-25v01-conf_runtime.sql | 2 ++ 36 files changed, 91 insertions(+), 7 deletions(-) create mode 100644 wings/faceless-flywave/src/main/resources/wings-flywave/manual-revision-procedure.sql diff --git a/example/winx-common/src/main/resources/wings-flywave/master/00-init/2022-0222u01-demo-init.sql b/example/winx-common/src/main/resources/wings-flywave/master/00-init/2022-0222u01-demo-init.sql index b11449786..660325bc6 100644 --- a/example/winx-common/src/main/resources/wings-flywave/master/00-init/2022-0222u01-demo-init.sql +++ b/example/winx-common/src/main/resources/wings-flywave/master/00-init/2022-0222u01-demo-init.sql @@ -1 +1,3 @@ DROP TABLE IF EXISTS `winx_user_detail`; -- 210/User Detail; + +-- CALL FLYWAVE('2022-0222u01-demo-init.sql'); \ No newline at end of file diff --git a/example/winx-common/src/main/resources/wings-flywave/master/00-init/2022-0222v01-demo-init.sql b/example/winx-common/src/main/resources/wings-flywave/master/00-init/2022-0222v01-demo-init.sql index 5f3213079..02eca9430 100644 --- a/example/winx-common/src/main/resources/wings-flywave/master/00-init/2022-0222v01-demo-init.sql +++ b/example/winx-common/src/main/resources/wings-flywave/master/00-init/2022-0222v01-demo-init.sql @@ -26,3 +26,5 @@ VALUES (2100100, 'user_type', 'user_type', 'User Type', 'classpath:/wings-tmpl/C (2100101, 'user_type', 'customer', 'customer', 'customer'), (2100102, 'user_type', 'operator', 'operator', 'operator'), (2100103, 'user_type', 'helpdesk', 'helpdesk', 'helpdesk'); + +-- CALL FLYWAVE('2022-0222v01-demo-init.sql'); \ No newline at end of file diff --git a/observe/docs b/observe/docs index 8032fd046..fbb1f4817 160000 --- a/observe/docs +++ b/observe/docs @@ -1 +1 @@ -Subproject commit 8032fd046fa1a726ed471625ea34d7ed8fe4a634 +Subproject commit fbb1f4817448a18f6c9bd497c9b5837508d2198e diff --git a/radiant/tiny-mail/src/main/resources/wings-flywave/master/07-mail/2020-10-27u01-tiny_mail.sql b/radiant/tiny-mail/src/main/resources/wings-flywave/master/07-mail/2020-10-27u01-tiny_mail.sql index 7da5da9a4..101848bec 100644 --- a/radiant/tiny-mail/src/main/resources/wings-flywave/master/07-mail/2020-10-27u01-tiny_mail.sql +++ b/radiant/tiny-mail/src/main/resources/wings-flywave/master/07-mail/2020-10-27u01-tiny_mail.sql @@ -1,2 +1,3 @@ DROP TABLE IF EXISTS `win_mail_sender`; -- 124/Mail Sending; +-- CALL FLYWAVE('2020-10-27u01-tiny_mail.sql'); \ No newline at end of file diff --git a/radiant/tiny-mail/src/main/resources/wings-flywave/master/07-mail/2020-10-27v01-tiny_mail.sql b/radiant/tiny-mail/src/main/resources/wings-flywave/master/07-mail/2020-10-27v01-tiny_mail.sql index 358d8ce68..66d25c9cb 100644 --- a/radiant/tiny-mail/src/main/resources/wings-flywave/master/07-mail/2020-10-27v01-tiny_mail.sql +++ b/radiant/tiny-mail/src/main/resources/wings-flywave/master/07-mail/2020-10-27v01-tiny_mail.sql @@ -41,3 +41,5 @@ CREATE TABLE `win_mail_sender` ( INDEX ix_ref_key2 (`ref_key2`) ) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COMMENT ='124/Mail Sending'; + +-- CALL FLYWAVE('2020-10-27v01-tiny_mail.sql'); \ No newline at end of file diff --git a/radiant/tiny-task/src/main/resources/wings-flywave/branch/somefix/03-task-tune/2021-10-26u02-task-tune.sql b/radiant/tiny-task/src/main/resources/wings-flywave/branch/somefix/03-task-tune/2021-10-26u02-task-tune.sql index b2eec67fa..0051cb419 100644 --- a/radiant/tiny-task/src/main/resources/wings-flywave/branch/somefix/03-task-tune/2021-10-26u02-task-tune.sql +++ b/radiant/tiny-task/src/main/resources/wings-flywave/branch/somefix/03-task-tune/2021-10-26u02-task-tune.sql @@ -29,3 +29,5 @@ WHERE exit_fail = 1; ALTER TABLE `win_task_result` DROP COLUMN `exit_fail`; + +-- CALL FLYWAVE('2021-10-26u02-task-tune.sql'); \ No newline at end of file diff --git a/radiant/tiny-task/src/main/resources/wings-flywave/branch/somefix/03-task-tune/2021-10-26v02-task-tune.sql b/radiant/tiny-task/src/main/resources/wings-flywave/branch/somefix/03-task-tune/2021-10-26v02-task-tune.sql index 8b0d17c74..88e5da9ce 100644 --- a/radiant/tiny-task/src/main/resources/wings-flywave/branch/somefix/03-task-tune/2021-10-26v02-task-tune.sql +++ b/radiant/tiny-task/src/main/resources/wings-flywave/branch/somefix/03-task-tune/2021-10-26v02-task-tune.sql @@ -35,3 +35,5 @@ WHERE time_fail > '2000-01-01'; ALTER TABLE `win_task_result` DROP COLUMN `time_fail`; + +-- CALL FLYWAVE('2021-10-26v02-task-tune.sql'); \ No newline at end of file diff --git a/radiant/tiny-task/src/main/resources/wings-flywave/master/06-task/2020-10-26u01-tiny_task.sql b/radiant/tiny-task/src/main/resources/wings-flywave/master/06-task/2020-10-26u01-tiny_task.sql index 8ec767b31..efc6b392f 100644 --- a/radiant/tiny-task/src/main/resources/wings-flywave/master/06-task/2020-10-26u01-tiny_task.sql +++ b/radiant/tiny-task/src/main/resources/wings-flywave/master/06-task/2020-10-26u01-tiny_task.sql @@ -1,3 +1,4 @@ DROP TABLE IF EXISTS `win_task_define`; -- 120/Task Define; DROP TABLE IF EXISTS `win_task_result`; -- 122/Task Result; +-- CALL FLYWAVE('2020-10-26u01-tiny_task.sql'); \ No newline at end of file diff --git a/radiant/tiny-task/src/main/resources/wings-flywave/master/06-task/2020-10-26v01-tiny_task.sql b/radiant/tiny-task/src/main/resources/wings-flywave/master/06-task/2020-10-26v01-tiny_task.sql index 63a43c4a3..c617eec77 100644 --- a/radiant/tiny-task/src/main/resources/wings-flywave/master/06-task/2020-10-26v01-tiny_task.sql +++ b/radiant/tiny-task/src/main/resources/wings-flywave/master/06-task/2020-10-26v01-tiny_task.sql @@ -61,3 +61,5 @@ CREATE TABLE `win_task_result` ( INDEX ix_task_id (`task_id`) ) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COMMENT ='122/Task Result'; + +-- CALL FLYWAVE('2020-10-26v01-tiny_task.sql'); \ No newline at end of file diff --git a/wings/faceless-flywave/src/main/resources/wings-flywave/branch/somefix/01-v227-fix/2019-05-12u02-version-add-column.sql b/wings/faceless-flywave/src/main/resources/wings-flywave/branch/somefix/01-v227-fix/2019-05-12u02-version-add-column.sql index 74359138c..5585fb7d8 100644 --- a/wings/faceless-flywave/src/main/resources/wings-flywave/branch/somefix/01-v227-fix/2019-05-12u02-version-add-column.sql +++ b/wings/faceless-flywave/src/main/resources/wings-flywave/branch/somefix/01-v227-fix/2019-05-12u02-version-add-column.sql @@ -1,3 +1,5 @@ ALTER TABLE `sys_schema_version` DROP COLUMN `comments`, CHANGE COLUMN `apply_dt` `apply_dt` DATETIME(3) NOT NULL DEFAULT '1000-01-01' COMMENT 'applied datetime' AFTER `undo_sql`; + +-- CALL FLYWAVE('2019-05-12u02-version-add-column.sql'); \ No newline at end of file diff --git a/wings/faceless-flywave/src/main/resources/wings-flywave/branch/somefix/01-v227-fix/2019-05-12v02-version-add-column.sql b/wings/faceless-flywave/src/main/resources/wings-flywave/branch/somefix/01-v227-fix/2019-05-12v02-version-add-column.sql index 1fbbbf78d..4b57bb438 100644 --- a/wings/faceless-flywave/src/main/resources/wings-flywave/branch/somefix/01-v227-fix/2019-05-12v02-version-add-column.sql +++ b/wings/faceless-flywave/src/main/resources/wings-flywave/branch/somefix/01-v227-fix/2019-05-12v02-version-add-column.sql @@ -2,3 +2,5 @@ ALTER TABLE `sys_schema_version` CHANGE COLUMN `apply_dt` `apply_dt` DATETIME(3) NOT NULL DEFAULT '1000-01-01' COMMENT 'applied datetime' AFTER `commit_id`, ADD COLUMN `comments` VARCHAR(500) NOT NULL DEFAULT '' COMMENT 'sql path' AFTER `apply_dt`; + +-- CALL FLYWAVE('2019-05-12v02-version-add-column.sql'); \ No newline at end of file diff --git a/wings/faceless-flywave/src/main/resources/wings-flywave/branch/somefix/02-v242-201/2021-12-20u01-journal-trg-insert.sql b/wings/faceless-flywave/src/main/resources/wings-flywave/branch/somefix/02-v242-201/2021-12-20u01-journal-trg-insert.sql index 548422d4b..7cb069f99 100644 --- a/wings/faceless-flywave/src/main/resources/wings-flywave/branch/somefix/02-v242-201/2021-12-20u01-journal-trg-insert.sql +++ b/wings/faceless-flywave/src/main/resources/wings-flywave/branch/somefix/02-v242-201/2021-12-20u01-journal-trg-insert.sql @@ -2,3 +2,5 @@ ALTER TABLE `sys_schema_journal` DROP COLUMN `ddl_instrg`, DROP COLUMN `ddl_instbl`, DROP COLUMN `log_insert`; + +-- CALL FLYWAVE('2021-12-20u01-journal-trg-insert.sql'); \ No newline at end of file diff --git a/wings/faceless-flywave/src/main/resources/wings-flywave/branch/somefix/02-v242-201/2021-12-20v01-journal-trg-insert.sql b/wings/faceless-flywave/src/main/resources/wings-flywave/branch/somefix/02-v242-201/2021-12-20v01-journal-trg-insert.sql index 222a0017c..b66db753e 100644 --- a/wings/faceless-flywave/src/main/resources/wings-flywave/branch/somefix/02-v242-201/2021-12-20v01-journal-trg-insert.sql +++ b/wings/faceless-flywave/src/main/resources/wings-flywave/branch/somefix/02-v242-201/2021-12-20v01-journal-trg-insert.sql @@ -3,3 +3,5 @@ ALTER TABLE `sys_schema_journal` ADD COLUMN `ddl_instbl` TEXT NOT NULL COMMENT 'trace DDL of insert' AFTER `commit_id`, ADD COLUMN `ddl_instrg` TEXT NOT NULL COMMENT 'trigger DDL of insert' AFTER `ddl_instbl`, ADD COLUMN `log_insert` DATETIME(3) NOT NULL DEFAULT '1000-01-01' COMMENT 'applied datetime of insert' AFTER `ddl_deltrg`; + +-- CALL FLYWAVE('2021-12-20v01-journal-trg-insert.sql'); \ No newline at end of file diff --git a/wings/faceless-flywave/src/main/resources/wings-flywave/manual-revision-procedure.sql b/wings/faceless-flywave/src/main/resources/wings-flywave/manual-revision-procedure.sql new file mode 100644 index 000000000..cc2cf4048 --- /dev/null +++ b/wings/faceless-flywave/src/main/resources/wings-flywave/manual-revision-procedure.sql @@ -0,0 +1,21 @@ +-- drop +DROP PROCEDURE IF EXISTS FLYWAVE; + +-- create +DELIMITER $$ +CREATE PROCEDURE FLYWAVE(IN filename VARCHAR(50)) +BEGIN + DECLARE revi VARCHAR(20); + SET revi = REGEXP_REPLACE(REGEXP_SUBSTR(filename, '[-_0-9]{8,}[uv][0-9]{2,}', 1, 1, 'i'), '[^0-9]', ''); + IF REGEXP_LIKE(filename, '[-_0-9]{8,}[v][0-9]{2,}','i') = 1 THEN + INSERT INTO `sys_schema_version` (`revision`, `apply_dt`, `comments`, `commit_id`, `upto_sql`, `undo_sql`) + VALUES (revi, NOW(3), filename, 0, '', '') + ON DUPLICATE KEY UPDATE `apply_dt` = NOW(3); + ELSE + UPDATE `sys_schema_version` + SET `apply_dt` = '1000-01-01', + `modify_dt`= NOW(3) + WHERE `revision` = revi; + END IF; +END$$ +DELIMITER ; diff --git a/wings/faceless-flywave/src/main/resources/wings-flywave/master/00-init/2019-05-12v01-version-journal.sql b/wings/faceless-flywave/src/main/resources/wings-flywave/master/00-init/2019-05-12v01-version-journal.sql index 00a55956f..9b259391d 100644 --- a/wings/faceless-flywave/src/main/resources/wings-flywave/master/00-init/2019-05-12v01-version-journal.sql +++ b/wings/faceless-flywave/src/main/resources/wings-flywave/master/00-init/2019-05-12v01-version-journal.sql @@ -32,11 +32,11 @@ CREATE TABLE `sys_schema_journal` ( ) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COMMENT ='102/Table Trigger'; --- sys_schema_version@plain -INSERT IGNORE INTO `sys_schema_version` (`revision`, `commit_id`, `upto_sql`, `undo_sql`, `apply_dt`) -VALUES (2019051201, 0, '', '', NOW(3)); - -- sys_schema_journal@plain REPLACE INTO `sys_schema_journal` (`table_name`, `commit_id`, `ddl_instbl`, `ddl_instrg`, `ddl_updtbl`, `ddl_updtrg`, `ddl_deltbl`, `ddl_deltrg`) VALUES ('sys_schema_journal', 0, '', '', '', '', '', ''), ('sys_schema_version', 0, '', '', '', '', '', ''); + +-- sys_schema_version@plain +INSERT IGNORE INTO `sys_schema_version` (`revision`, `apply_dt`, `commit_id`,`comments`, `upto_sql`, `undo_sql`) +VALUES (2019051201, NOW(3), 0, 'master/00-init/2019-05-12v01-version-journal.sql', '', ''); diff --git a/wings/faceless/src/main/resources/wings-flywave/branch/feature/01-enum-i18n/2019-05-21u01-enum-i18n.sql b/wings/faceless/src/main/resources/wings-flywave/branch/feature/01-enum-i18n/2019-05-21u01-enum-i18n.sql index 881b470ca..9b331ea08 100644 --- a/wings/faceless/src/main/resources/wings-flywave/branch/feature/01-enum-i18n/2019-05-21u01-enum-i18n.sql +++ b/wings/faceless/src/main/resources/wings-flywave/branch/feature/01-enum-i18n/2019-05-21u01-enum-i18n.sql @@ -1,2 +1,4 @@ DROP TABLE IF EXISTS `sys_constant_enum`; -- 105/Enum and Const; DROP TABLE IF EXISTS `sys_standard_i18n`; -- 106/I18n Message; + +-- CALL FLYWAVE('2019-05-21u01-enum-i18n.sql'); \ No newline at end of file diff --git a/wings/faceless/src/main/resources/wings-flywave/branch/feature/01-enum-i18n/2019-05-21v01-enum-i18n.sql b/wings/faceless/src/main/resources/wings-flywave/branch/feature/01-enum-i18n/2019-05-21v01-enum-i18n.sql index 5bc729d34..41c868073 100644 --- a/wings/faceless/src/main/resources/wings-flywave/branch/feature/01-enum-i18n/2019-05-21v01-enum-i18n.sql +++ b/wings/faceless/src/main/resources/wings-flywave/branch/feature/01-enum-i18n/2019-05-21v01-enum-i18n.sql @@ -179,3 +179,5 @@ VALUES ('sys_constant_enum', 'hint', 'standard_language.zh_CN', 'zh_CN', '简体 ('sys_constant_enum', 'hint', 'standard_language.en_US', 'en_US', 'English(US)'), ('sys_constant_enum', 'hint', 'standard_language.en_US', 'zh_CN', '美国英语'); + +-- CALL FLYWAVE('2019-05-21v01-enum-i18n.sql'); \ No newline at end of file diff --git a/wings/faceless/src/main/resources/wings-flywave/branch/somefix/05-journal-elapse/2021-10-26u05-journal-elapse.sql b/wings/faceless/src/main/resources/wings-flywave/branch/somefix/05-journal-elapse/2021-10-26u05-journal-elapse.sql index ab780dbe8..43ad7e4b5 100644 --- a/wings/faceless/src/main/resources/wings-flywave/branch/somefix/05-journal-elapse/2021-10-26u05-journal-elapse.sql +++ b/wings/faceless/src/main/resources/wings-flywave/branch/somefix/05-journal-elapse/2021-10-26u05-journal-elapse.sql @@ -1,3 +1,5 @@ ALTER TABLE `sys_commit_journal` DROP COLUMN `parent_id`, - DROP COLUMN `elapse_ms`; \ No newline at end of file + DROP COLUMN `elapse_ms`; + +-- CALL FLYWAVE('2021-10-26u05-journal-elapse.sql'); \ No newline at end of file diff --git a/wings/faceless/src/main/resources/wings-flywave/branch/somefix/05-journal-elapse/2021-10-26v05-journal-elapse.sql b/wings/faceless/src/main/resources/wings-flywave/branch/somefix/05-journal-elapse/2021-10-26v05-journal-elapse.sql index 06771a36f..f54232df2 100644 --- a/wings/faceless/src/main/resources/wings-flywave/branch/somefix/05-journal-elapse/2021-10-26v05-journal-elapse.sql +++ b/wings/faceless/src/main/resources/wings-flywave/branch/somefix/05-journal-elapse/2021-10-26v05-journal-elapse.sql @@ -1,3 +1,5 @@ ALTER TABLE `sys_commit_journal` ADD COLUMN `parent_id` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'parent id if renew' AFTER `create_dt`, - ADD COLUMN `elapse_ms` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'elapse mills' AFTER `parent_id`; \ No newline at end of file + ADD COLUMN `elapse_ms` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'elapse mills' AFTER `parent_id`; + +-- CALL FLYWAVE('2021-10-26v05-journal-elapse.sql'); \ No newline at end of file diff --git a/wings/faceless/src/main/resources/wings-flywave/master/01-light/2019-05-20u01-light-commit.sql b/wings/faceless/src/main/resources/wings-flywave/master/01-light/2019-05-20u01-light-commit.sql index 48983d538..a6f162b48 100644 --- a/wings/faceless/src/main/resources/wings-flywave/master/01-light/2019-05-20u01-light-commit.sql +++ b/wings/faceless/src/main/resources/wings-flywave/master/01-light/2019-05-20u01-light-commit.sql @@ -1,3 +1,5 @@ -- ask@danger DROP TABLE IF EXISTS `sys_light_sequence`; -- 103/Sequence Generation; DROP TABLE IF EXISTS `sys_commit_journal`; -- 104/Data Changeset; + +-- CALL FLYWAVE('2019-05-20u01-light-commit.sql'); \ No newline at end of file diff --git a/wings/faceless/src/main/resources/wings-flywave/master/01-light/2019-05-20v01-light-commit.sql b/wings/faceless/src/main/resources/wings-flywave/master/01-light/2019-05-20v01-light-commit.sql index d956bbfa7..39ec78d7a 100644 --- a/wings/faceless/src/main/resources/wings-flywave/master/01-light/2019-05-20v01-light-commit.sql +++ b/wings/faceless/src/main/resources/wings-flywave/master/01-light/2019-05-20v01-light-commit.sql @@ -29,3 +29,5 @@ VALUES ('singleton_lightid_blockid', 0, 10000000, 100, 'default block_id'), -- sys_commit_journal@plain REPLACE INTO `sys_commit_journal` (`id`, `event_name`) VALUES (0, 'system_manual_init'); + +-- CALL FLYWAVE('2019-05-20v01-light-commit.sql'); \ No newline at end of file diff --git a/wings/testing-faceless/src/main/resources/wings-flywave/master/2022-0601u01-test.sql b/wings/testing-faceless/src/main/resources/wings-flywave/master/2022-0601u01-test.sql index 9b1e9f4d6..eb3b102ff 100644 --- a/wings/testing-faceless/src/main/resources/wings-flywave/master/2022-0601u01-test.sql +++ b/wings/testing-faceless/src/main/resources/wings-flywave/master/2022-0601u01-test.sql @@ -1,3 +1,5 @@ DROP TABLE IF EXISTS `tst_sharding`; -- 201/sharding; DROP TABLE IF EXISTS `tst_sharding_postfix`; -- 201/sharding; DROP TABLE IF EXISTS `tst_normal_table`; -- 202/normal; + +-- CALL FLYWAVE('2022-0601u01-test.sql'); \ No newline at end of file diff --git a/wings/testing-faceless/src/main/resources/wings-flywave/master/2022-0601u02-test.sql b/wings/testing-faceless/src/main/resources/wings-flywave/master/2022-0601u02-test.sql index 99a72b635..2f7bb7d43 100644 --- a/wings/testing-faceless/src/main/resources/wings-flywave/master/2022-0601u02-test.sql +++ b/wings/testing-faceless/src/main/resources/wings-flywave/master/2022-0601u02-test.sql @@ -1,2 +1,4 @@ -- @plain TRUNCATE `tst_sharding`; + +-- CALL FLYWAVE('2022-0601u02-test.sql'); \ No newline at end of file diff --git a/wings/testing-faceless/src/main/resources/wings-flywave/master/2022-0601v01-test.sql b/wings/testing-faceless/src/main/resources/wings-flywave/master/2022-0601v01-test.sql index 6c144bb2a..380587f46 100644 --- a/wings/testing-faceless/src/main/resources/wings-flywave/master/2022-0601v01-test.sql +++ b/wings/testing-faceless/src/main/resources/wings-flywave/master/2022-0601v01-test.sql @@ -45,3 +45,5 @@ CREATE TABLE `tst_normal_table` ( REPLACE INTO `sys_light_sequence` (`seq_name`, `block_id`, `next_val`, `step_val`, `comments`) VALUES ('tst_normal_table', 0, 1000, 1, 'for test step 1'); + +-- CALL FLYWAVE('2022-0601v01-test.sql'); \ No newline at end of file diff --git a/wings/testing-faceless/src/main/resources/wings-flywave/master/2022-0601v02-test.sql b/wings/testing-faceless/src/main/resources/wings-flywave/master/2022-0601v02-test.sql index 5af828869..2d9483cd8 100644 --- a/wings/testing-faceless/src/main/resources/wings-flywave/master/2022-0601v02-test.sql +++ b/wings/testing-faceless/src/main/resources/wings-flywave/master/2022-0601v02-test.sql @@ -20,3 +20,5 @@ VALUES (100, -1, 'LOGIN_INFO-00', 'OTHER_INFO-00'), (117, -1, 'LOGIN_INFO-17', 'OTHER_INFO-17'), (118, -1, 'LOGIN_INFO-18', 'OTHER_INFO-18'), (119, -1, 'LOGIN_INFO-19', 'OTHER_INFO-19'); + +-- CALL FLYWAVE('2022-0601v02-test.sql'); \ No newline at end of file diff --git a/wings/warlock/src/main/resources/wings-flywave/branch/somefix/01-authn-fix/2021-09-18u01-rename-authn.sql b/wings/warlock/src/main/resources/wings-flywave/branch/somefix/01-authn-fix/2021-09-18u01-rename-authn.sql index 3a380db68..d480d91db 100644 --- a/wings/warlock/src/main/resources/wings-flywave/branch/somefix/01-authn-fix/2021-09-18u01-rename-authn.sql +++ b/wings/warlock/src/main/resources/wings-flywave/branch/somefix/01-authn-fix/2021-09-18u01-rename-authn.sql @@ -2,3 +2,5 @@ ALTER TABLE `win_user_authn` RENAME TO `win_user_anthn`; update `sys_light_sequence` set `seq_name`='win_user_anthn' where `seq_name`='win_user_authn'; + +-- CALL FLYWAVE('2021-09-18u01-rename-authn.sql'); \ No newline at end of file diff --git a/wings/warlock/src/main/resources/wings-flywave/branch/somefix/01-authn-fix/2021-09-18v01-rename-authn.sql b/wings/warlock/src/main/resources/wings-flywave/branch/somefix/01-authn-fix/2021-09-18v01-rename-authn.sql index c64826c59..8351b4ba7 100644 --- a/wings/warlock/src/main/resources/wings-flywave/branch/somefix/01-authn-fix/2021-09-18v01-rename-authn.sql +++ b/wings/warlock/src/main/resources/wings-flywave/branch/somefix/01-authn-fix/2021-09-18v01-rename-authn.sql @@ -2,3 +2,5 @@ ALTER TABLE `win_user_anthn` RENAME TO `win_user_authn`; update `sys_light_sequence` set `seq_name`='win_user_authn' where `seq_name`='win_user_anthn'; + +-- CALL FLYWAVE('2021-09-18v01-rename-authn.sql'); \ No newline at end of file diff --git a/wings/warlock/src/main/resources/wings-flywave/branch/somefix/04-conf-size/2021-10-26u03-conf-size.sql b/wings/warlock/src/main/resources/wings-flywave/branch/somefix/04-conf-size/2021-10-26u03-conf-size.sql index 8bbd1e773..1ea4435c4 100644 --- a/wings/warlock/src/main/resources/wings-flywave/branch/somefix/04-conf-size/2021-10-26u03-conf-size.sql +++ b/wings/warlock/src/main/resources/wings-flywave/branch/somefix/04-conf-size/2021-10-26u03-conf-size.sql @@ -6,3 +6,5 @@ ALTER TABLE `win_conf_runtime` CHANGE COLUMN `initial` `initial` VARCHAR(5000) NOT NULL DEFAULT '' COMMENT 'initial value', CHANGE COLUMN `comment` `comment` VARCHAR(500) NOT NULL DEFAULT '' COMMENT 'comment', CHANGE COLUMN `handler` `handler` VARCHAR(200) NOT NULL DEFAULT 'prop' COMMENT 'data handling:prop|json'; + +-- CALL FLYWAVE('2021-10-26u03-conf-size.sql'); \ No newline at end of file diff --git a/wings/warlock/src/main/resources/wings-flywave/branch/somefix/04-conf-size/2021-10-26v03-conf-size.sql b/wings/warlock/src/main/resources/wings-flywave/branch/somefix/04-conf-size/2021-10-26v03-conf-size.sql index 5f5b71014..0178a29db 100644 --- a/wings/warlock/src/main/resources/wings-flywave/branch/somefix/04-conf-size/2021-10-26v03-conf-size.sql +++ b/wings/warlock/src/main/resources/wings-flywave/branch/somefix/04-conf-size/2021-10-26v03-conf-size.sql @@ -15,3 +15,5 @@ UPDATE `win_conf_runtime` SET outline = `key`, `initial` = 'Nothing' WHERE `key` = 'pro.fessional.wings.warlock.service.conf.mode.ApiMode'; + +-- CALL FLYWAVE('2021-10-26v03-conf-size.sql'); \ No newline at end of file diff --git a/wings/warlock/src/main/resources/wings-flywave/master/03-enum/2020-10-23v01-auth_enum.sql b/wings/warlock/src/main/resources/wings-flywave/master/03-enum/2020-10-23v01-auth_enum.sql index 09e7e3a88..83b38ef8a 100644 --- a/wings/warlock/src/main/resources/wings-flywave/master/03-enum/2020-10-23v01-auth_enum.sql +++ b/wings/warlock/src/main/resources/wings-flywave/master/03-enum/2020-10-23v01-auth_enum.sql @@ -13,3 +13,5 @@ VALUES (1200200, 'user_status', 'user_status', 'user status', 'classpath:/wings- (1330100, 'grant_type', 'grant_type', 'grant type', 'classpath:/wings-tmpl/ConstantEnumTemplate.java'), (1330101, 'grant_type', 'perm', 'permit', 'permit'), (1330102, 'grant_type', 'role', 'role', 'role'); + +-- CALL FLYWAVE('2020-10-23v01-auth_enum.sql'); \ No newline at end of file diff --git a/wings/warlock/src/main/resources/wings-flywave/master/04-auth/2020-10-24u01-user_login.sql b/wings/warlock/src/main/resources/wings-flywave/master/04-auth/2020-10-24u01-user_login.sql index a94b62324..939fec33b 100644 --- a/wings/warlock/src/main/resources/wings-flywave/master/04-auth/2020-10-24u01-user_login.sql +++ b/wings/warlock/src/main/resources/wings-flywave/master/04-auth/2020-10-24u01-user_login.sql @@ -1,3 +1,5 @@ DROP TABLE IF EXISTS `win_user_basis`; -- 120/User Basis; DROP TABLE IF EXISTS `win_user_authn`; -- 121/User Authn; DROP TABLE IF EXISTS `win_user_login`; -- 122/User Login; + +-- CALL FLYWAVE('2020-10-24u01-user_login.sql'); \ No newline at end of file diff --git a/wings/warlock/src/main/resources/wings-flywave/master/04-auth/2020-10-24u02-role_permit.sql b/wings/warlock/src/main/resources/wings-flywave/master/04-auth/2020-10-24u02-role_permit.sql index bbe3a3321..6b794cede 100644 --- a/wings/warlock/src/main/resources/wings-flywave/master/04-auth/2020-10-24u02-role_permit.sql +++ b/wings/warlock/src/main/resources/wings-flywave/master/04-auth/2020-10-24u02-role_permit.sql @@ -2,3 +2,5 @@ DROP TABLE IF EXISTS `win_perm_entry`; -- 130/Perm Entry; DROP TABLE IF EXISTS `win_role_entry`; -- 131/Role Entry; DROP TABLE IF EXISTS `win_role_grant`; -- 134/Role Grant; DROP TABLE IF EXISTS `win_user_grant`; -- 135/User Grant; + +-- CALL FLYWAVE('2020-10-24u02-role_permit.sql'); \ No newline at end of file diff --git a/wings/warlock/src/main/resources/wings-flywave/master/04-auth/2020-10-24v01-user_login.sql b/wings/warlock/src/main/resources/wings-flywave/master/04-auth/2020-10-24v01-user_login.sql index eb4c4ac9c..cea67b84e 100644 --- a/wings/warlock/src/main/resources/wings-flywave/master/04-auth/2020-10-24v01-user_login.sql +++ b/wings/warlock/src/main/resources/wings-flywave/master/04-auth/2020-10-24v01-user_login.sql @@ -72,3 +72,5 @@ VALUES (0, NOW(3), 0, 'nobody', UUID(), 1200103, '', 'zh_CN', 1010201, 'system u INSERT IGNORE INTO `win_user_authn`(`id`, `create_dt`, `commit_id`, `user_id`, `auth_type`, `username`, `password`, `expired_dt`) VALUES (1, NOW(3), 0, 1, 'username', 'root', CONCAT('{never}', UUID()), '2999-09-09'); + +-- CALL FLYWAVE('2020-10-24v01-user_login.sql'); \ No newline at end of file diff --git a/wings/warlock/src/main/resources/wings-flywave/master/04-auth/2020-10-24v02-role_permit.sql b/wings/warlock/src/main/resources/wings-flywave/master/04-auth/2020-10-24v02-role_permit.sql index 336d7918f..6471ae137 100644 --- a/wings/warlock/src/main/resources/wings-flywave/master/04-auth/2020-10-24v02-role_permit.sql +++ b/wings/warlock/src/main/resources/wings-flywave/master/04-auth/2020-10-24v02-role_permit.sql @@ -88,3 +88,5 @@ VALUES (1, 1330101, 1, NOW(3), 0), -- Grant super perm to root user REPLACE INTO `win_user_grant`(`refer_user`, `grant_type`, `grant_entry`, `create_dt`, `commit_id`) VALUES (1, 1330102, 1, NOW(3), 0); + +-- CALL FLYWAVE('2020-10-24v02-role_permit.sql'); \ No newline at end of file diff --git a/wings/warlock/src/main/resources/wings-flywave/master/05-conf/2020-10-25u01-conf_runtime.sql b/wings/warlock/src/main/resources/wings-flywave/master/05-conf/2020-10-25u01-conf_runtime.sql index 6ad5d2773..ce23d198d 100644 --- a/wings/warlock/src/main/resources/wings-flywave/master/05-conf/2020-10-25u01-conf_runtime.sql +++ b/wings/warlock/src/main/resources/wings-flywave/master/05-conf/2020-10-25u01-conf_runtime.sql @@ -1,2 +1,3 @@ DROP TABLE IF EXISTS `win_conf_runtime`; -- 110/Runtime Config; +-- CALL FLYWAVE('2020-10-25u01-conf_runtime.sql'); \ No newline at end of file diff --git a/wings/warlock/src/main/resources/wings-flywave/master/05-conf/2020-10-25v01-conf_runtime.sql b/wings/warlock/src/main/resources/wings-flywave/master/05-conf/2020-10-25v01-conf_runtime.sql index e3ebc47bc..7b79280b8 100644 --- a/wings/warlock/src/main/resources/wings-flywave/master/05-conf/2020-10-25v01-conf_runtime.sql +++ b/wings/warlock/src/main/resources/wings-flywave/master/05-conf/2020-10-25v01-conf_runtime.sql @@ -15,3 +15,5 @@ CREATE TABLE `win_conf_runtime` ( INSERT IGNORE INTO `win_conf_runtime` (`key`, `current`, `previous`, `initial`, `outline`, `comment`, `handler`) VALUES ('pro.fessional.wings.warlock.service.conf.mode.RunMode', 'Local', 'pro.fessional.wings.warlock.service.conf.mode.RunMode', '', 'Local', 'RunMode', 'prop') , ('pro.fessional.wings.warlock.service.conf.mode.ApiMode', 'Nothing', 'pro.fessional.wings.warlock.service.conf.mode.ApiMode', '', 'Nothing', 'ApiMode', 'prop'); + +-- CALL FLYWAVE('2020-10-25v01-conf_runtime.sql'); \ No newline at end of file From c8f9f466300ff68ac1a01c684b79b5e0a1298f5b Mon Sep 17 00:00:00 2001 From: trydofor Date: Mon, 8 Jul 2024 18:53:04 +0800 Subject: [PATCH 17/51] =?UTF-8?q?=F0=9F=8E=A8=20fit-revi=20logger,=20prop?= =?UTF-8?q?=20poly?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../project/Devops1SchemaManagerTest.java | 15 ++++++++ observe/docs | 2 +- .../faceless/flywave/RevisionFitness.java | 36 ++++++++++--------- .../wings/silencer/support/PropHelper.java | 8 +++++ 4 files changed, 44 insertions(+), 17 deletions(-) diff --git a/example/winx-devops/src/test/java/com/moilioncircle/wings/devops/project/Devops1SchemaManagerTest.java b/example/winx-devops/src/test/java/com/moilioncircle/wings/devops/project/Devops1SchemaManagerTest.java index abf306b33..edebf4e2c 100644 --- a/example/winx-devops/src/test/java/com/moilioncircle/wings/devops/project/Devops1SchemaManagerTest.java +++ b/example/winx-devops/src/test/java/com/moilioncircle/wings/devops/project/Devops1SchemaManagerTest.java @@ -21,6 +21,12 @@ "spring.datasource.url=" + Devops0ProjectConstant.JDBC_URL, "spring.datasource.username=" + Devops0ProjectConstant.JDBC_USER, "spring.datasource.password=" + Devops0ProjectConstant.JDBC_PASS, +// "wings.silencer.i18n.zoneid=UTC", + "wings.enabled.faceless.flywave=true", + "wings.faceless.flywave.auto-init=true", + "wings.faceless.flywave.checker=true", + "java.awt.headless=false", + "debug=true" }) class Devops1SchemaManagerTest { @@ -37,6 +43,15 @@ void initSchema() { ); } + @Test + void bumpSchema() { + final Warlock1SchemaManager manager = new Warlock1SchemaManager(schemaRevisionManager); + manager.mergeBumping(2022_0222_01L, + includeWarlockPath(), + Helper::master + ); + } + @Test void resetSchema() { long revi = 2022_0222_01L; diff --git a/observe/docs b/observe/docs index fbb1f4817..eca196fc3 160000 --- a/observe/docs +++ b/observe/docs @@ -1 +1 @@ -Subproject commit fbb1f4817448a18f6c9bd497c9b5837508d2198e +Subproject commit eca196fc388ca300b37f2514d7bca434d5cd7d32 diff --git a/wings/faceless-flywave/src/main/java/pro/fessional/wings/faceless/flywave/RevisionFitness.java b/wings/faceless-flywave/src/main/java/pro/fessional/wings/faceless/flywave/RevisionFitness.java index 71190796c..65cec63a0 100644 --- a/wings/faceless-flywave/src/main/java/pro/fessional/wings/faceless/flywave/RevisionFitness.java +++ b/wings/faceless-flywave/src/main/java/pro/fessional/wings/faceless/flywave/RevisionFitness.java @@ -16,6 +16,7 @@ import java.util.Set; import java.util.SortedMap; import java.util.TreeMap; +import java.util.TreeSet; /** * @author trydofor @@ -33,7 +34,7 @@ public void addFit(Fit fit, String msg) { if (fit == null) return; final Act act = fit.getLost(); if (act == null || act == Act.SKIP) { - log.info("skip fit {}", msg); + log.info("skip fit-revi {}", msg); return; } @@ -45,11 +46,11 @@ public void addFit(Fit fit, String msg) { final Set revi = fit.getRevi(); for (String str : revi) { Long r = AnyIntegerUtil.obj64(str); - reviAct.computeIfAbsent(r, ignored -> new HashSet<>()).add(act); - reviMsg.computeIfAbsent(r, ignored -> new HashSet<>()).add(msg); + reviAct.computeIfAbsent(r, ignored -> new TreeSet<>()).add(act); + reviMsg.computeIfAbsent(r, ignored -> new TreeSet<>()).add(msg); } - log.info("found fit {}. `wings.faceless.flywave.fit[{}].lost=SKIP` to skip", revi, msg); + log.info("found fit-revi {}. `wings.faceless.flywave.fit[{}].lost=SKIP` to skip", revi, msg); } public void addFits(Map fits) { @@ -72,7 +73,6 @@ private void applyRevision(SchemaRevisionManager manager, TreeMap for (Set at : revi.values()) { if (!autoInit && at.contains(Act.EXEC)) { throw new IllegalStateException(""" - Wings `flywave revision` do NOT exist, and Auto Init is dangerous, you can, 1.stop checker: `wings.faceless.flywave.checker=false` 2.revision fitness do NOT contain `EXEC` @@ -89,10 +89,10 @@ private void applyRevision(SchemaRevisionManager manager, TreeMap final Set ts = en.getValue(); final Set ms = reviMsg.get(rv); if (ts.contains(Act.WARN)) { - log.warn("Wings Revision Lost revi={}. Manual={}", rv, manual(ms)); + log.warn("Wings Revision Lost fit-revi={}. Manual={}", rv, manual(ms)); } if (ts.contains(Act.FAIL)) { - log.error("Wings Revision Lost revi={}. Manual={}", rv, manual(ms)); + log.error("Wings Revision Lost fit-revi={}. Manual={}", rv, manual(ms)); failed = true; } if (ts.contains(Act.EXEC)) { @@ -101,7 +101,7 @@ private void applyRevision(SchemaRevisionManager manager, TreeMap } if (failed) { - throw new IllegalStateException("Wings Revision Lost revi need FAIL"); + throw new IllegalStateException("Wings Revision Lost fit-revi need FAIL"); } if (exec.isEmpty()) { return; @@ -116,7 +116,7 @@ private void applyRevision(SchemaRevisionManager manager, TreeMap final Set ms = en.getValue(); final RevisionSql sql = scan.get(rv); if (sql == null) { - log.error("Wings Revision Lost And Failed to Scan. revi={} by={}", rv, ms); + log.error("Wings Revision Lost And Failed to Scan. fit-revi={} by={}", rv, ms); errors = true; } } @@ -134,12 +134,12 @@ private void applyRevision(SchemaRevisionManager manager, TreeMap if (rv == WingsRevision.V00_19_0512_01_Schema.revision()) { TreeMap init = new TreeMap<>(); init.put(rv, sql); - log.info("Wings Revision force to init revi={}, cid={}, by={}", rv, cid, ms); + log.info("Wings Revision force to init fit-revi={}, cid={}, by={}", rv, cid, ms); manager.checkAndInitSql(init, cid, true); } else { manager.forceUpdateSql(sql, cid); - log.info("Wings Revision force to apply revi={}, cid={}, by={}", rv, cid, ms); + log.info("Wings Revision force to apply fit-revi={}, cid={}, by={}", rv, cid, ms); manager.forceApplyBreak(rv, cid, true, null); } } @@ -198,13 +198,13 @@ private TreeMap> checkUnapply(SchemaRevisionManager manager) { if (reviStatus == null || reviStatus.isEmpty()) { if (unInit) { - log.warn("Wings Revision UnInit all-revi"); + log.warn("Wings Revision UnInit all fit-revi"); final TreeMap> map = new TreeMap<>(reviAct); map.put(UnInit, Set.of(Act.WARN)); return map; } else { - log.info("Wings Revision Unapply all-revi"); + log.info("Wings Revision Unapply all fit-revi"); return reviAct; } } @@ -236,13 +236,17 @@ private TreeMap> checkUnapply(SchemaRevisionManager manager) { for (Map.Entry> revi : reviAct.entrySet()) { final Long rv = revi.getKey(); final Status st = reviStatus.get(rv); - if (st != Status.Applied) { + if (st == Status.Applied) { + log.info("found fit-revi={} had applied", rv); + } + else { map.put(rv, revi.getValue()); - log.info("Wings Revision Unapply revi={}, status={}", rv, st); + Set keys = reviMsg.get(rv); + log.info("found fit-revi={} not applied, status={}", rv, st); } } if (unInit) { - log.warn("Wings Revision UnInit all-revi"); + log.warn("Wings Revision UnInit all fit-revi"); map.put(UnInit, Set.of(Act.WARN)); return map; } diff --git a/wings/silencer/src/main/java/pro/fessional/wings/silencer/support/PropHelper.java b/wings/silencer/src/main/java/pro/fessional/wings/silencer/support/PropHelper.java index c118c53db..7eefa9df2 100644 --- a/wings/silencer/src/main/java/pro/fessional/wings/silencer/support/PropHelper.java +++ b/wings/silencer/src/main/java/pro/fessional/wings/silencer/support/PropHelper.java @@ -142,6 +142,14 @@ public static String removeOptional(@NotNull String url, String elz) { return ok ? url : elz; } + /** + * remove prefix `optional:`, return the input url if no prefix + */ + @NotNull + public static String removeOptional(@NotNull String url) { + return removeOptional(url, url); + } + /** * `optional:` prefix will return null if exception. * use ApplicationContext(if prepared) or DefaultResourceLoader as loader by default. From deaf97b98323fe6c147f8cb833c6935367840e73 Mon Sep 17 00:00:00 2001 From: trydofor Date: Tue, 9 Jul 2024 16:37:45 +0800 Subject: [PATCH 18/51] =?UTF-8?q?=E2=9C=A8=20tinymail=20use=20its=20own=20?= =?UTF-8?q?scheduler=20#271?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- observe/docs | 2 +- .../service/impl/TinyMailServiceImpl.java | 35 +++++++++++++------ .../mail/spring/prop/TinyMailServiceProp.java | 8 +++++ .../wings-tinymail-service-79.properties | 6 ++++ .../slardar/spring/prop/SlardarAsyncProp.java | 6 ++-- 5 files changed, 43 insertions(+), 14 deletions(-) diff --git a/observe/docs b/observe/docs index eca196fc3..f90679fde 160000 --- a/observe/docs +++ b/observe/docs @@ -1 +1 @@ -Subproject commit eca196fc388ca300b37f2514d7bca434d5cd7d32 +Subproject commit f90679fde42926eb7418ced023054a68003e24fa diff --git a/radiant/tiny-mail/src/main/java/pro/fessional/wings/tiny/mail/service/impl/TinyMailServiceImpl.java b/radiant/tiny-mail/src/main/java/pro/fessional/wings/tiny/mail/service/impl/TinyMailServiceImpl.java index 295d401cd..bc50a7702 100644 --- a/radiant/tiny-mail/src/main/java/pro/fessional/wings/tiny/mail/service/impl/TinyMailServiceImpl.java +++ b/radiant/tiny-mail/src/main/java/pro/fessional/wings/tiny/mail/service/impl/TinyMailServiceImpl.java @@ -9,8 +9,9 @@ import org.jetbrains.annotations.Nullable; import org.springframework.beans.factory.InitializingBean; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.autoconfigure.task.TaskSchedulingProperties; +import org.springframework.boot.task.ThreadPoolTaskSchedulerBuilder; import org.springframework.core.io.Resource; import org.springframework.core.io.ResourceLoader; import org.springframework.mail.MailParseException; @@ -31,6 +32,7 @@ import pro.fessional.wings.silencer.modulate.RuntimeMode; import pro.fessional.wings.silencer.spring.boot.ConditionalWingsEnabled; import pro.fessional.wings.silencer.support.PropHelper; +import pro.fessional.wings.slardar.async.TaskSchedulerHelper; import pro.fessional.wings.slardar.fastjson.FastJsonHelper; import pro.fessional.wings.tiny.mail.database.autogen.tables.WinMailSenderTable; import pro.fessional.wings.tiny.mail.database.autogen.tables.daos.WinMailSenderDao; @@ -57,7 +59,6 @@ import java.util.concurrent.PriorityBlockingQueue; import java.util.concurrent.atomic.AtomicInteger; -import static org.springframework.scheduling.annotation.ScheduledAnnotationBeanPostProcessor.DEFAULT_TASK_SCHEDULER_BEAN_NAME; import static pro.fessional.wings.silencer.support.PropHelper.commaArray; import static pro.fessional.wings.silencer.support.PropHelper.invalid; @@ -89,8 +90,8 @@ public class TinyMailServiceImpl implements TinyMailService, InitializingBean { @Setter(onMethod_ = { @Autowired(required = false) }) protected List statusHooks; - @Setter(onMethod_ = { @Autowired, @Qualifier(DEFAULT_TASK_SCHEDULER_BEAN_NAME) }) - private ThreadPoolTaskScheduler taskScheduler; + // init afterPropertiesSet + protected ThreadPoolTaskScheduler mailScheduler; @SuppressWarnings("all") private final PriorityBlockingQueue asyncMails = new PriorityBlockingQueue<>(); @@ -211,6 +212,7 @@ public long save(@NotNull TinyMailPlain msg) { po.setMailMark(msg.getMark()); po.setMailDate(md); + // PropertyMapper IfSetter.nonnull(po::setMaxFail, msg.getMaxFail()); IfSetter.nonnull(po::setMaxDone, msg.getMaxDone()); @@ -260,16 +262,29 @@ public int scan() { log.info("plan misfire tiny-mail, size={}", size); if (size > 0) { asyncMails.addAll(pos); - taskScheduler.schedule(this::doAsyncBatchSend, Instant.ofEpochMilli(now)); + mailScheduler.schedule(this::doAsyncBatchSend, Instant.ofEpochMilli(now)); } return size; } @Override public void afterPropertiesSet() { + ThreadPoolTaskSchedulerBuilder builder = new ThreadPoolTaskSchedulerBuilder(); + TaskSchedulingProperties scheduler = tinyMailServiceProp.getScheduler(); + builder = builder.poolSize(scheduler.getPool().getSize()); + builder = builder.threadNamePrefix(scheduler.getThreadNamePrefix()); + TaskSchedulingProperties.Shutdown shutdown = scheduler.getShutdown(); + builder = builder.awaitTermination(shutdown.isAwaitTermination()); + builder = builder.awaitTerminationPeriod(shutdown.getAwaitTerminationPeriod()); + + mailScheduler = TaskSchedulerHelper.Ttl(builder); + mailScheduler.initialize(); + + log.info("tiny-mail mailScheduler, prefix=" + mailScheduler.getThreadNamePrefix()); + final long bms = tinyMailServiceProp.getBootScan().toMillis(); if (bms > 0) { - taskScheduler.schedule(this::scan, Instant.ofEpochMilli(ThreadNow.millis() + bms)); + mailScheduler.schedule(this::scan, Instant.ofEpochMilli(ThreadNow.millis() + bms)); } } @@ -513,14 +528,14 @@ else if (exception instanceof MailParseException || exception instanceof Messagi if (exception == null) { if (notHookStop && nextSend > 0) { asyncMails.add(new AsyncMail(po.getId(), nextSend, retry, check, null, message)); - taskScheduler.schedule(this::doAsyncBatchSend, Instant.ofEpochMilli(nextSend)); + mailScheduler.schedule(this::doAsyncBatchSend, Instant.ofEpochMilli(nextSend)); log.debug("schedule done-tiny-mail send, id={}, subject={}", po.getId(), po.getMailSubj()); } } else { if (notHookStop && retry && nextSend > 0 && nextSend - now < tinyMailServiceProp.getMaxNext().toMillis()) { asyncMails.add(new AsyncMail(po.getId(), nextSend, retry, check, null, message)); - taskScheduler.schedule(this::doAsyncBatchSend, Instant.ofEpochMilli(nextSend)); + mailScheduler.schedule(this::doAsyncBatchSend, Instant.ofEpochMilli(nextSend)); log.debug("schedule fail-tiny-mail send, id=" + po.getId() + ", subject=" + po.getMailSubj()); } else { @@ -591,7 +606,7 @@ private long doAsyncFreshSend(@NotNull WinMailSender po, TinyMailMessage message mailSenderManager.checkMessage(message); asyncMails.add(new AsyncMail(id, nxt, retry, check, po, message)); - taskScheduler.schedule(this::doAsyncBatchSend, Instant.ofEpochMilli(nxt)); + mailScheduler.schedule(this::doAsyncBatchSend, Instant.ofEpochMilli(nxt)); return nxt; } @@ -672,7 +687,7 @@ private void doAsyncBatchSend() { final int size = asyncMails.size(); if (size > 0) { final long next = start + tinyMailServiceProp.getTryNext().toMillis(); - taskScheduler.schedule(this::doAsyncBatchSend, Instant.ofEpochMilli(next)); + mailScheduler.schedule(this::doAsyncBatchSend, Instant.ofEpochMilli(next)); if (size > tinyMailServiceProp.getWarnSize()) { log.warn("plan next tiny-mail warn-size={}, idle={}", size, tinyMailServiceProp.getTryNext()); } diff --git a/radiant/tiny-mail/src/main/java/pro/fessional/wings/tiny/mail/spring/prop/TinyMailServiceProp.java b/radiant/tiny-mail/src/main/java/pro/fessional/wings/tiny/mail/spring/prop/TinyMailServiceProp.java index 8c7c8467f..7a279ae69 100644 --- a/radiant/tiny-mail/src/main/java/pro/fessional/wings/tiny/mail/spring/prop/TinyMailServiceProp.java +++ b/radiant/tiny-mail/src/main/java/pro/fessional/wings/tiny/mail/spring/prop/TinyMailServiceProp.java @@ -1,6 +1,7 @@ package pro.fessional.wings.tiny.mail.spring.prop; import lombok.Data; +import org.springframework.boot.autoconfigure.task.TaskSchedulingProperties; import org.springframework.boot.context.properties.ConfigurationProperties; import java.time.Duration; @@ -85,4 +86,11 @@ public class TinyMailServiceProp { */ private boolean onlyRun = true; public static final String Key$onlyRun = Key + ".only-run"; + + /** + * @see TaskSchedulingProperties + * @see #Key$scheduler + */ + private TaskSchedulingProperties scheduler = null; + public static final String Key$scheduler = Key + ".scheduler"; } diff --git a/radiant/tiny-mail/src/main/resources/wings-conf/wings-tinymail-service-79.properties b/radiant/tiny-mail/src/main/resources/wings-conf/wings-tinymail-service-79.properties index ec095542d..129a85b22 100644 --- a/radiant/tiny-mail/src/main/resources/wings-conf/wings-tinymail-service-79.properties +++ b/radiant/tiny-mail/src/main/resources/wings-conf/wings-tinymail-service-79.properties @@ -16,3 +16,9 @@ wings.tiny.mail.service.boot-scan=60s wings.tiny.mail.service.only-app=false ## whether to send emails from this RumMode only. wings.tiny.mail.service.only-run=true + +## TaskSchedulingProperties +wings.tiny.mail.service.scheduler.pool.size=2 +wings.tiny.mail.service.scheduler.shutdown.await-termination=true +wings.tiny.mail.service.scheduler.shutdown.await-termination-period=60s +wings.tiny.mail.service.scheduler.thread-name-prefix=mail- diff --git a/wings/slardar/src/main/java/pro/fessional/wings/slardar/spring/prop/SlardarAsyncProp.java b/wings/slardar/src/main/java/pro/fessional/wings/slardar/spring/prop/SlardarAsyncProp.java index 23f8aedd3..5aa5406c7 100644 --- a/wings/slardar/src/main/java/pro/fessional/wings/slardar/spring/prop/SlardarAsyncProp.java +++ b/wings/slardar/src/main/java/pro/fessional/wings/slardar/spring/prop/SlardarAsyncProp.java @@ -27,10 +27,10 @@ public class SlardarAsyncProp { /** * fast thread pool * - * @see #Key$heavy + * @see #Key$fast */ private TaskSchedulingProperties fast; - public static final String Key$heavy = Key + ".fast"; + public static final String Key$fast = Key + ".fast"; /** * executor prefix @@ -45,7 +45,7 @@ public static class ExecPrefix { /** * AsyncHelper lite Pool */ - private String lite = "lite-"; + private String lite = "lit-exec-"; /** * Callable MVC mapping */ From e2f316d43f860e81a70b3a7f40698ca806914709 Mon Sep 17 00:00:00 2001 From: trydofor Date: Wed, 10 Jul 2024 09:26:16 +0800 Subject: [PATCH 19/51] =?UTF-8?q?=E2=9C=A8=20tinymail=20add=20scan-idle=20?= =?UTF-8?q?#271?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- observe/docs | 2 +- .../tiny/mail/sender/MailSenderManager.java | 9 +- .../tiny/mail/service/TinyMailService.java | 19 +- .../service/impl/TinyMailServiceImpl.java | 496 ++++++++++++------ .../mail/spring/prop/TinyMailServiceProp.java | 13 +- .../wings-tinymail-service-79.properties | 4 +- .../app/conf/TestStatusHookConfiguration.java | 14 +- .../app/service/TestMailSenderManager.java | 46 ++ .../mail/service/TinyMailServiceDbTest.java | 159 ++++++ .../mail/service/TinyMailServiceTest.java | 7 +- .../src/test/resources/application.properties | 2 + 11 files changed, 592 insertions(+), 179 deletions(-) create mode 100644 radiant/tiny-mail/src/test/java/pro/fessional/wings/tiny/app/service/TestMailSenderManager.java create mode 100644 radiant/tiny-mail/src/test/java/pro/fessional/wings/tiny/mail/service/TinyMailServiceDbTest.java diff --git a/observe/docs b/observe/docs index f90679fde..55df815df 160000 --- a/observe/docs +++ b/observe/docs @@ -1 +1 @@ -Subproject commit f90679fde42926eb7418ced023054a68003e24fa +Subproject commit 55df815dfb3f2a4c7387d931e122ffee2e9fa27c diff --git a/radiant/tiny-mail/src/main/java/pro/fessional/wings/tiny/mail/sender/MailSenderManager.java b/radiant/tiny-mail/src/main/java/pro/fessional/wings/tiny/mail/sender/MailSenderManager.java index 4d55809e4..236ec2e45 100644 --- a/radiant/tiny-mail/src/main/java/pro/fessional/wings/tiny/mail/sender/MailSenderManager.java +++ b/radiant/tiny-mail/src/main/java/pro/fessional/wings/tiny/mail/sender/MailSenderManager.java @@ -188,8 +188,11 @@ public List batchSend(Collection message final long slp = Sleep.ignoreInterrupt(10, 2000); log.info("batch mail dryrun and sleep {} ms", slp); final long avg = slp / dryrunCount; + long end = ThreadNow.millis(); for (BatchResult rst : results) { - if (rst.costMillis < 0) rst.costMillis = avg; + if(rst.costMillis == 0) continue; + rst.costMillis = avg; + rst.exitMillis = end; } } @@ -245,7 +248,7 @@ public List batchSend(Collection message long avg = (now - start) / len; for (BatchResult br : result) { br.costMillis = avg; - br.doneMillis = now; + br.exitMillis = now; if (br.exception != null) { log.warn("failed to batch send message, " + br.tinyMessage.toMainString()); } @@ -472,7 +475,7 @@ public static class BatchResult { @Getter private long costMillis = 0; @Getter - private long doneMillis = 0; + private long exitMillis = 0; @Getter private Exception exception; diff --git a/radiant/tiny-mail/src/main/java/pro/fessional/wings/tiny/mail/service/TinyMailService.java b/radiant/tiny-mail/src/main/java/pro/fessional/wings/tiny/mail/service/TinyMailService.java index d002bf5d0..f60b51a1a 100644 --- a/radiant/tiny-mail/src/main/java/pro/fessional/wings/tiny/mail/service/TinyMailService.java +++ b/radiant/tiny-mail/src/main/java/pro/fessional/wings/tiny/mail/service/TinyMailService.java @@ -82,15 +82,28 @@ default long emit(@NotNull TinyMailPlain message) { long emit(long id, boolean retry, boolean check); /** - * Create(id is empty) or edit a mail, return the id + * Create(id is empty) or edit a mail, return the id. + * NOTE: no schedule to send, need manually send/post/emit it. */ long save(@NotNull TinyMailPlain message); /** - * Sync scan the mail to resend, return the count, and send them async + *

+     * Sync scan the unsent mail to resend them async, return the count. and if idel is
+     * * null, only scan, nothing to idle
+     * * > 0, adjust the scheduled scan interval mills
+     * * = 0, disable the scheduled scan
+     * * < 0, reset to scan-idle prop if adjusted before
+     * 
*/ - int scan(); + int scan(Long idle); + /** + * Sync scan the unsent mail to resend them async, return the count. + */ + default int scan() { + return scan(null); + } /** * Create the mail, and auto send it in sync or async way. diff --git a/radiant/tiny-mail/src/main/java/pro/fessional/wings/tiny/mail/service/impl/TinyMailServiceImpl.java b/radiant/tiny-mail/src/main/java/pro/fessional/wings/tiny/mail/service/impl/TinyMailServiceImpl.java index bc50a7702..33e3fedfb 100644 --- a/radiant/tiny-mail/src/main/java/pro/fessional/wings/tiny/mail/service/impl/TinyMailServiceImpl.java +++ b/radiant/tiny-mail/src/main/java/pro/fessional/wings/tiny/mail/service/impl/TinyMailServiceImpl.java @@ -2,6 +2,7 @@ import jakarta.mail.MessagingException; import lombok.Data; +import lombok.Getter; import lombok.Setter; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; @@ -51,13 +52,20 @@ import java.time.Instant; import java.time.LocalDateTime; import java.util.ArrayList; +import java.util.Collection; import java.util.Collections; import java.util.HashMap; +import java.util.HashSet; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; -import java.util.concurrent.PriorityBlockingQueue; +import java.util.PriorityQueue; +import java.util.Set; +import java.util.TreeMap; +import java.util.concurrent.ScheduledFuture; import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicLong; +import java.util.concurrent.atomic.AtomicReference; import static pro.fessional.wings.silencer.support.PropHelper.commaArray; import static pro.fessional.wings.silencer.support.PropHelper.invalid; @@ -90,11 +98,11 @@ public class TinyMailServiceImpl implements TinyMailService, InitializingBean { @Setter(onMethod_ = { @Autowired(required = false) }) protected List statusHooks; - // init afterPropertiesSet - protected ThreadPoolTaskScheduler mailScheduler; + // init by afterPropertiesSet + protected ThreadPoolTaskScheduler taskScheduler; - @SuppressWarnings("all") - private final PriorityBlockingQueue asyncMails = new PriorityBlockingQueue<>(); + private final PriorityQueue asyncMailQueue = new PriorityQueue<>(); + private final TreeMap> asyncMailSched = new TreeMap<>(); @Override public boolean send(@NotNull TinyMail message, boolean retry) { @@ -122,10 +130,11 @@ public boolean post(@NotNull TinyMail message, boolean retry) { public long emit(@NotNull TinyMail message, boolean retry) { final String conf = message.getConf(); final TinyMailConfig config = mailConfigProvider.bynamedConfig(conf); - AssertArgs.notNull(config, "mail conf={} not found", conf); + AssertArgs.notNull(config, "tiny-mail conf={} not found", conf); + final WinMailSender po = saveMailSender(config, message); final TinyMailMessage mailMessage = makeMailMessage(config, po, message); - return doAsyncFreshSend(po, mailMessage, retry, true); + return doAsyncSend(po, mailMessage, retry, true); } @Override @@ -164,7 +173,7 @@ public long emit(long id, boolean retry, boolean check) { log.warn("tiny-mail not found by id={}, skip emit", id); return -1; } - return doAsyncFreshSend(po, null, retry, check); + return doAsyncSend(po, null, retry, check); } @Override @@ -239,14 +248,71 @@ public long save(@NotNull TinyMailPlain msg) { } @Override - public int scan() { + public int scan(Long idle) { + if (idle == null) return scanSync(); + + idleScanMills.set(idle); + final ScheduledFuture task = idleScanTask.get(); + if (task != null) task.cancel(false); + + return scanIdle(); + } + + @NotNull + public ArrayList listAsyncMailQueue() { + synchronized (asyncMailQueue) { + return new ArrayList<>(asyncMailQueue); + } + } + + @NotNull + public TreeMap> listAsyncMailSched() { + synchronized (asyncMailSched) { + return new TreeMap(asyncMailSched); + } + } + + protected final AtomicLong idleScanMills = new AtomicLong(-1); + protected final AtomicReference> idleScanTask = new AtomicReference<>(); + + protected int scanIdle() { + int size = -1; + try { + size = scanSync(); + } + catch (Exception e) { + log.error("fail to scanSync", e); + } + + long idle = idleScanMills.get(); + + if (idle < 0) { // reset to prop + idle = tinyMailServiceProp.getScanIdle().toMillis(); + idleScanMills.set(idle); + log.info("schedule reset tiny-mail scan, idle={} ms", idle); + } + + if (idle > 0) { + var task = taskScheduler.schedule(this::scanIdle, Instant.ofEpochMilli(ThreadNow.millis() + idle)); + idleScanTask.set(task); + log.info("schedule next tiny-mail scan, idle={} ms", idle); + } + else { + idleScanTask.set(null); + log.info("schedule stop tiny-mail scan, idle={} ms", idle); + } + + return size; + } + + protected int scanSync() { final long now = ThreadNow.millis(); final LocalDateTime min = DateLocaling.sysLdt(now - tinyMailServiceProp.getMaxNext().toMillis()); final LocalDateTime max = DateLocaling.sysLdt(now + tinyMailServiceProp.getTryNext().toMillis()); - log.info("scan misfire tiny-mail to queue, min={}, max={}", min, max); + log.info("scan tiny-mail to queue, min={}, max={}", min, max); final WinMailSenderTable t = winMailSenderDao.getTable(); - final List pos = winMailSenderDao + final List mails = winMailSenderDao .ctx() .selectFrom(t) .where(t.NextSend.ge(min).and(t.NextSend.lt(max))) @@ -258,11 +324,9 @@ public int scan() { .toList(); // - final int size = pos.size(); - log.info("plan misfire tiny-mail, size={}", size); + final int size = mails.size(); if (size > 0) { - asyncMails.addAll(pos); - mailScheduler.schedule(this::doAsyncBatchSend, Instant.ofEpochMilli(now)); + planAsyncMail(mails); } return size; } @@ -277,18 +341,18 @@ public void afterPropertiesSet() { builder = builder.awaitTermination(shutdown.isAwaitTermination()); builder = builder.awaitTerminationPeriod(shutdown.getAwaitTerminationPeriod()); - mailScheduler = TaskSchedulerHelper.Ttl(builder); - mailScheduler.initialize(); - - log.info("tiny-mail mailScheduler, prefix=" + mailScheduler.getThreadNamePrefix()); + taskScheduler = TaskSchedulerHelper.Ttl(builder); + taskScheduler.initialize(); + log.info("tiny-mail mailScheduler, prefix=" + taskScheduler.getThreadNamePrefix()); - final long bms = tinyMailServiceProp.getBootScan().toMillis(); - if (bms > 0) { - mailScheduler.schedule(this::scan, Instant.ofEpochMilli(ThreadNow.millis() + bms)); + final long idle = tinyMailServiceProp.getBootScan().toMillis(); + if (idle > 0) { + log.info("tiny-mail schedule boot-scan after={} ms", idle); + taskScheduler.schedule(this::scanIdle, Instant.ofEpochMilli(ThreadNow.millis() + idle)); } } - private TinyMailMessage makeMailMessage(@NotNull TinyMailConfig config, @NotNull WinMailSender po, @Nullable TinyMail msg) { + protected TinyMailMessage makeMailMessage(@NotNull TinyMailConfig config, @NotNull WinMailSender po, @Nullable TinyMail msg) { final TinyMailMessage message = new TinyMailMessage(); TinyMailConfig.ConfSetter.toAny(message, config); message.setBizId(po.getId()); @@ -323,7 +387,7 @@ private TinyMailMessage makeMailMessage(@NotNull TinyMailConfig config, @NotNull return message; } - private WinMailSender saveMailSender(@NotNull TinyMailConfig config, @NotNull TinyMail msg) { + protected WinMailSender saveMailSender(@NotNull TinyMailConfig config, @NotNull TinyMail msg) { final WinMailSender po = new WinMailSender(); final long id = lightIdService.getId(winMailSenderDao.getTable()); po.setId(id); @@ -369,7 +433,10 @@ private WinMailSender saveMailSender(@NotNull TinyMailConfig config, @NotNull Ti return po; } - private boolean notMatchProp(WinMailSender po) { + /** + * should skip sending, condition not match + */ + protected boolean notMatchProp(@NotNull WinMailSender po) { if (tinyMailServiceProp.isOnlyApp()) { final String ma = po.getMailApps(); if (StringUtils.isNotEmpty(ma) && !appName.equalsIgnoreCase(ma)) { @@ -392,15 +459,17 @@ private boolean notMatchProp(WinMailSender po) { } } - final int maxDone = BoxedCastUtil.orElse(po.getMaxDone(), 0) > 0 ? po.getMaxDone() : tinyMailServiceProp.getMaxDone(); - final int sumDone = BoxedCastUtil.orElse(po.getSumDone(), 0); + final int poDone = BoxedCastUtil.orZero(po.getMaxDone()); + final int maxDone = poDone > 0 ? poDone : tinyMailServiceProp.getMaxDone(); + final int sumDone = BoxedCastUtil.orZero(po.getSumDone()); if (sumDone >= maxDone) { log.debug("skip max-send tiny-mail, max={}, sum={}, id={}", maxDone, sumDone, po.getId()); return true; } - final int maxFail = BoxedCastUtil.orElse(po.getMaxFail(), 0) > 0 ? po.getMaxFail() : tinyMailServiceProp.getMaxFail(); - final int sumFail = BoxedCastUtil.orElse(po.getSumFail(), 0); + final int poFail = BoxedCastUtil.orZero(po.getMaxFail()); + final int maxFail = poFail > 0 ? poFail : tinyMailServiceProp.getMaxFail(); + final int sumFail = BoxedCastUtil.orZero(po.getSumFail()); if (sumFail >= maxFail) { log.debug("skip max-fail tiny-mail, max={}, sum={}, id={}", maxFail, sumFail, po.getId()); return true; @@ -409,7 +478,10 @@ private boolean notMatchProp(WinMailSender po) { return false; } - private boolean notNextLock(WinMailSender po, long now) { + /** + * should skip sending, others do it + */ + protected boolean notNextLock(@NotNull WinMailSender po, long now) { final WinMailSenderTable t = winMailSenderDao.getTable(); final int rc = winMailSenderDao .ctx() @@ -427,25 +499,24 @@ private boolean notNextLock(WinMailSender po, long now) { return false; } - private void saveStatusAndRetry(@NotNull WinMailSender po, TinyMailMessage message, long cost, long now, Exception exception, boolean retry, boolean check, boolean rethrow) { + protected long saveSendResult(@NotNull WinMailSender po, @NotNull TinyMailMessage message, long cost, long exit, Exception exception, boolean retry) { long nextSend = -1; - boolean notHookStop = true; try { final WinMailSenderTable t = winMailSenderDao.getTable(); final Map setter = new HashMap<>(); if (exception == null) { setter.put(t.LastFail, null); - setter.put(t.LastDone, DateLocaling.sysLdt(now)); + setter.put(t.LastDone, DateLocaling.sysLdt(exit)); setter.put(t.LastCost, cost); - if (po.getSumDone() + 1 >= tinyMailServiceProp.getMaxDone()) { - setter.put(t.NextSend, EmptyValue.DATE_TIME); + final int poDone = BoxedCastUtil.orZero(po.getMaxDone()); + final int maxDone = poDone > 0 ? poDone : tinyMailServiceProp.getMaxDone(); + if (po.getSumDone() + 1 >= maxDone) { log.debug("done tiny-mail by max-send id={}, subject={}", po.getId(), po.getMailSubj()); } else { - nextSend = now + tinyMailServiceProp.getTryNext().toMillis(); - setter.put(t.NextSend, DateLocaling.sysLdt(nextSend)); - log.debug("next done-tiny-mail id={}, subject={}", po.getId(), po.getMailSubj()); + nextSend = exit + tinyMailServiceProp.getTryNext().toMillis(); + log.debug("next done tiny-mail id={}, subject={}", po.getId(), po.getMailSubj()); } setter.put(t.SumSend, t.SumSend.add(1)); @@ -456,15 +527,14 @@ private void saveStatusAndRetry(@NotNull WinMailSender po, TinyMailMessage messa setter.put(t.LastDone, EmptyValue.DATE_TIME); setter.put(t.LastCost, cost); - final int maxFail = BoxedCastUtil.orElse(po.getMaxFail(), 0) > 0 ? po.getMaxFail() : tinyMailServiceProp.getMaxFail(); + final int poFail = BoxedCastUtil.orZero(po.getMaxFail()); + final int maxFail = poFail > 0 ? poFail : tinyMailServiceProp.getMaxFail(); if (po.getSumFail() + 1 >= maxFail) { - setter.put(t.NextSend, EmptyValue.DATE_TIME); log.debug("done tiny-mail by max-fail id={}, subject={}", po.getId(), po.getMailSubj()); } else if (retry) { if (exception instanceof MailWaitException mwe) { if (mwe.isStopRetry()) { - setter.put(t.NextSend, EmptyValue.DATE_TIME); log.error("stop stop-retry tiny-mail, id=" + po.getId(), exception); } else { @@ -472,31 +542,25 @@ else if (retry) { } } else if (exception instanceof MailParseException || exception instanceof MessagingException) { - setter.put(t.NextSend, EmptyValue.DATE_TIME); log.error("failed to parse, stop tiny-mail, id=" + po.getId(), exception); } else { - nextSend = now + tinyMailServiceProp.getTryNext().toMillis(); - } - - if (nextSend > 0) { - setter.put(t.NextSend, DateLocaling.sysLdt(nextSend)); - log.debug("next fail-tiny-mail id={}, subject={}", po.getId(), po.getMailSubj()); + nextSend = exit + tinyMailServiceProp.getTryNext().toMillis(); } } else { - setter.put(t.NextSend, EmptyValue.DATE_TIME); log.error("stop not-retry tiny-mail, id=" + po.getId(), exception); } setter.put(t.SumSend, t.SumSend.add(1)); setter.put(t.SumFail, t.SumFail.add(1)); } + boolean hookStop = false; if (statusHooks != null) { for (StatusHook sh : statusHooks) { try { if (sh.stop(po, cost, exception)) { - notHookStop = false; + hookStop = true; } } catch (Exception e) { @@ -505,11 +569,18 @@ else if (exception instanceof MailParseException || exception instanceof Messagi } } - if (!notHookStop) { - setter.put(t.NextSend, EmptyValue.DATE_TIME); + if (hookStop) { log.debug("hook stop tiny-mail, id={}", po.getId()); } + if (nextSend > 0) { + setter.put(t.NextSend, DateLocaling.sysLdt(nextSend)); + log.debug("next tiny-mail id={}, subject={}", po.getId(), po.getMailSubj()); + } + else { + setter.put(t.NextSend, EmptyValue.DATE_TIME); + } + journalService.commit(Jane.Update, journal -> { setter.put(t.CommitId, journal.getCommitId()); setter.put(t.ModifyDt, journal.getCommitDt()); @@ -522,49 +593,21 @@ else if (exception instanceof MailParseException || exception instanceof Messagi } catch (Exception e) { log.error("failed to save tiny-mail status, id=" + po.getId() + ", subject=" + po.getMailSubj(), e); - nextSend = now + tinyMailServiceProp.getTryNext().toMillis(); + nextSend = exit + tinyMailServiceProp.getTryNext().toMillis(); } - if (exception == null) { - if (notHookStop && nextSend > 0) { - asyncMails.add(new AsyncMail(po.getId(), nextSend, retry, check, null, message)); - mailScheduler.schedule(this::doAsyncBatchSend, Instant.ofEpochMilli(nextSend)); - log.debug("schedule done-tiny-mail send, id={}, subject={}", po.getId(), po.getMailSubj()); - } - } - else { - if (notHookStop && retry && nextSend > 0 && nextSend - now < tinyMailServiceProp.getMaxNext().toMillis()) { - asyncMails.add(new AsyncMail(po.getId(), nextSend, retry, check, null, message)); - mailScheduler.schedule(this::doAsyncBatchSend, Instant.ofEpochMilli(nextSend)); - log.debug("schedule fail-tiny-mail send, id=" + po.getId() + ", subject=" + po.getMailSubj()); - } - else { - if (rethrow) { - if (exception instanceof RuntimeException) { - throw (RuntimeException) exception; - } - else { - throw new MailSendException("failed tiny-mail, id=" + po.getId() + ", subject=" + po.getMailSubj(), exception); - } - } - else { - log.debug("no rethrow or retry tiny-mail, id=" + po.getId() + ", subject=" + po.getMailSubj()); - } - } - } + return nextSend; } - private boolean doSyncSend(@NotNull WinMailSender po, TinyMailMessage mailMessage, boolean retry, boolean check) { + private boolean doSyncSend(@NotNull WinMailSender po, @NotNull TinyMailMessage message, boolean retry, boolean check) { final long start; if (check) { - if (notMatchProp(po)) { - return false; - } + // condition not match + if (notMatchProp(po)) return false; start = ThreadNow.millis(); - if (notNextLock(po, start)) { - return false; - } + // others do it + if (notNextLock(po, start)) return false; } else { start = ThreadNow.millis(); @@ -572,130 +615,255 @@ private boolean doSyncSend(@NotNull WinMailSender po, TinyMailMessage mailMessag Exception exception = null; try { - mailSenderManager.singleSend(mailMessage); + mailSenderManager.singleSend(message); } catch (Exception e) { exception = e; } finally { - final long now = ThreadNow.millis(); - saveStatusAndRetry(po, mailMessage, now - start, now, exception, retry, check, true); + final long end = ThreadNow.millis(); + long nxt = saveSendResult(po, message, end - start, end, exception, retry); + if (nxt > 0) { + planAsyncMail(new AsyncMail(po.getId(), nxt, retry, check, null, message)); + log.debug("schedule tiny-mail next-send, err={}, id={}, subject={}", exception == null, po.getId(), po.getMailSubj()); + } } - return exception == null; + if (exception != null) { + if (exception instanceof RuntimeException) { + throw (RuntimeException) exception; + } + else { + throw new MailSendException("failed tiny-mail, id=" + po.getId() + ", subject=" + po.getMailSubj(), exception); + } + } + + return true; } - private long doAsyncFreshSend(@NotNull WinMailSender po, TinyMailMessage message, boolean retry, boolean check) { + private long doAsyncSend(@NotNull WinMailSender po, @NotNull TinyMailMessage message, boolean retry, boolean check) { + // condition not match if (check && notMatchProp(po)) return -1; - final LocalDateTime md = po.getNextSend(); - final long mds = md == null ? 0 : DateLocaling.sysEpoch(md); + final LocalDateTime ns = po.getNextSend(); + final long nsm = ns == null ? 0 : DateLocaling.sysEpoch(ns); final long now = ThreadNow.millis(); final Long id = po.getId(); final long nxt; - if (mds > now) { - nxt = mds; - log.debug("plan async tiny-mail date={} id={}", md, id); + if (nsm > now) { + nxt = nsm; + log.debug("plan async tiny-mail date={} id={}", ns, id); } else { nxt = now; log.debug("plan async tiny-mail date=now id={}", id); } - // check format - mailSenderManager.checkMessage(message); + // check format, may fail + try { + mailSenderManager.checkMessage(message); + } + catch (Exception e) { + log.error("tiny-mail format error", e); + // save format error without retry + saveSendResult(po, message, 0, now, e, false); + return -1; + } - asyncMails.add(new AsyncMail(id, nxt, retry, check, po, message)); - mailScheduler.schedule(this::doAsyncBatchSend, Instant.ofEpochMilli(nxt)); + planAsyncMail(new AsyncMail(id, nxt, retry, check, po, message)); return nxt; } - private void doAsyncBatchSend() { + private void planAsyncMail(@NotNull AsyncMail mail) { + log.info("planAsyncMail tiny-mail, id={}", mail.id); + synchronized (asyncMailQueue) { + asyncMailQueue.removeIf(it -> it.id == mail.id); + asyncMailQueue.add(mail); + } + planAsyncMail(mail.next); + } + + private void planAsyncMail(@NotNull Collection mails) { + if (mails.isEmpty()) return; + + final Set ids = new HashSet<>(); + long next = -1; + for (AsyncMail m : mails) { + ids.add(m.id); + if (next <= 0) { + next = m.next; + } + else if (m.next < next) { + next = m.next; + } + } + + log.info("planAsyncMail tiny-mail, size={}", ids.size()); + synchronized (asyncMailQueue) { + asyncMailQueue.removeIf(it -> ids.contains(it.id)); + asyncMailQueue.addAll(mails); + } + + planAsyncMail(next); + } + + private void planAsyncMail(long next) { + if (next <= 0) { + log.debug("planAsyncMail tiny-mail, skip={}", next); + return; + } + + if (log.isDebugEnabled()) { + log.debug("planAsyncMail tiny-mail, next={}", DateLocaling.sysLdt(next)); + } + + final long nxt = (next / 1_000L + 1) * 1_000L; // ceiling to second + synchronized (asyncMailSched) { + asyncMailSched.computeIfAbsent(nxt, k -> + taskScheduler.schedule(this::sendAsyncMail, Instant.ofEpochMilli(nxt)) + ); + } + } + + private void sendAsyncMail() { final long start = ThreadNow.millis(); - final int bz = tinyMailServiceProp.getBatchSize(); + final int count = Math.max(tinyMailServiceProp.getBatchSize(), 1); + final HashMap mails = new HashMap<>(count); + final HashMap freshPo = new HashMap<>(count); + final ArrayList dirtyIds = new ArrayList<>(count); + final ArrayList messages = new ArrayList<>(count); + final ArrayList nexts = new ArrayList<>(count); try { - final AtomicInteger count = new AtomicInteger(bz > 0 ? bz : 1); - final HashMap mails = new HashMap<>(count.get()); - asyncMails.removeIf(it -> { - if (count.get() <= 0) return false; - if (it.next > start) { - return false; + while (true) { + mails.clear(); + freshPo.clear(); + dirtyIds.clear(); + messages.clear(); + nexts.clear(); + + // get TopN by prioriy, remove dupli + synchronized (asyncMailQueue) { + asyncMailQueue.removeIf(it -> { + if (it.next > start) return false; + if (mails.size() >= count) return mails.containsKey(it.id); + + mails.put(it.id, it); + return true; + }); } - else { - mails.put(it.id, it); - count.decrementAndGet(); - return true; - } - }); - if (mails.isEmpty()) return; + if (mails.isEmpty()) return; - final Map freshPo = new HashMap<>(); - final List dirtyIds = new ArrayList<>(); - for (AsyncMail am : mails.values()) { - if (am.fresher == null) { - dirtyIds.add(am.id); - } - else { - freshPo.put(am.id, am.fresher); + for (AsyncMail am : mails.values()) { + if (am.fresher == null) { + dirtyIds.add(am.id); + } + else { + freshPo.put(am.id, am.fresher); + } } - } - if (!dirtyIds.isEmpty()) { - final WinMailSenderTable t = winMailSenderDao.getTable(); - winMailSenderDao - .ctx() - .selectFrom(t) - .where(t.Id.in(dirtyIds)) - .fetchInto(WinMailSender.class) - .forEach(po -> freshPo.put(po.getId(), po)); - } + if (!dirtyIds.isEmpty()) { + final WinMailSenderTable t = winMailSenderDao.getTable(); + // mails >= freshPo + dirtyIds(db may less) + winMailSenderDao + .ctx() + .selectFrom(t) + .where(t.Id.in(dirtyIds)) + .fetchInto(WinMailSender.class) + .forEach(po -> freshPo.put(po.getId(), po)); + } - final List messages = new ArrayList<>(freshPo.size()); - for (WinMailSender po : freshPo.values()) { - final AsyncMail am = mails.get(po.getId()); + for (WinMailSender po : freshPo.values()) { + final AsyncMail am = mails.get(po.getId()); + if (am == null) continue; // never null - if (am != null && am.check && (notMatchProp(po) || notNextLock(po, start))) { - continue; - } + if (am.check && (notMatchProp(po) || notNextLock(po, start))) { + continue; + } - if (am != null && am.message != null) { - messages.add(am.message); - } - else { - final String conf = po.getMailConf(); - final TinyMailConfig config = mailConfigProvider.bynamedConfig(conf); - if (config == null) { - log.warn("mail conf={} not found", conf); + if (am.message != null) { + messages.add(am.message); } else { - messages.add(makeMailMessage(config, po, null)); + final String conf = po.getMailConf(); + final TinyMailConfig config = mailConfigProvider.bynamedConfig(conf); + if (config == null) { + log.warn("tiny-mail conf={} not found", conf); + } + else { + messages.add(makeMailMessage(config, po, null)); + } + } + } + + final List brs = mailSenderManager.batchSend(messages); + + for (BatchResult br : brs) { + final TinyMailMessage msg = br.getTinyMessage(); + final WinMailSender po = freshPo.get(msg.getBizId()); // must not null + final AsyncMail am = mails.get(po.getId()); + if (am == null) continue; // never null + + long nxt = saveSendResult(po, msg, br.getCostMillis(), br.getExitMillis(), br.getException(), am.retry); + if (nxt > 0) { + nexts.add(new AsyncMail(po.getId(), nxt, am.retry, am.check, null, msg)); } } - } - final List results = mailSenderManager.batchSend(messages); - for (BatchResult result : results) { - final TinyMailMessage msg = result.getTinyMessage(); - final WinMailSender po = freshPo.get(msg.getBizId()); // must not null - final AsyncMail am = mails.get(po.getId()); - saveStatusAndRetry(po, msg, result.getCostMillis(), result.getDoneMillis(), result.getException(), am != null && am.retry, am != null && am.check, false); + planAsyncMail(nexts); } } finally { - final int size = asyncMails.size(); - if (size > 0) { - final long next = start + tinyMailServiceProp.getTryNext().toMillis(); - mailScheduler.schedule(this::doAsyncBatchSend, Instant.ofEpochMilli(next)); - if (size > tinyMailServiceProp.getWarnSize()) { - log.warn("plan next tiny-mail warn-size={}, idle={}", size, tinyMailServiceProp.getTryNext()); + final int ws = tinyMailServiceProp.getWarnSize(); + final int qs; + synchronized (asyncMailQueue) { + qs = asyncMailQueue.size(); + } + if (qs > 0) { + planAsyncMail(start + tinyMailServiceProp.getTryNext().toMillis()); + if (qs > ws) { + log.warn("plan tiny-mail queue-size={}, idle={}", qs, tinyMailServiceProp.getTryNext()); } else { - log.debug("plan next tiny-mail size={}, idle={}", size, tinyMailServiceProp.getTryNext()); + log.debug("plan tiny-mail queue-size={}, idle={}", qs, tinyMailServiceProp.getTryNext()); } } + + trimAsyncMailSched(); + } + } + + private final AtomicInteger trimSchedConter = new AtomicInteger(0); + @Setter @Getter + private int maxAsyncSched = 1; + + private void trimAsyncMailSched() { + synchronized (trimSchedConter) { + if (trimSchedConter.get() > maxAsyncSched) return; + trimSchedConter.incrementAndGet(); } + + taskScheduler.schedule(() -> { + trimSchedConter.decrementAndGet(); + + final int ts; + synchronized (asyncMailSched) { + asyncMailSched.entrySet().removeIf(it -> it.getValue().isDone()); + ts = asyncMailSched.size(); + } + + final int ws = tinyMailServiceProp.getWarnSize(); + if (ts > ws) { + log.warn("plan tiny-mail sched-size={}", ts); + } + else { + log.debug("plan tiny-mail sched-size={}", ts); + } + } + , Instant.ofEpochMilli(ThreadNow.millis() + 1_000) + ); } @Nullable @@ -748,7 +916,7 @@ private Map resourceString(String jsonMap) { } @Data - private static class AsyncMail implements Comparable { + public static class AsyncMail implements Comparable { private final long id; private final long next; private final boolean retry; diff --git a/radiant/tiny-mail/src/main/java/pro/fessional/wings/tiny/mail/spring/prop/TinyMailServiceProp.java b/radiant/tiny-mail/src/main/java/pro/fessional/wings/tiny/mail/spring/prop/TinyMailServiceProp.java index 7a279ae69..c506bfff5 100644 --- a/radiant/tiny-mail/src/main/java/pro/fessional/wings/tiny/mail/spring/prop/TinyMailServiceProp.java +++ b/radiant/tiny-mail/src/main/java/pro/fessional/wings/tiny/mail/spring/prop/TinyMailServiceProp.java @@ -60,17 +60,26 @@ public class TinyMailServiceProp { * * @see #Key$warnSize */ - private int warnSize = 1000; + private int warnSize = 50; public static final String Key$warnSize = Key + ".warn-size"; /** - * how long after start, scan for unsent mail, `0` for no scan. + * idle time after afterPropertiesSet to scan for unsent/misfired mail, `<=0` for disable. * * @see #Key$bootScan + * @see #Key$scanIdle */ private Duration bootScan = Duration.ofSeconds(60); public static final String Key$bootScan = Key + ".boot-scan"; + /** + * idle time to scan for unsent/misfired mail. `<=0` for disable. + * + * @see #Key$scanIdle + */ + private Duration scanIdle = Duration.ofMinutes(5); + public static final String Key$scanIdle = Key + ".scan-idle"; + /** * whether to send emails from this app only. * diff --git a/radiant/tiny-mail/src/main/resources/wings-conf/wings-tinymail-service-79.properties b/radiant/tiny-mail/src/main/resources/wings-conf/wings-tinymail-service-79.properties index 129a85b22..872510e71 100644 --- a/radiant/tiny-mail/src/main/resources/wings-conf/wings-tinymail-service-79.properties +++ b/radiant/tiny-mail/src/main/resources/wings-conf/wings-tinymail-service-79.properties @@ -10,8 +10,10 @@ wings.tiny.mail.service.try-next=1m wings.tiny.mail.service.batch-size=10 ## if this capacity is exceeded, log it as Warn. wings.tiny.mail.service.warn-size=50 -## how long after start, scan for unsent mail, `0` for no scan. +## idle time after afterPropertiesSet to scan for unsent/misfired mail, `<=0` for disable wings.tiny.mail.service.boot-scan=60s +## idle time to scan for unsent/misfired mail. `<=0` for disable. +wings.tiny.mail.service.scan-idle=5m ## whether to send emails from this app only. wings.tiny.mail.service.only-app=false ## whether to send emails from this RumMode only. diff --git a/radiant/tiny-mail/src/test/java/pro/fessional/wings/tiny/app/conf/TestStatusHookConfiguration.java b/radiant/tiny-mail/src/test/java/pro/fessional/wings/tiny/app/conf/TestStatusHookConfiguration.java index e3b53edc5..f5c00ae84 100644 --- a/radiant/tiny-mail/src/test/java/pro/fessional/wings/tiny/app/conf/TestStatusHookConfiguration.java +++ b/radiant/tiny-mail/src/test/java/pro/fessional/wings/tiny/app/conf/TestStatusHookConfiguration.java @@ -5,7 +5,11 @@ import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import pro.fessional.wings.slardar.notice.DingTalkNotice; +import pro.fessional.wings.tiny.app.service.TestMailSenderManager; +import pro.fessional.wings.tiny.mail.sender.MailSenderManager; +import pro.fessional.wings.tiny.mail.sender.MailSenderProvider; import pro.fessional.wings.tiny.mail.service.TinyMailService; +import pro.fessional.wings.tiny.mail.spring.prop.TinyMailSenderProp; /** * @author trydofor @@ -21,8 +25,14 @@ public TinyMailService.StatusHook gmailStatusHook(@Autowired(required = false) D if (notice != null) { notice.send("hook mail subj=" + po.getMailSubj() + ", cost=" + cost, po.getMailText()); } - log.info("hook mail subj=" + po.getMailSubj() + ", cost" + cost, exception); - return exception != null; + log.info("hook mail subj=" + po.getMailSubj() + ", cost=" + cost, exception); + return false; }; } + + @Bean + public MailSenderManager mailSenderManager(TinyMailSenderProp senderProp, MailSenderProvider senderProvider) { + log.info("TinyMail spring-bean mailSenderManager"); + return new TestMailSenderManager(senderProp, senderProvider); + } } diff --git a/radiant/tiny-mail/src/test/java/pro/fessional/wings/tiny/app/service/TestMailSenderManager.java b/radiant/tiny-mail/src/test/java/pro/fessional/wings/tiny/app/service/TestMailSenderManager.java new file mode 100644 index 000000000..7d6610162 --- /dev/null +++ b/radiant/tiny-mail/src/test/java/pro/fessional/wings/tiny/app/service/TestMailSenderManager.java @@ -0,0 +1,46 @@ +package pro.fessional.wings.tiny.app.service; + +import lombok.extern.slf4j.Slf4j; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.springframework.mail.MailParseException; +import pro.fessional.mirana.time.ThreadNow; +import pro.fessional.wings.tiny.mail.sender.MailSenderManager; +import pro.fessional.wings.tiny.mail.sender.MailSenderProvider; +import pro.fessional.wings.tiny.mail.sender.MailWaitException; +import pro.fessional.wings.tiny.mail.sender.TinyMailMessage; +import pro.fessional.wings.tiny.mail.spring.prop.TinyMailSenderProp; + +import java.util.HashSet; + +/** + * @author trydofor + * @since 2024-07-11 + */ +@Slf4j +public class TestMailSenderManager extends MailSenderManager { + + private final HashSet exception1st = new HashSet<>(); + + public TestMailSenderManager(TinyMailSenderProp senderProp, MailSenderProvider senderProvider) { + super(senderProp, senderProvider); + } + + @Override + public void singleSend(@NotNull TinyMailMessage message, long maxWait, @Nullable MimeMessagePrepareHelper preparer) { + super.singleSend(message, maxWait, preparer); + + if (exception1st.add(message.getBizId())) { + String text = message.getSubject(); + if (text.contains("MailWaitException")) { + throw new MailWaitException(ThreadNow.millis() + 5_000, false, false, new IllegalStateException("Mock")); + } + if (text.contains("MailParseException")) { + throw new MailParseException("Mock"); + } + if (text.contains("RuntimeException")) { + throw new RuntimeException("Mock"); + } + } + } +} diff --git a/radiant/tiny-mail/src/test/java/pro/fessional/wings/tiny/mail/service/TinyMailServiceDbTest.java b/radiant/tiny-mail/src/test/java/pro/fessional/wings/tiny/mail/service/TinyMailServiceDbTest.java new file mode 100644 index 000000000..8fb3ac442 --- /dev/null +++ b/radiant/tiny-mail/src/test/java/pro/fessional/wings/tiny/mail/service/TinyMailServiceDbTest.java @@ -0,0 +1,159 @@ +package pro.fessional.wings.tiny.mail.service; + +import io.qameta.allure.TmsLink; +import lombok.Setter; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.mail.MailProperties; +import org.springframework.boot.test.context.SpringBootTest; +import pro.fessional.mirana.time.Sleep; +import pro.fessional.mirana.time.ThreadNow; +import pro.fessional.wings.faceless.convention.EmptySugar; +import pro.fessional.wings.tiny.mail.TestingMailUtil; +import pro.fessional.wings.tiny.mail.database.autogen.tables.daos.WinMailSenderDao; +import pro.fessional.wings.tiny.mail.database.autogen.tables.pojos.WinMailSender; +import pro.fessional.wings.tiny.mail.service.impl.TinyMailServiceImpl; +import pro.fessional.wings.tiny.mail.spring.prop.TinyMailServiceProp; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.TreeMap; +import java.util.concurrent.ScheduledFuture; + +/** + * @author trydofor + * @since 2023-01-10 + */ +@SpringBootTest(properties = { + "wings.tiny.mail.service.boot-scan=0", + "wings.tiny.mail.service.scan-idle=0", + "wings.tiny.mail.service.try-next=3s", + "wings.tiny.mail.service.batch-size=2", + "wings.tiny.mail.service.warn-size=5", + "logging.level.pro.fessional.wings.tiny.mail=debug", +}) +@Slf4j +class TinyMailServiceDbTest { + + @Setter(onMethod_ = { @Autowired }) + protected TinyMailServiceImpl tinyMailService; + + @Setter(onMethod_ = { @Autowired }) + protected MailProperties mailProperties; + + @Setter(onMethod_ = { @Autowired }) + protected TinyMailServiceProp tinyMailServiceProp; + + @Setter(onMethod_ = { @Autowired }) + protected WinMailSenderDao winMailSenderDao; + + @Test + @TmsLink("C15006") + void mockData() { + bootScan(); + sendError(); + } + + void bootScan() { + String subject = TestingMailUtil.dryrun("TinyMailService bootScan", mailProperties); + TinyMailPlain mail0 = new TinyMailPlain(); + mail0.setSubject(subject); + mail0.setContent("bootScan"); + long id = tinyMailService.save(mail0); + Assertions.assertTrue(id > 0); + // before boot scan + WinMailSender po0 = winMailSenderDao.fetchOneById(id); + Assertions.assertTrue(EmptySugar.nonEmptyValue(po0.getNextSend())); + Assertions.assertTrue(EmptySugar.asEmptyValue(po0.getLastSend())); + Assertions.assertTrue(EmptySugar.asEmptyValue(po0.getLastDone())); + Assertions.assertTrue(StringUtils.isBlank(po0.getLastFail())); + Assertions.assertEquals(0, po0.getSumFail()); + Assertions.assertEquals(0, po0.getSumSend()); + Assertions.assertEquals(0, po0.getSumDone()); + + // wait boot scan and send + tinyMailService.scan(); // scan now + long ms = 5_000; + Sleep.ignoreInterrupt(ms); + log.info("after boot scan, slept={}", ms); + WinMailSender po1 = winMailSenderDao.fetchOneById(id); + Assertions.assertTrue(EmptySugar.asEmptyValue(po1.getNextSend())); + Assertions.assertTrue(EmptySugar.nonEmptyValue(po1.getLastSend())); + Assertions.assertTrue(EmptySugar.nonEmptyValue(po1.getLastDone())); + Assertions.assertTrue(StringUtils.isBlank(po0.getLastFail())); + Assertions.assertEquals(0, po1.getSumFail()); + Assertions.assertEquals(1, po1.getSumSend()); + Assertions.assertEquals(1, po1.getSumDone()); + } + + void sendError() { + int time = 10; + Set ids = new HashSet<>(); + String subj = TestingMailUtil.dryrun("TinyMailService", mailProperties); + for (int i = 0; i < time; i++) { + TinyMailPlain mail0 = new TinyMailPlain(); + boolean err = i % 3 == 0; + mail0.setSubject(subj + (err ? " RuntimeException " : " ") + i); + mail0.setContent(""); // mock + long id = tinyMailService.save(mail0); + ids.add(id); + + try { + tinyMailService.send(id, true, true); + if (err) Assertions.fail(); + } + catch (Exception e) { + Assertions.assertTrue(e.getMessage().contains("Mock")); + } + + WinMailSender po0 = winMailSenderDao.fetchOneById(id); + if (err) { + Assertions.assertTrue(po0.getNextSend().isAfter(ThreadNow.localDateTime())); + Assertions.assertTrue(StringUtils.isNotBlank(po0.getLastFail())); + Assertions.assertEquals(1, po0.getSumFail()); + Assertions.assertEquals(1, po0.getSumSend()); + Assertions.assertEquals(0, po0.getSumDone()); + } + else { + Assertions.assertTrue(EmptySugar.asEmptyValue(po0.getNextSend())); + Assertions.assertTrue(StringUtils.isBlank(po0.getLastFail())); + Assertions.assertEquals(0, po0.getSumFail()); + Assertions.assertEquals(1, po0.getSumSend()); + Assertions.assertEquals(1, po0.getSumDone()); + } + } + + long ms = tinyMailServiceProp.getTryNext().toMillis() * 2; + Sleep.ignoreInterrupt(ms); + log.info("after try next, slept={}", ms); + + List pos = winMailSenderDao.fetchById(ids); + for (WinMailSender po : pos) { + Assertions.assertTrue(EmptySugar.asEmptyValue(po.getNextSend())); + Assertions.assertTrue(EmptySugar.nonEmptyValue(po.getLastSend())); + Assertions.assertTrue(StringUtils.isBlank(po.getLastFail())); + if (po.getMailSubj().contains("RuntimeException")) { + Assertions.assertEquals(1, po.getSumFail()); + Assertions.assertEquals(2, po.getSumSend()); + Assertions.assertEquals(1, po.getSumDone()); + } + else { + + Assertions.assertEquals(0, po.getSumFail()); + Assertions.assertEquals(1, po.getSumSend()); + Assertions.assertEquals(1, po.getSumDone()); + } + } + + Sleep.ignoreInterrupt(2_000L); + ArrayList queue = tinyMailService.listAsyncMailQueue(); + Assertions.assertTrue(queue.isEmpty()); + TreeMap> sched = tinyMailService.listAsyncMailSched(); + Assertions.assertTrue(sched.isEmpty()); + } +} diff --git a/radiant/tiny-mail/src/test/java/pro/fessional/wings/tiny/mail/service/TinyMailServiceTest.java b/radiant/tiny-mail/src/test/java/pro/fessional/wings/tiny/mail/service/TinyMailServiceTest.java index e39c8c7ac..fd24892d7 100644 --- a/radiant/tiny-mail/src/test/java/pro/fessional/wings/tiny/mail/service/TinyMailServiceTest.java +++ b/radiant/tiny-mail/src/test/java/pro/fessional/wings/tiny/mail/service/TinyMailServiceTest.java @@ -20,15 +20,16 @@ * @since 2023-01-10 */ @SpringBootTest(properties = { - "wings.tiny.mail.service.boot-scan=0", + "wings.tiny.mail.service.scan-idle=0", + "wings.tiny.mail.service.boot-scan=0", }) @Slf4j class TinyMailServiceTest { - @Setter(onMethod_ = {@Autowired}) + @Setter(onMethod_ = { @Autowired }) protected TinyMailService tinyMailService; - @Setter(onMethod_ = {@Autowired}) + @Setter(onMethod_ = { @Autowired }) protected MailProperties mailProperties; @Test diff --git a/radiant/tiny-mail/src/test/resources/application.properties b/radiant/tiny-mail/src/test/resources/application.properties index 0dfb08897..ffef63d5b 100644 --- a/radiant/tiny-mail/src/test/resources/application.properties +++ b/radiant/tiny-mail/src/test/resources/application.properties @@ -22,3 +22,5 @@ wings.tiny.mail.sender.err-auth=60s wings.faceless.flywave.auto-init=true wings.faceless.flywave.fit.tiny-mail.revi=2019_0512_01L, 2019_0520_01L, 2020_1027_01L +wings.enabled.pro.fessional.wings.tiny.mail.spring.bean.TinyMailConfiguration.mailSenderManager=false + From d5ca5480384e328da4345cc9ea4e1a35f33ede34 Mon Sep 17 00:00:00 2001 From: trydofor Date: Fri, 12 Jul 2024 18:07:55 +0800 Subject: [PATCH 20/51] =?UTF-8?q?=E2=9C=A8=20tinymail=20support=20lazy=20e?= =?UTF-8?q?dit=20#270?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- observe/docs | 2 +- .../autogen/tables/WinMailSenderTable.java | 10 + .../autogen/tables/daos/WinMailSenderDao.java | 68 ++++++- .../tables/interfaces/IWinMailSender.java | 22 ++- .../autogen/tables/pojos/WinMailSender.java | 186 ++++++++++++++++++ .../tables/records/WinMailSenderRecord.java | 98 ++++++--- .../tiny/mail/sender/MailSenderManager.java | 3 +- .../wings/tiny/mail/service/TinyMail.java | 14 ++ .../wings/tiny/mail/service/TinyMailLazy.java | 40 ++++ .../tiny/mail/service/TinyMailPlain.java | 19 ++ .../service/impl/TinyMailListServiceImpl.java | 4 +- .../service/impl/TinyMailServiceImpl.java | 138 +++++++++++-- .../06-lazy-mail/2021-10-26u06-lazy-mail.sql | 5 + .../06-lazy-mail/2021-10-26v06-lazy-mail.sql | 5 + .../07-mail/2020-10-27v01-tiny_mail.sql | 2 + .../app/conf/TestStatusHookConfiguration.java | 7 +- .../app/service/TestMailSenderManager.java | 33 +++- .../tiny/app/service/TestTinyMailLazy.java | 32 +++ .../mail/service/TinyMailServiceDbTest.java | 79 +++++--- .../wings/faceless/flywave/WingsRevision.java | 1 + 20 files changed, 677 insertions(+), 91 deletions(-) create mode 100644 radiant/tiny-mail/src/main/java/pro/fessional/wings/tiny/mail/service/TinyMailLazy.java create mode 100644 radiant/tiny-mail/src/main/resources/wings-flywave/branch/somefix/06-lazy-mail/2021-10-26u06-lazy-mail.sql create mode 100644 radiant/tiny-mail/src/main/resources/wings-flywave/branch/somefix/06-lazy-mail/2021-10-26v06-lazy-mail.sql create mode 100644 radiant/tiny-mail/src/test/java/pro/fessional/wings/tiny/app/service/TestTinyMailLazy.java diff --git a/observe/docs b/observe/docs index 55df815df..b7f98fdbc 160000 --- a/observe/docs +++ b/observe/docs @@ -1 +1 @@ -Subproject commit 55df815dfb3f2a4c7387d931e122ffee2e9fa27c +Subproject commit b7f98fdbcca854143856b6032bf8c1819b601f15 diff --git a/radiant/tiny-mail/src/main/java-gen/pro/fessional/wings/tiny/mail/database/autogen/tables/WinMailSenderTable.java b/radiant/tiny-mail/src/main/java-gen/pro/fessional/wings/tiny/mail/database/autogen/tables/WinMailSenderTable.java index 186013336..91e95f9f8 100644 --- a/radiant/tiny-mail/src/main/java-gen/pro/fessional/wings/tiny/mail/database/autogen/tables/WinMailSenderTable.java +++ b/radiant/tiny-mail/src/main/java-gen/pro/fessional/wings/tiny/mail/database/autogen/tables/WinMailSenderTable.java @@ -155,6 +155,16 @@ public Class getRecordType() { */ public final TableField MailDate = createField(DSL.name("mail_date"), SQLDataType.LOCALDATETIME(3).nullable(false).defaultValue(DSL.inline("1000-01-01 00:00:00.000", SQLDataType.LOCALDATETIME)), this, ""); + /** + * The column win_mail_sender.lazy_bean. + */ + public final TableField LazyBean = createField(DSL.name("lazy_bean"), SQLDataType.VARCHAR(300).nullable(false).defaultValue(DSL.inline("", SQLDataType.VARCHAR)), this, ""); + + /** + * The column win_mail_sender.lazy_para. + */ + public final TableField LazyPara = createField(DSL.name("lazy_para"), SQLDataType.CLOB, this, ""); + /** * The column win_mail_sender.last_send. */ diff --git a/radiant/tiny-mail/src/main/java-gen/pro/fessional/wings/tiny/mail/database/autogen/tables/daos/WinMailSenderDao.java b/radiant/tiny-mail/src/main/java-gen/pro/fessional/wings/tiny/mail/database/autogen/tables/daos/WinMailSenderDao.java index fc506951c..ff6238682 100644 --- a/radiant/tiny-mail/src/main/java-gen/pro/fessional/wings/tiny/mail/database/autogen/tables/daos/WinMailSenderDao.java +++ b/radiant/tiny-mail/src/main/java-gen/pro/fessional/wings/tiny/mail/database/autogen/tables/daos/WinMailSenderDao.java @@ -26,7 +26,7 @@ @Generated( value = { "https://www.jooq.org", - "jOOQ version:3.18.7", + "jOOQ version:3.18.9", "schema version:2020102701" }, comments = "This class is generated by jOOQ" @@ -707,6 +707,72 @@ public List fetchByMailDateLive(Collectionlazy_bean BETWEEN lowerInclusive AND + * upperInclusive + */ + public List fetchRangeOfLazyBean(String lowerInclusive, String upperInclusive) { + return fetchRange(WinMailSenderTable.WinMailSender.LazyBean, lowerInclusive, upperInclusive); + } + + + public List fetchRangeOfLazyBeanLive(String lowerInclusive, String upperInclusive) { + return fetchRangeLive(WinMailSenderTable.WinMailSender.LazyBean, lowerInclusive, upperInclusive); + } + + /** + * Fetch records that have lazy_bean IN (values) + */ + public List fetchByLazyBean(String... values) { + return fetch(WinMailSenderTable.WinMailSender.LazyBean, values); + } + + public List fetchByLazyBean(Collection values) { + return fetch(WinMailSenderTable.WinMailSender.LazyBean, values); + } + + + public List fetchByLazyBeanLive(String... values) { + return fetchLive(WinMailSenderTable.WinMailSender.LazyBean, values); + } + + public List fetchByLazyBeanLive(Collection values) { + return fetchLive(WinMailSenderTable.WinMailSender.LazyBean, values); + } + + /** + * Fetch records that have lazy_para BETWEEN lowerInclusive AND + * upperInclusive + */ + public List fetchRangeOfLazyPara(String lowerInclusive, String upperInclusive) { + return fetchRange(WinMailSenderTable.WinMailSender.LazyPara, lowerInclusive, upperInclusive); + } + + + public List fetchRangeOfLazyParaLive(String lowerInclusive, String upperInclusive) { + return fetchRangeLive(WinMailSenderTable.WinMailSender.LazyPara, lowerInclusive, upperInclusive); + } + + /** + * Fetch records that have lazy_para IN (values) + */ + public List fetchByLazyPara(String... values) { + return fetch(WinMailSenderTable.WinMailSender.LazyPara, values); + } + + public List fetchByLazyPara(Collection values) { + return fetch(WinMailSenderTable.WinMailSender.LazyPara, values); + } + + + public List fetchByLazyParaLive(String... values) { + return fetchLive(WinMailSenderTable.WinMailSender.LazyPara, values); + } + + public List fetchByLazyParaLive(Collection values) { + return fetchLive(WinMailSenderTable.WinMailSender.LazyPara, values); + } + /** * Fetch records that have last_send BETWEEN lowerInclusive AND * upperInclusive diff --git a/radiant/tiny-mail/src/main/java-gen/pro/fessional/wings/tiny/mail/database/autogen/tables/interfaces/IWinMailSender.java b/radiant/tiny-mail/src/main/java-gen/pro/fessional/wings/tiny/mail/database/autogen/tables/interfaces/IWinMailSender.java index 0a626881a..3dcdad88a 100644 --- a/radiant/tiny-mail/src/main/java-gen/pro/fessional/wings/tiny/mail/database/autogen/tables/interfaces/IWinMailSender.java +++ b/radiant/tiny-mail/src/main/java-gen/pro/fessional/wings/tiny/mail/database/autogen/tables/interfaces/IWinMailSender.java @@ -17,7 +17,7 @@ @Generated( value = { "https://www.jooq.org", - "jOOQ version:3.18.7", + "jOOQ version:3.18.9", "schema version:2020102701" }, comments = "This class is generated by jOOQ" @@ -215,6 +215,26 @@ public interface IWinMailSender extends JournalAware, Serializable { */ public LocalDateTime getMailDate(); + /** + * Setter for win_mail_sender.lazy_bean. + */ + public void setLazyBean(String value); + + /** + * Getter for win_mail_sender.lazy_bean. + */ + public String getLazyBean(); + + /** + * Setter for win_mail_sender.lazy_para. + */ + public void setLazyPara(String value); + + /** + * Getter for win_mail_sender.lazy_para. + */ + public String getLazyPara(); + /** * Setter for win_mail_sender.last_send. */ diff --git a/radiant/tiny-mail/src/main/java-gen/pro/fessional/wings/tiny/mail/database/autogen/tables/pojos/WinMailSender.java b/radiant/tiny-mail/src/main/java-gen/pro/fessional/wings/tiny/mail/database/autogen/tables/pojos/WinMailSender.java index 42dfd2326..4ec032ec9 100644 --- a/radiant/tiny-mail/src/main/java-gen/pro/fessional/wings/tiny/mail/database/autogen/tables/pojos/WinMailSender.java +++ b/radiant/tiny-mail/src/main/java-gen/pro/fessional/wings/tiny/mail/database/autogen/tables/pojos/WinMailSender.java @@ -49,6 +49,8 @@ public class WinMailSender implements IWinMailSender { private String mailFile; private String mailMark; private LocalDateTime mailDate; + private String lazyBean; + private String lazyPara; private LocalDateTime lastSend; private String lastFail; private LocalDateTime lastDone; @@ -86,6 +88,8 @@ public WinMailSender(IWinMailSender value) { this.mailFile = value.getMailFile(); this.mailMark = value.getMailMark(); this.mailDate = value.getMailDate(); + this.lazyBean = value.getLazyBean(); + this.lazyPara = value.getLazyPara(); this.lastSend = value.getLastSend(); this.lastFail = value.getLastFail(); this.lastDone = value.getLastDone(); @@ -122,6 +126,8 @@ public WinMailSender( String mailFile, String mailMark, LocalDateTime mailDate, + String lazyBean, + String lazyPara, LocalDateTime lastSend, String lastFail, LocalDateTime lastDone, @@ -156,6 +162,8 @@ public WinMailSender( this.mailFile = mailFile; this.mailMark = mailMark; this.mailDate = mailDate; + this.lazyBean = lazyBean; + this.lazyPara = lazyPara; this.lastSend = lastSend; this.lastFail = lastFail; this.lastDone = lastDone; @@ -1692,6 +1700,166 @@ public void setMailDateIf(UnaryOperator mailDate) { } + /** + * Getter for win_mail_sender.lazy_bean. + */ + @Override + public String getLazyBean() { + return this.lazyBean; + } + + /** + * Setter for win_mail_sender.lazy_bean. + */ + @Override + public void setLazyBean(String lazyBean) { + this.lazyBean = lazyBean; + } + + @Transient + public void setLazyBeanIf(String lazyBean, boolean bool) { + if (bool) { + this.lazyBean = lazyBean; + } + } + + @Transient + public void setLazyBeanIf(Supplier lazyBean, boolean bool) { + if (bool) { + this.lazyBean = lazyBean.get(); + } + } + + @Transient + public void setLazyBeanIf(String lazyBean, Predicate bool) { + if (bool.test(lazyBean)) { + this.lazyBean = lazyBean; + } + } + + @Transient + public void setLazyBeanIf(String lazyBean, Predicate bool, Supplier... lazyBeans) { + if (bool.test(lazyBean)) { + this.lazyBean = lazyBean; + return; + } + for (Supplier supplier : lazyBeans) { + lazyBean = supplier.get(); + if (bool.test(lazyBean)) { + this.lazyBean = lazyBean; + return; + } + } + } + + @Transient + public void setLazyBeanIfNot(String lazyBean, Predicate bool) { + if (!bool.test(lazyBean)) { + this.lazyBean = lazyBean; + } + } + + @Transient + public void setLazyBeanIfNot(String lazyBean, Predicate bool, Supplier... lazyBeans) { + if (!bool.test(lazyBean)) { + this.lazyBean = lazyBean; + return; + } + for (Supplier supplier : lazyBeans) { + lazyBean = supplier.get(); + if (!bool.test(lazyBean)) { + this.lazyBean = lazyBean; + return; + } + } + } + + @Transient + public void setLazyBeanIf(UnaryOperator lazyBean) { + this.lazyBean = lazyBean.apply(this.lazyBean); + } + + + /** + * Getter for win_mail_sender.lazy_para. + */ + @Override + public String getLazyPara() { + return this.lazyPara; + } + + /** + * Setter for win_mail_sender.lazy_para. + */ + @Override + public void setLazyPara(String lazyPara) { + this.lazyPara = lazyPara; + } + + @Transient + public void setLazyParaIf(String lazyPara, boolean bool) { + if (bool) { + this.lazyPara = lazyPara; + } + } + + @Transient + public void setLazyParaIf(Supplier lazyPara, boolean bool) { + if (bool) { + this.lazyPara = lazyPara.get(); + } + } + + @Transient + public void setLazyParaIf(String lazyPara, Predicate bool) { + if (bool.test(lazyPara)) { + this.lazyPara = lazyPara; + } + } + + @Transient + public void setLazyParaIf(String lazyPara, Predicate bool, Supplier... lazyParas) { + if (bool.test(lazyPara)) { + this.lazyPara = lazyPara; + return; + } + for (Supplier supplier : lazyParas) { + lazyPara = supplier.get(); + if (bool.test(lazyPara)) { + this.lazyPara = lazyPara; + return; + } + } + } + + @Transient + public void setLazyParaIfNot(String lazyPara, Predicate bool) { + if (!bool.test(lazyPara)) { + this.lazyPara = lazyPara; + } + } + + @Transient + public void setLazyParaIfNot(String lazyPara, Predicate bool, Supplier... lazyParas) { + if (!bool.test(lazyPara)) { + this.lazyPara = lazyPara; + return; + } + for (Supplier supplier : lazyParas) { + lazyPara = supplier.get(); + if (!bool.test(lazyPara)) { + this.lazyPara = lazyPara; + return; + } + } + } + + @Transient + public void setLazyParaIf(UnaryOperator lazyPara) { + this.lazyPara = lazyPara.apply(this.lazyPara); + } + + /** * Getter for win_mail_sender.last_send. */ @@ -2935,6 +3103,18 @@ else if (!this.mailMark.equals(other.mailMark)) } else if (!this.mailDate.equals(other.mailDate)) return false; + if (this.lazyBean == null) { + if (other.lazyBean != null) + return false; + } + else if (!this.lazyBean.equals(other.lazyBean)) + return false; + if (this.lazyPara == null) { + if (other.lazyPara != null) + return false; + } + else if (!this.lazyPara.equals(other.lazyPara)) + return false; if (this.lastSend == null) { if (other.lastSend != null) return false; @@ -3045,6 +3225,8 @@ public int hashCode() { result = prime * result + ((this.mailFile == null) ? 0 : this.mailFile.hashCode()); result = prime * result + ((this.mailMark == null) ? 0 : this.mailMark.hashCode()); result = prime * result + ((this.mailDate == null) ? 0 : this.mailDate.hashCode()); + result = prime * result + ((this.lazyBean == null) ? 0 : this.lazyBean.hashCode()); + result = prime * result + ((this.lazyPara == null) ? 0 : this.lazyPara.hashCode()); result = prime * result + ((this.lastSend == null) ? 0 : this.lastSend.hashCode()); result = prime * result + ((this.lastFail == null) ? 0 : this.lastFail.hashCode()); result = prime * result + ((this.lastDone == null) ? 0 : this.lastDone.hashCode()); @@ -3085,6 +3267,8 @@ public String toString() { sb.append(", ").append(mailFile); sb.append(", ").append(mailMark); sb.append(", ").append(mailDate); + sb.append(", ").append(lazyBean); + sb.append(", ").append(lazyPara); sb.append(", ").append(lastSend); sb.append(", ").append(lastFail); sb.append(", ").append(lastDone); @@ -3129,6 +3313,8 @@ public void from(IWinMailSender from) { setMailFile(from.getMailFile()); setMailMark(from.getMailMark()); setMailDate(from.getMailDate()); + setLazyBean(from.getLazyBean()); + setLazyPara(from.getLazyPara()); setLastSend(from.getLastSend()); setLastFail(from.getLastFail()); setLastDone(from.getLastDone()); diff --git a/radiant/tiny-mail/src/main/java-gen/pro/fessional/wings/tiny/mail/database/autogen/tables/records/WinMailSenderRecord.java b/radiant/tiny-mail/src/main/java-gen/pro/fessional/wings/tiny/mail/database/autogen/tables/records/WinMailSenderRecord.java index b9dfa0919..dbb6bd4bd 100644 --- a/radiant/tiny-mail/src/main/java-gen/pro/fessional/wings/tiny/mail/database/autogen/tables/records/WinMailSenderRecord.java +++ b/radiant/tiny-mail/src/main/java-gen/pro/fessional/wings/tiny/mail/database/autogen/tables/records/WinMailSenderRecord.java @@ -20,7 +20,7 @@ @Generated( value = { "https://www.jooq.org", - "jOOQ version:3.18.7", + "jOOQ version:3.18.9", "schema version:2020102701" }, comments = "This class is generated by jOOQ" @@ -334,12 +334,44 @@ public LocalDateTime getMailDate() { return (LocalDateTime) get(18); } + /** + * Setter for win_mail_sender.lazy_bean. + */ + @Override + public void setLazyBean(String value) { + set(19, value); + } + + /** + * Getter for win_mail_sender.lazy_bean. + */ + @Override + public String getLazyBean() { + return (String) get(19); + } + + /** + * Setter for win_mail_sender.lazy_para. + */ + @Override + public void setLazyPara(String value) { + set(20, value); + } + + /** + * Getter for win_mail_sender.lazy_para. + */ + @Override + public String getLazyPara() { + return (String) get(20); + } + /** * Setter for win_mail_sender.last_send. */ @Override public void setLastSend(LocalDateTime value) { - set(19, value); + set(21, value); } /** @@ -347,7 +379,7 @@ public void setLastSend(LocalDateTime value) { */ @Override public LocalDateTime getLastSend() { - return (LocalDateTime) get(19); + return (LocalDateTime) get(21); } /** @@ -355,7 +387,7 @@ public LocalDateTime getLastSend() { */ @Override public void setLastFail(String value) { - set(20, value); + set(22, value); } /** @@ -363,7 +395,7 @@ public void setLastFail(String value) { */ @Override public String getLastFail() { - return (String) get(20); + return (String) get(22); } /** @@ -371,7 +403,7 @@ public String getLastFail() { */ @Override public void setLastDone(LocalDateTime value) { - set(21, value); + set(23, value); } /** @@ -379,7 +411,7 @@ public void setLastDone(LocalDateTime value) { */ @Override public LocalDateTime getLastDone() { - return (LocalDateTime) get(21); + return (LocalDateTime) get(23); } /** @@ -387,7 +419,7 @@ public LocalDateTime getLastDone() { */ @Override public void setLastCost(Integer value) { - set(22, value); + set(24, value); } /** @@ -395,7 +427,7 @@ public void setLastCost(Integer value) { */ @Override public Integer getLastCost() { - return (Integer) get(22); + return (Integer) get(24); } /** @@ -403,7 +435,7 @@ public Integer getLastCost() { */ @Override public void setNextSend(LocalDateTime value) { - set(23, value); + set(25, value); } /** @@ -411,7 +443,7 @@ public void setNextSend(LocalDateTime value) { */ @Override public LocalDateTime getNextSend() { - return (LocalDateTime) get(23); + return (LocalDateTime) get(25); } /** @@ -419,7 +451,7 @@ public LocalDateTime getNextSend() { */ @Override public void setNextLock(Integer value) { - set(24, value); + set(26, value); } /** @@ -427,7 +459,7 @@ public void setNextLock(Integer value) { */ @Override public Integer getNextLock() { - return (Integer) get(24); + return (Integer) get(26); } /** @@ -435,7 +467,7 @@ public Integer getNextLock() { */ @Override public void setSumSend(Integer value) { - set(25, value); + set(27, value); } /** @@ -443,7 +475,7 @@ public void setSumSend(Integer value) { */ @Override public Integer getSumSend() { - return (Integer) get(25); + return (Integer) get(27); } /** @@ -451,7 +483,7 @@ public Integer getSumSend() { */ @Override public void setSumFail(Integer value) { - set(26, value); + set(28, value); } /** @@ -459,7 +491,7 @@ public void setSumFail(Integer value) { */ @Override public Integer getSumFail() { - return (Integer) get(26); + return (Integer) get(28); } /** @@ -467,7 +499,7 @@ public Integer getSumFail() { */ @Override public void setSumDone(Integer value) { - set(27, value); + set(29, value); } /** @@ -475,7 +507,7 @@ public void setSumDone(Integer value) { */ @Override public Integer getSumDone() { - return (Integer) get(27); + return (Integer) get(29); } /** @@ -483,7 +515,7 @@ public Integer getSumDone() { */ @Override public void setMaxFail(Integer value) { - set(28, value); + set(30, value); } /** @@ -491,7 +523,7 @@ public void setMaxFail(Integer value) { */ @Override public Integer getMaxFail() { - return (Integer) get(28); + return (Integer) get(30); } /** @@ -499,7 +531,7 @@ public Integer getMaxFail() { */ @Override public void setMaxDone(Integer value) { - set(29, value); + set(31, value); } /** @@ -507,7 +539,7 @@ public void setMaxDone(Integer value) { */ @Override public Integer getMaxDone() { - return (Integer) get(29); + return (Integer) get(31); } /** @@ -515,7 +547,7 @@ public Integer getMaxDone() { */ @Override public void setRefType(Integer value) { - set(30, value); + set(32, value); } /** @@ -523,7 +555,7 @@ public void setRefType(Integer value) { */ @Override public Integer getRefType() { - return (Integer) get(30); + return (Integer) get(32); } /** @@ -531,7 +563,7 @@ public Integer getRefType() { */ @Override public void setRefKey1(Long value) { - set(31, value); + set(33, value); } /** @@ -539,7 +571,7 @@ public void setRefKey1(Long value) { */ @Override public Long getRefKey1() { - return (Long) get(31); + return (Long) get(33); } /** @@ -547,7 +579,7 @@ public Long getRefKey1() { */ @Override public void setRefKey2(String value) { - set(32, value); + set(34, value); } /** @@ -555,7 +587,7 @@ public void setRefKey2(String value) { */ @Override public String getRefKey2() { - return (String) get(32); + return (String) get(34); } // ------------------------------------------------------------------------- @@ -592,6 +624,8 @@ public void from(IWinMailSender from) { setMailFile(from.getMailFile()); setMailMark(from.getMailMark()); setMailDate(from.getMailDate()); + setLazyBean(from.getLazyBean()); + setLazyPara(from.getLazyPara()); setLastSend(from.getLastSend()); setLastFail(from.getLastFail()); setLastDone(from.getLastDone()); @@ -629,7 +663,7 @@ public WinMailSenderRecord() { /** * Create a detached, initialised WinMailSenderRecord */ - public WinMailSenderRecord(Long id, LocalDateTime createDt, LocalDateTime modifyDt, LocalDateTime deleteDt, Long commitId, String mailApps, String mailRuns, String mailConf, String mailFrom, String mailTo, String mailCc, String mailBcc, String mailReply, String mailSubj, String mailText, Boolean mailHtml, String mailFile, String mailMark, LocalDateTime mailDate, LocalDateTime lastSend, String lastFail, LocalDateTime lastDone, Integer lastCost, LocalDateTime nextSend, Integer nextLock, Integer sumSend, Integer sumFail, Integer sumDone, Integer maxFail, Integer maxDone, Integer refType, Long refKey1, String refKey2) { + public WinMailSenderRecord(Long id, LocalDateTime createDt, LocalDateTime modifyDt, LocalDateTime deleteDt, Long commitId, String mailApps, String mailRuns, String mailConf, String mailFrom, String mailTo, String mailCc, String mailBcc, String mailReply, String mailSubj, String mailText, Boolean mailHtml, String mailFile, String mailMark, LocalDateTime mailDate, String lazyBean, String lazyPara, LocalDateTime lastSend, String lastFail, LocalDateTime lastDone, Integer lastCost, LocalDateTime nextSend, Integer nextLock, Integer sumSend, Integer sumFail, Integer sumDone, Integer maxFail, Integer maxDone, Integer refType, Long refKey1, String refKey2) { super(WinMailSenderTable.WinMailSender); setId(id); @@ -651,6 +685,8 @@ public WinMailSenderRecord(Long id, LocalDateTime createDt, LocalDateTime modify setMailFile(mailFile); setMailMark(mailMark); setMailDate(mailDate); + setLazyBean(lazyBean); + setLazyPara(lazyPara); setLastSend(lastSend); setLastFail(lastFail); setLastDone(lastDone); @@ -694,6 +730,8 @@ public WinMailSenderRecord(WinMailSender value) { setMailFile(value.getMailFile()); setMailMark(value.getMailMark()); setMailDate(value.getMailDate()); + setLazyBean(value.getLazyBean()); + setLazyPara(value.getLazyPara()); setLastSend(value.getLastSend()); setLastFail(value.getLastFail()); setLastDone(value.getLastDone()); diff --git a/radiant/tiny-mail/src/main/java/pro/fessional/wings/tiny/mail/sender/MailSenderManager.java b/radiant/tiny-mail/src/main/java/pro/fessional/wings/tiny/mail/sender/MailSenderManager.java index 236ec2e45..a19ec9102 100644 --- a/radiant/tiny-mail/src/main/java/pro/fessional/wings/tiny/mail/sender/MailSenderManager.java +++ b/radiant/tiny-mail/src/main/java/pro/fessional/wings/tiny/mail/sender/MailSenderManager.java @@ -4,6 +4,7 @@ import jakarta.mail.internet.MimeMessage; import lombok.Getter; import lombok.RequiredArgsConstructor; +import lombok.Setter; import lombok.SneakyThrows; import lombok.extern.slf4j.Slf4j; import org.jetbrains.annotations.NotNull; @@ -476,7 +477,7 @@ public static class BatchResult { private long costMillis = 0; @Getter private long exitMillis = 0; - @Getter + @Getter @Setter private Exception exception; private JavaMailSender mailSender; diff --git a/radiant/tiny-mail/src/main/java/pro/fessional/wings/tiny/mail/service/TinyMail.java b/radiant/tiny-mail/src/main/java/pro/fessional/wings/tiny/mail/service/TinyMail.java index 499f32b4c..823e94f21 100644 --- a/radiant/tiny-mail/src/main/java/pro/fessional/wings/tiny/mail/service/TinyMail.java +++ b/radiant/tiny-mail/src/main/java/pro/fessional/wings/tiny/mail/service/TinyMail.java @@ -87,6 +87,16 @@ public void setBcc(String... bcc) { */ protected LocalDateTime date; + /** + * lazy bean to edit mail if mail_text is null + */ + protected String lazyBean; + + /** + * lazy para of lazy bean + */ + protected String lazyPara; + /** * Max count of fail, defaults to system configuration */ @@ -112,6 +122,10 @@ public void setBcc(String... bcc) { private String refKey2; // + public void setMailLazy(@NotNull TinyMailLazy bean, @Nullable Object para) { + lazyBean = bean.lazyBean(); + lazyPara = bean.lazyPara(para); + } public void setContentText(String content) { this.content = content; diff --git a/radiant/tiny-mail/src/main/java/pro/fessional/wings/tiny/mail/service/TinyMailLazy.java b/radiant/tiny-mail/src/main/java/pro/fessional/wings/tiny/mail/service/TinyMailLazy.java new file mode 100644 index 000000000..4ccbdecc0 --- /dev/null +++ b/radiant/tiny-mail/src/main/java/pro/fessional/wings/tiny/mail/service/TinyMailLazy.java @@ -0,0 +1,40 @@ +package pro.fessional.wings.tiny.mail.service; + +import lombok.Data; +import org.jetbrains.annotations.Nullable; +import org.springframework.core.io.Resource; +import pro.fessional.wings.slardar.fastjson.FastJsonHelper; + +import java.util.Map; + +/** + * @author trydofor + * @since 2024-07-12 + */ +public interface TinyMailLazy { + + /** + * get the registered name of bean, for safe reason + */ + default String lazyBean() { + return this.getClass().getName(); + } + + default String lazyPara(@Nullable Object para) { + return para == null ? null : FastJsonHelper.string(para); + } + + /** + * use lazyPara to edit the lazy mail if returned items is nonnull + */ + @Nullable + Edit lazyEdit(@Nullable String para); + + @Data + class Edit { + private String subject = null; + private String content = null; + private Map attachment = null; + private Boolean html; + } +} diff --git a/radiant/tiny-mail/src/main/java/pro/fessional/wings/tiny/mail/service/TinyMailPlain.java b/radiant/tiny-mail/src/main/java/pro/fessional/wings/tiny/mail/service/TinyMailPlain.java index 7b20b8b5e..818d93a43 100644 --- a/radiant/tiny-mail/src/main/java/pro/fessional/wings/tiny/mail/service/TinyMailPlain.java +++ b/radiant/tiny-mail/src/main/java/pro/fessional/wings/tiny/mail/service/TinyMailPlain.java @@ -1,6 +1,8 @@ package pro.fessional.wings.tiny.mail.service; import lombok.Data; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import java.time.LocalDateTime; import java.util.Collections; @@ -90,6 +92,16 @@ public class TinyMailPlain { */ private LocalDateTime date; + /** + * lazy bean to edit mail if mail_text is null + */ + private String lazyBean; + + /** + * lazy para of lazy bean + */ + private String lazyPara; + /** * Next send time, system time zone, update when non-null */ @@ -169,4 +181,11 @@ public class TinyMailPlain { * Send parameter, whether to check the sending condition, otherwise it is forced to send */ private Boolean check; + + // + public void setMailLazy(@NotNull TinyMailLazy bean, @Nullable Object para) { + lazyBean = bean.lazyBean(); + lazyPara = bean.lazyPara(para); + } + } diff --git a/radiant/tiny-mail/src/main/java/pro/fessional/wings/tiny/mail/service/impl/TinyMailListServiceImpl.java b/radiant/tiny-mail/src/main/java/pro/fessional/wings/tiny/mail/service/impl/TinyMailListServiceImpl.java index 5d366cf8d..375edfff1 100644 --- a/radiant/tiny-mail/src/main/java/pro/fessional/wings/tiny/mail/service/impl/TinyMailListServiceImpl.java +++ b/radiant/tiny-mail/src/main/java/pro/fessional/wings/tiny/mail/service/impl/TinyMailListServiceImpl.java @@ -72,6 +72,8 @@ public class TinyMailListServiceImpl implements TinyMailListService, Initializin bo.setHtml(po.getMailHtml()); bo.setMark(po.getMailMark()); bo.setDate(po.getMailDate()); + bo.setLazyBean(po.getLazyBean()); + bo.setLazyPara(po.getLazyPara()); bo.setCreateDt(po.getCreateDt()); bo.setLastSend(po.getLastSend()); @@ -203,7 +205,7 @@ public void afterPropertiesSet() { t.Id, t.MailApps, t.MailRuns, t.MailConf, t.MailFrom, t.MailTo, t.MailCc, t.MailBcc, t.MailReply, t.MailSubj, /*t.MailText, t.MailFile,*/ - t.MailHtml, t.MailMark, t.MailDate, + t.MailHtml, t.MailMark, t.MailDate, t.LazyBean, /*t.LazyPara,*/ t.CreateDt, t.LastSend, /*t.LastFail,*/ t.LastDone, t.NextSend, t.SumSend, t.SumFail, t.SumDone, t.MaxFail, t.MaxDone, }; diff --git a/radiant/tiny-mail/src/main/java/pro/fessional/wings/tiny/mail/service/impl/TinyMailServiceImpl.java b/radiant/tiny-mail/src/main/java/pro/fessional/wings/tiny/mail/service/impl/TinyMailServiceImpl.java index 33e3fedfb..46a9fd81b 100644 --- a/radiant/tiny-mail/src/main/java/pro/fessional/wings/tiny/mail/service/impl/TinyMailServiceImpl.java +++ b/radiant/tiny-mail/src/main/java/pro/fessional/wings/tiny/mail/service/impl/TinyMailServiceImpl.java @@ -20,6 +20,7 @@ import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler; import org.springframework.stereotype.Service; import pro.fessional.mirana.best.AssertArgs; +import pro.fessional.mirana.best.AssertState; import pro.fessional.mirana.cast.BoxedCastUtil; import pro.fessional.mirana.cond.IfSetter; import pro.fessional.mirana.pain.ThrowableUtil; @@ -45,6 +46,7 @@ import pro.fessional.wings.tiny.mail.sender.TinyMailConfig; import pro.fessional.wings.tiny.mail.sender.TinyMailMessage; import pro.fessional.wings.tiny.mail.service.TinyMail; +import pro.fessional.wings.tiny.mail.service.TinyMailLazy; import pro.fessional.wings.tiny.mail.service.TinyMailPlain; import pro.fessional.wings.tiny.mail.service.TinyMailService; import pro.fessional.wings.tiny.mail.spring.prop.TinyMailServiceProp; @@ -62,6 +64,7 @@ import java.util.PriorityQueue; import java.util.Set; import java.util.TreeMap; +import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ScheduledFuture; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicLong; @@ -97,12 +100,15 @@ public class TinyMailServiceImpl implements TinyMailService, InitializingBean { protected ResourceLoader resourceLoader; @Setter(onMethod_ = { @Autowired(required = false) }) protected List statusHooks; + @Setter(onMethod_ = { @Autowired(required = false) }) + protected Map namedLazyBean; // init by afterPropertiesSet protected ThreadPoolTaskScheduler taskScheduler; + protected Map lazyBeanHolder; - private final PriorityQueue asyncMailQueue = new PriorityQueue<>(); - private final TreeMap> asyncMailSched = new TreeMap<>(); + protected final PriorityQueue asyncMailQueue = new PriorityQueue<>(); + protected final TreeMap> asyncMailSched = new TreeMap<>(); @Override public boolean send(@NotNull TinyMail message, boolean retry) { @@ -220,6 +226,8 @@ public long save(@NotNull TinyMailPlain msg) { po.setMailFile(toString(msg.getAttachment())); po.setMailMark(msg.getMark()); po.setMailDate(md); + po.setLazyBean(msg.getLazyBean()); + po.setLazyPara(msg.getLazyPara()); // PropertyMapper IfSetter.nonnull(po::setMaxFail, msg.getMaxFail()); @@ -345,6 +353,18 @@ public void afterPropertiesSet() { taskScheduler.initialize(); log.info("tiny-mail mailScheduler, prefix=" + taskScheduler.getThreadNamePrefix()); + if (namedLazyBean != null && !namedLazyBean.isEmpty()) { + lazyBeanHolder = new ConcurrentHashMap<>(); + for (var en : namedLazyBean.entrySet()) { + TinyMailLazy bean = en.getValue(); + TinyMailLazy old = lazyBeanHolder.put(bean.lazyBean(), bean); + if (old != null) { + throw new IllegalStateException("lazy bean name existed, name=" + old.lazyBean() + ", new-bean=" + en.getKey()); + } + } + log.info("tiny-mail TinyMailLazy, size=" + lazyBeanHolder.size()); + } + final long idle = tinyMailServiceProp.getBootScan().toMillis(); if (idle > 0) { log.info("tiny-mail schedule boot-scan after={} ms", idle); @@ -409,6 +429,8 @@ protected WinMailSender saveMailSender(@NotNull TinyMailConfig config, @NotNull final LocalDateTime md = msg.getDate(); po.setMailDate(md); + po.setLazyBean(msg.getLazyBean()); + po.setLazyPara(msg.getLazyPara()); po.setMaxFail(BoxedCastUtil.orElse(msg.getMaxFail(), tinyMailServiceProp.getMaxFail())); po.setMaxDone(BoxedCastUtil.orElse(msg.getMaxDone(), tinyMailServiceProp.getMaxDone())); @@ -599,6 +621,61 @@ else if (exception instanceof MailParseException || exception instanceof Messagi return nextSend; } + protected boolean editLazyMail(@NotNull WinMailSender po, @NotNull TinyMailMessage message) { + // nonnull means no need to edit + if (message.getContent() != null) return false; + + var bean = lazyBeanHolder.get(po.getLazyBean()); + AssertState.notNull(bean, "TinyMailLazy not found, bean={}", po.getLazyBean()); + + var edit = bean.lazyEdit(po.getLazyPara()); + if (edit == null) return false; + + final WinMailSenderTable t = winMailSenderDao.getTable(); + final Map setter = new HashMap<>(); + + Boolean html = edit.getHtml(); + if(html != null){ + setter.put(t.MailHtml, html); + message.setHtml(html); + } + + String subj = edit.getSubject(); + if(subj != null){ + setter.put(t.MailSubj, subj); + message.setSubject(subj); + } + + String text = edit.getContent(); + if(text != null){ + setter.put(t.MailText, text); + message.setContent(text); + } + + Map file = edit.getAttachment(); + if(file != null && !file.isEmpty()){ + setter.put(t.MailFile, stringResource(file)); + message.setAttachment(file); + } + + if(setter.isEmpty()) return false; + + Long id = po.getId(); + log.info("lazy edit tiny-mail, id={}", id); + + journalService.commit(Jane.Lazify, journal -> { + setter.put(t.CommitId, journal.getCommitId()); + setter.put(t.ModifyDt, journal.getCommitDt()); + winMailSenderDao.ctx() + .update(t) + .set(setter) + .where(t.Id.eq(id)) + .execute(); + }); + + return true; + } + private boolean doSyncSend(@NotNull WinMailSender po, @NotNull TinyMailMessage message, boolean retry, boolean check) { final long start; if (check) { @@ -615,6 +692,7 @@ private boolean doSyncSend(@NotNull WinMailSender po, @NotNull TinyMailMessage m Exception exception = null; try { + editLazyMail(po, message); mailSenderManager.singleSend(message); } catch (Exception e) { @@ -625,7 +703,7 @@ private boolean doSyncSend(@NotNull WinMailSender po, @NotNull TinyMailMessage m long nxt = saveSendResult(po, message, end - start, end, exception, retry); if (nxt > 0) { planAsyncMail(new AsyncMail(po.getId(), nxt, retry, check, null, message)); - log.debug("schedule tiny-mail next-send, err={}, id={}, subject={}", exception == null, po.getId(), po.getMailSubj()); + log.debug("plan tiny-mail next-send, err={}, id={}, subject={}", exception == null, po.getId(), po.getMailSubj()); } } @@ -649,33 +727,39 @@ private long doAsyncSend(@NotNull WinMailSender po, @NotNull TinyMailMessage mes final long nsm = ns == null ? 0 : DateLocaling.sysEpoch(ns); final long now = ThreadNow.millis(); final Long id = po.getId(); - final long nxt; + + long next; if (nsm > now) { - nxt = nsm; + next = nsm; log.debug("plan async tiny-mail date={} id={}", ns, id); } else { - nxt = now; + next = now; log.debug("plan async tiny-mail date=now id={}", id); } - // check format, may fail + boolean lzk = false; try { + lzk = editLazyMail(po, message); // lazy ok mailSenderManager.checkMessage(message); } catch (Exception e) { log.error("tiny-mail format error", e); - // save format error without retry - saveSendResult(po, message, 0, now, e, false); - return -1; + long nx = saveSendResult(po, message, 0, now, e, !lzk && retry); // retry if lazy fail + if (nx > 0) { + next = nx; + } + else { + return -1; + } } - planAsyncMail(new AsyncMail(id, nxt, retry, check, po, message)); - return nxt; + planAsyncMail(new AsyncMail(id, next, retry, check, po, message)); + return next; } private void planAsyncMail(@NotNull AsyncMail mail) { - log.info("planAsyncMail tiny-mail, id={}", mail.id); + log.info("plan async tiny-mail, id={}", mail.id); synchronized (asyncMailQueue) { asyncMailQueue.removeIf(it -> it.id == mail.id); asyncMailQueue.add(mail); @@ -698,7 +782,7 @@ else if (m.next < next) { } } - log.info("planAsyncMail tiny-mail, size={}", ids.size()); + log.info("plan async tiny-mail, size={}", ids.size()); synchronized (asyncMailQueue) { asyncMailQueue.removeIf(it -> ids.contains(it.id)); asyncMailQueue.addAll(mails); @@ -709,12 +793,12 @@ else if (m.next < next) { private void planAsyncMail(long next) { if (next <= 0) { - log.debug("planAsyncMail tiny-mail, skip={}", next); + log.debug("plan async tiny-mail, skip={}", next); return; } if (log.isDebugEnabled()) { - log.debug("planAsyncMail tiny-mail, next={}", DateLocaling.sysLdt(next)); + log.debug("plan async tiny-mail, next={}", DateLocaling.sysLdt(next)); } final long nxt = (next / 1_000L + 1) * 1_000L; // ceiling to second @@ -783,8 +867,9 @@ private void sendAsyncMail() { continue; } + TinyMailMessage msg = null; if (am.message != null) { - messages.add(am.message); + msg = am.message; } else { final String conf = po.getMailConf(); @@ -793,8 +878,22 @@ private void sendAsyncMail() { log.warn("tiny-mail conf={} not found", conf); } else { - messages.add(makeMailMessage(config, po, null)); + msg = makeMailMessage(config, po, null); + } + } + + if (msg != null) { + try { + editLazyMail(po, msg); + } + catch (Exception e) { + log.error("tiny-mail lazy error", e); + long nxt = saveSendResult(po, msg, 0, start, e, am.retry); + if (nxt > 0) { + nexts.add(new AsyncMail(po.getId(), nxt, am.retry, am.check, null, msg)); + } } + messages.add(msg); } } @@ -934,6 +1033,7 @@ public int compareTo(@NotNull TinyMailServiceImpl.AsyncMail o) { public enum Jane { Insert, - Update + Update, + Lazify } } diff --git a/radiant/tiny-mail/src/main/resources/wings-flywave/branch/somefix/06-lazy-mail/2021-10-26u06-lazy-mail.sql b/radiant/tiny-mail/src/main/resources/wings-flywave/branch/somefix/06-lazy-mail/2021-10-26u06-lazy-mail.sql new file mode 100644 index 000000000..b020230d6 --- /dev/null +++ b/radiant/tiny-mail/src/main/resources/wings-flywave/branch/somefix/06-lazy-mail/2021-10-26u06-lazy-mail.sql @@ -0,0 +1,5 @@ +ALTER TABLE `win_mail_sender` + DROP COLUMN `lazy_bean`, + DROP COLUMN `lazy_para`; + +-- CALL FLYWAVE('2021-10-26u06-lazy-mail.sql'); \ No newline at end of file diff --git a/radiant/tiny-mail/src/main/resources/wings-flywave/branch/somefix/06-lazy-mail/2021-10-26v06-lazy-mail.sql b/radiant/tiny-mail/src/main/resources/wings-flywave/branch/somefix/06-lazy-mail/2021-10-26v06-lazy-mail.sql new file mode 100644 index 000000000..1d278fe05 --- /dev/null +++ b/radiant/tiny-mail/src/main/resources/wings-flywave/branch/somefix/06-lazy-mail/2021-10-26v06-lazy-mail.sql @@ -0,0 +1,5 @@ +ALTER TABLE `win_mail_sender` + ADD COLUMN `lazy_bean` VARCHAR(300) NOT NULL DEFAULT '' COMMENT 'lazy bean to edit mail if mail_text is null' AFTER `mail_date`, + ADD COLUMN `lazy_para` TEXT NULL COMMENT 'lazy para of lazy bean' AFTER `lazy_bean`; + +-- CALL FLYWAVE('2021-10-26v06-lazy-mail.sql'); \ No newline at end of file diff --git a/radiant/tiny-mail/src/main/resources/wings-flywave/master/07-mail/2020-10-27v01-tiny_mail.sql b/radiant/tiny-mail/src/main/resources/wings-flywave/master/07-mail/2020-10-27v01-tiny_mail.sql index 66d25c9cb..7d6fe929e 100644 --- a/radiant/tiny-mail/src/main/resources/wings-flywave/master/07-mail/2020-10-27v01-tiny_mail.sql +++ b/radiant/tiny-mail/src/main/resources/wings-flywave/master/07-mail/2020-10-27v01-tiny_mail.sql @@ -18,6 +18,8 @@ CREATE TABLE `win_mail_sender` ( `mail_file` TEXT NULL COMMENT 'attachment name and path map, json format', `mail_mark` VARCHAR(900) NOT NULL DEFAULT '' COMMENT 'business key to lookup', `mail_date` DATETIME(3) NOT NULL DEFAULT '1000-01-01' COMMENT 'scheduled mail send (sys)', + `lazy_bean` VARCHAR(300) NOT NULL DEFAULT '' COMMENT 'lazy bean to edit mail if mail_text is null', + `lazy_para` TEXT NULL COMMENT 'lazy para of lazy bean', `last_send` DATETIME(3) NOT NULL DEFAULT '1000-01-01' COMMENT 'previous send (sys)', `last_fail` TEXT NULL COMMENT 'previous fail info', `last_done` DATETIME(3) NOT NULL DEFAULT '1000-01-01' COMMENT 'previous success (sys)', diff --git a/radiant/tiny-mail/src/test/java/pro/fessional/wings/tiny/app/conf/TestStatusHookConfiguration.java b/radiant/tiny-mail/src/test/java/pro/fessional/wings/tiny/app/conf/TestStatusHookConfiguration.java index f5c00ae84..fc618c783 100644 --- a/radiant/tiny-mail/src/test/java/pro/fessional/wings/tiny/app/conf/TestStatusHookConfiguration.java +++ b/radiant/tiny-mail/src/test/java/pro/fessional/wings/tiny/app/conf/TestStatusHookConfiguration.java @@ -1,10 +1,8 @@ package pro.fessional.wings.tiny.app.conf; import lombok.extern.slf4j.Slf4j; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import pro.fessional.wings.slardar.notice.DingTalkNotice; import pro.fessional.wings.tiny.app.service.TestMailSenderManager; import pro.fessional.wings.tiny.mail.sender.MailSenderManager; import pro.fessional.wings.tiny.mail.sender.MailSenderProvider; @@ -20,11 +18,8 @@ public class TestStatusHookConfiguration { @Bean - public TinyMailService.StatusHook gmailStatusHook(@Autowired(required = false) DingTalkNotice notice) { + public TinyMailService.StatusHook gmailStatusHook() { return (po, cost, exception) -> { - if (notice != null) { - notice.send("hook mail subj=" + po.getMailSubj() + ", cost=" + cost, po.getMailText()); - } log.info("hook mail subj=" + po.getMailSubj() + ", cost=" + cost, exception); return false; }; diff --git a/radiant/tiny-mail/src/test/java/pro/fessional/wings/tiny/app/service/TestMailSenderManager.java b/radiant/tiny-mail/src/test/java/pro/fessional/wings/tiny/app/service/TestMailSenderManager.java index 7d6610162..64287c95e 100644 --- a/radiant/tiny-mail/src/test/java/pro/fessional/wings/tiny/app/service/TestMailSenderManager.java +++ b/radiant/tiny-mail/src/test/java/pro/fessional/wings/tiny/app/service/TestMailSenderManager.java @@ -11,7 +11,9 @@ import pro.fessional.wings.tiny.mail.sender.TinyMailMessage; import pro.fessional.wings.tiny.mail.spring.prop.TinyMailSenderProp; +import java.util.Collection; import java.util.HashSet; +import java.util.List; /** * @author trydofor @@ -30,17 +32,34 @@ public TestMailSenderManager(TinyMailSenderProp senderProp, MailSenderProvider s public void singleSend(@NotNull TinyMailMessage message, long maxWait, @Nullable MimeMessagePrepareHelper preparer) { super.singleSend(message, maxWait, preparer); + String subj = message.getSubject(); + if (subj.contains("AlwaysRuntimeException")) { + throw new RuntimeException("Mock " + subj); + } + if (exception1st.add(message.getBizId())) { - String text = message.getSubject(); - if (text.contains("MailWaitException")) { - throw new MailWaitException(ThreadNow.millis() + 5_000, false, false, new IllegalStateException("Mock")); + if (subj.contains("MailWaitException")) { + throw new MailWaitException(ThreadNow.millis() + 5_000, false, false, new IllegalStateException("Mock " + subj)); } - if (text.contains("MailParseException")) { - throw new MailParseException("Mock"); + if (subj.contains("MailParseException")) { + throw new MailParseException("Mock " + subj); } - if (text.contains("RuntimeException")) { - throw new RuntimeException("Mock"); + if (subj.contains("RuntimeException")) { + throw new RuntimeException("Mock " + subj); + } + } + } + + @Override + public List batchSend(Collection messages, long maxWait, @Nullable MimeMessagePrepareHelper preparer) { + List results = super.batchSend(messages, maxWait, preparer); + + for (BatchResult result : results) { + String subj = result.getTinyMessage().getSubject(); + if (subj.contains("AlwaysRuntimeException")) { + result.setException(new RuntimeException("Mock " + subj)); } } + return results; } } diff --git a/radiant/tiny-mail/src/test/java/pro/fessional/wings/tiny/app/service/TestTinyMailLazy.java b/radiant/tiny-mail/src/test/java/pro/fessional/wings/tiny/app/service/TestTinyMailLazy.java new file mode 100644 index 000000000..0c933046f --- /dev/null +++ b/radiant/tiny-mail/src/test/java/pro/fessional/wings/tiny/app/service/TestTinyMailLazy.java @@ -0,0 +1,32 @@ +package pro.fessional.wings.tiny.app.service; + +import org.jetbrains.annotations.Nullable; +import org.springframework.stereotype.Service; +import pro.fessional.wings.tiny.mail.service.TinyMailLazy; + +import java.util.HashSet; + +/** + * @author trydofor + * @since 2024-07-12 + */ +@Service +public class TestTinyMailLazy implements TinyMailLazy { + + private final HashSet exception1st = new HashSet<>(); + + @Override + public @Nullable Edit lazyEdit(@Nullable String para) { + if(para == null) return null; + + if (exception1st.add(para)) { + if (para.contains("RuntimeException")) { + throw new RuntimeException("Mock "+ para); + } + } + + Edit edit = new Edit(); + edit.setContent(para); + return edit; + } +} diff --git a/radiant/tiny-mail/src/test/java/pro/fessional/wings/tiny/mail/service/TinyMailServiceDbTest.java b/radiant/tiny-mail/src/test/java/pro/fessional/wings/tiny/mail/service/TinyMailServiceDbTest.java index 8fb3ac442..573249e1e 100644 --- a/radiant/tiny-mail/src/test/java/pro/fessional/wings/tiny/mail/service/TinyMailServiceDbTest.java +++ b/radiant/tiny-mail/src/test/java/pro/fessional/wings/tiny/mail/service/TinyMailServiceDbTest.java @@ -52,6 +52,9 @@ class TinyMailServiceDbTest { @Setter(onMethod_ = { @Autowired }) protected WinMailSenderDao winMailSenderDao; + @Setter(onMethod_ = { @Autowired }) + protected TinyMailLazy tinyMailLazy; + @Test @TmsLink("C15006") void mockData() { @@ -93,14 +96,31 @@ void bootScan() { void sendError() { int time = 10; + String etk = "RuntimeException"; + String atk = "AlwaysRuntimeException"; Set ids = new HashSet<>(); String subj = TestingMailUtil.dryrun("TinyMailService", mailProperties); + for (int i = 0; i < time; i++) { - TinyMailPlain mail0 = new TinyMailPlain(); + TinyMailPlain ml = new TinyMailPlain(); boolean err = i % 3 == 0; - mail0.setSubject(subj + (err ? " RuntimeException " : " ") + i); - mail0.setContent(""); // mock - long id = tinyMailService.save(mail0); + String tkn = err ? " " + etk + " " : " "; + + if (i == 0) { + ml.setSubject(subj + " " + atk + " " + i); + } + else { + ml.setSubject(subj + tkn + i); + } + + if (i % 2 == 0) { + ml.setContent("mail text " + i); + } + else { + ml.setMailLazy(tinyMailLazy, "lazy" + tkn + i); + } + + long id = tinyMailService.save(ml); ids.add(id); try { @@ -111,24 +131,24 @@ void sendError() { Assertions.assertTrue(e.getMessage().contains("Mock")); } - WinMailSender po0 = winMailSenderDao.fetchOneById(id); + WinMailSender po = winMailSenderDao.fetchOneById(id); if (err) { - Assertions.assertTrue(po0.getNextSend().isAfter(ThreadNow.localDateTime())); - Assertions.assertTrue(StringUtils.isNotBlank(po0.getLastFail())); - Assertions.assertEquals(1, po0.getSumFail()); - Assertions.assertEquals(1, po0.getSumSend()); - Assertions.assertEquals(0, po0.getSumDone()); + Assertions.assertTrue(po.getNextSend().isAfter(ThreadNow.localDateTime())); + Assertions.assertTrue(StringUtils.isNotBlank(po.getLastFail())); + Assertions.assertEquals(1, po.getSumFail()); + Assertions.assertEquals(1, po.getSumSend()); + Assertions.assertEquals(0, po.getSumDone()); } else { - Assertions.assertTrue(EmptySugar.asEmptyValue(po0.getNextSend())); - Assertions.assertTrue(StringUtils.isBlank(po0.getLastFail())); - Assertions.assertEquals(0, po0.getSumFail()); - Assertions.assertEquals(1, po0.getSumSend()); - Assertions.assertEquals(1, po0.getSumDone()); + Assertions.assertTrue(EmptySugar.asEmptyValue(po.getNextSend())); + Assertions.assertTrue(StringUtils.isBlank(po.getLastFail())); + Assertions.assertEquals(0, po.getSumFail()); + Assertions.assertEquals(1, po.getSumSend()); + Assertions.assertEquals(1, po.getSumDone()); } } - long ms = tinyMailServiceProp.getTryNext().toMillis() * 2; + long ms = tinyMailServiceProp.getTryNext().toMillis() * 4; Sleep.ignoreInterrupt(ms); log.info("after try next, slept={}", ms); @@ -136,17 +156,28 @@ void sendError() { for (WinMailSender po : pos) { Assertions.assertTrue(EmptySugar.asEmptyValue(po.getNextSend())); Assertions.assertTrue(EmptySugar.nonEmptyValue(po.getLastSend())); - Assertions.assertTrue(StringUtils.isBlank(po.getLastFail())); - if (po.getMailSubj().contains("RuntimeException")) { - Assertions.assertEquals(1, po.getSumFail()); - Assertions.assertEquals(2, po.getSumSend()); - Assertions.assertEquals(1, po.getSumDone()); + int sumFail = 0; + + String sub = po.getMailSubj(); + if (sub.contains(etk) || sub.contains(atk)) { + sumFail++; + } + else if (po.getLazyPara() != null && po.getLazyPara().contains(etk)) { + sumFail++; } - else { - Assertions.assertEquals(0, po.getSumFail()); - Assertions.assertEquals(1, po.getSumSend()); + if (sub.contains(atk)) { + int maxFail = tinyMailServiceProp.getMaxFail(); + Assertions.assertEquals(maxFail, po.getSumSend()); + Assertions.assertEquals(maxFail, po.getSumFail()); + Assertions.assertEquals(0, po.getSumDone()); + Assertions.assertTrue(StringUtils.isNotBlank(po.getLastFail())); + } + else { + Assertions.assertEquals(sumFail + 1, po.getSumSend()); + Assertions.assertEquals(sumFail, po.getSumFail()); Assertions.assertEquals(1, po.getSumDone()); + Assertions.assertTrue(StringUtils.isBlank(po.getLastFail())); } } diff --git a/wings/faceless-flywave/src/main/java/pro/fessional/wings/faceless/flywave/WingsRevision.java b/wings/faceless-flywave/src/main/java/pro/fessional/wings/faceless/flywave/WingsRevision.java index e935b525a..12d3d558e 100644 --- a/wings/faceless-flywave/src/main/java/pro/fessional/wings/faceless/flywave/WingsRevision.java +++ b/wings/faceless-flywave/src/main/java/pro/fessional/wings/faceless/flywave/WingsRevision.java @@ -27,6 +27,7 @@ public enum WingsRevision implements RevisionRegister { V03_21_1026_02_FixTaskTune(2021_1026_02L, "fix task tune", "branch/somefix/03-task-tune", "radiant/tiny-task/src/main/resources/wings-flywave"), V04_21_1026_03_FixConfSize(2021_1026_03L, "fix conf size", "branch/somefix/04-conf-size", "wings/warlock/src/main/resources/wings-flywave"), V05_21_1026_05_FixJournal(2021_1026_05L, "fix journal elapse", "branch/somefix/05-journal-elapse", "wings/faceless/src/main/resources/wings-flywave"), + V06_21_1026_06_FixLazyMail(2021_1026_06L, "fix lazy mail", "branch/somefix/06-lazy-mail", "radiant/tiny-mail/src/main/resources/wings-flywave"), // testing V90_22_0601_01_TestSchema(2022_0601_01L, "test v1 schema", "master", "wings/testing-faceless/src/main/resources/wings-flywave/"), From 0fbd5fe224f063787dbf4ea355bd2f04314e2dca Mon Sep 17 00:00:00 2001 From: trydofor Date: Sun, 14 Jul 2024 17:46:59 +0800 Subject: [PATCH 21/51] =?UTF-8?q?=F0=9F=92=A5tinymail=20service=20refactor?= =?UTF-8?q?=20#272?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../tiny/mail/sender/MailRetryException.java | 22 +++ .../tiny/mail/sender/MailWaitException.java | 4 +- .../tiny/mail/service/TinyMailService.java | 104 +++++++---- .../service/impl/TinyMailServiceImpl.java | 164 +++++++++++------- .../mail/service/TinyMailServiceDbTest.java | 5 +- 5 files changed, 201 insertions(+), 98 deletions(-) create mode 100644 radiant/tiny-mail/src/main/java/pro/fessional/wings/tiny/mail/sender/MailRetryException.java diff --git a/radiant/tiny-mail/src/main/java/pro/fessional/wings/tiny/mail/sender/MailRetryException.java b/radiant/tiny-mail/src/main/java/pro/fessional/wings/tiny/mail/sender/MailRetryException.java new file mode 100644 index 000000000..2198258d2 --- /dev/null +++ b/radiant/tiny-mail/src/main/java/pro/fessional/wings/tiny/mail/sender/MailRetryException.java @@ -0,0 +1,22 @@ +package pro.fessional.wings.tiny.mail.sender; + +import lombok.Getter; +import org.springframework.mail.MailException; + +/** + * @author trydofor + * @since 2023-01-03 + */ +@Getter +public class MailRetryException extends MailException { + + /** + * Epoch mills to retry + */ + private final long nextEpoch; + + public MailRetryException(long next, Throwable cause) { + super("retry at epoch=" + next + " for exception", cause); + this.nextEpoch = next; + } +} diff --git a/radiant/tiny-mail/src/main/java/pro/fessional/wings/tiny/mail/sender/MailWaitException.java b/radiant/tiny-mail/src/main/java/pro/fessional/wings/tiny/mail/sender/MailWaitException.java index d90362d49..f9d6796a7 100644 --- a/radiant/tiny-mail/src/main/java/pro/fessional/wings/tiny/mail/sender/MailWaitException.java +++ b/radiant/tiny-mail/src/main/java/pro/fessional/wings/tiny/mail/sender/MailWaitException.java @@ -7,23 +7,21 @@ * @author trydofor * @since 2023-01-03 */ +@Getter public class MailWaitException extends MailException { /** * Epoch mills to wait */ - @Getter private final long waitEpoch; /** * Whether it is a host-level wait */ - @Getter private final boolean hostLevel; /** * Whether to stop sending than to wait */ - @Getter private final boolean stopRetry; public MailWaitException(long epoch, boolean host, boolean stop, Throwable cause) { diff --git a/radiant/tiny-mail/src/main/java/pro/fessional/wings/tiny/mail/service/TinyMailService.java b/radiant/tiny-mail/src/main/java/pro/fessional/wings/tiny/mail/service/TinyMailService.java index f60b51a1a..f29d08938 100644 --- a/radiant/tiny-mail/src/main/java/pro/fessional/wings/tiny/mail/service/TinyMailService.java +++ b/radiant/tiny-mail/src/main/java/pro/fessional/wings/tiny/mail/service/TinyMailService.java @@ -16,27 +16,43 @@ public interface TinyMailService { /** - * Sync send, return success or not, or throw exception. - * If not success, async retry + *
+     * Save and Sync single send. and return,
+     * - false, if check fail.
+     * - throw if send fail, MailRetryException if async retry.
+     * - true, otherwise.
+     * 
*/ boolean send(@NotNull TinyMail message, boolean retry); /** - * Sync send, fire and forget, no exception throw. - * If not success, async retry + *
+     * Save and Sync single send, fire and forget, no exception throw. and return,
+     * - -2, if throw non MailRetryException.
+     * - -1, if check fail.
+     * - 0, if send success.
+     * - > now(), (estimated retry time) if fail and async retry
+     * 
*/ - boolean post(@NotNull TinyMail message, boolean retry); + long post(@NotNull TinyMail message, boolean retry); /** - * Async, no exception throw. auto batch send. - * Return the estimated sending time, `-1` for failure - * If not success, async retry. + *
+     * Async batch send, no exception throw. auto in batch send. and return,
+     * - -2, if throw non MailRetryException.
+     * - -1 if check fail.
+     * - > now() estimated retry time if fail and async retry
+     * 
*/ long emit(@NotNull TinyMail message, boolean retry); /** - * Sync send, return success or not, or throw exception. - * If not success, async retry + *
+     * Save and Sync single send. and return,
+     * - false, if check fail.
+     * - throw if send fail, MailRetryException if async retry.
+     * - true, otherwise.
+     * 
*/ default boolean send(@NotNull TinyMailPlain message) { final long id = save(message); @@ -44,18 +60,24 @@ default boolean send(@NotNull TinyMailPlain message) { } /** - * Sync send, fire and forget, no exception throw. - * If not success, async retry + *
+     * Save and Sync single send, fire and forget, no exception throw. and return,
+     * - -1, if check fail.
+     * - 0, if send success.
+     * - > now(), (estimated retry time) if fail and async retry
+     * 
*/ - default boolean post(@NotNull TinyMailPlain message) { + default long post(@NotNull TinyMailPlain message) { final long id = save(message); return post(id, BoxedCastUtil.orFalse(message.getRetry()), BoxedCastUtil.orFalse(message.getCheck())); } /** - * Async, no exception throw. auto batch send. - * Return the estimated sending time, `-1` for failure - * If not success, async retry. + *
+     * Save and Async batch send, no exception throw. auto in batch send. and return,
+     * - -1 if check fail.
+     * - > now() estimated retry time if fail and async retry
+     * 
*/ default long emit(@NotNull TinyMailPlain message) { final long id = save(message); @@ -63,21 +85,31 @@ default long emit(@NotNull TinyMailPlain message) { } /** - * Sync send, fire and forget, no exception throw. - * If not success, async retry, whether to check state before sending + *
+     * Load and Sync single send. and return,
+     * - false, if check fail.
+     * - throw if send fail, MailRetryException if async retry.
+     * - true, otherwise.
+     * 
*/ boolean send(long id, boolean retry, boolean check); /** - * Sync send, fire and forget, no exception throw. - * If not success, async retry, whether to check state before sending + *
+     * Load and Sync single send, fire and forget, no exception throw. and return,
+     * - -1, if check fail.
+     * - 0, if send success.
+     * - > now(), (estimated retry time) if fail and async retry
+     * 
*/ - boolean post(long id, boolean retry, boolean check); + long post(long id, boolean retry, boolean check); /** - * Async, no exception throw. auto batch send. - * Return the estimated sending time, `-1` for failure - * If not success, async retry, whether to check state before sending + *
+     * Load and Async batch send, no exception throw. auto in batch send. and return,
+     * - -1 if check fail.
+     * - > now() estimated retry time if fail and async retry
+     * 
*/ long emit(long id, boolean retry, boolean check); @@ -106,15 +138,17 @@ default int scan() { } /** - * Create the mail, and auto send it in sync or async way. - * `-1` means failure, `0` means sync send, - * otherwise means async send at estimated sending time + *
+     * Save and auto post/emit by its mail-date. and retrun,
+     * - -1, if check fail.
+     * - 0, if send success.
+     * - > now(), (estimated retry time) if fail and async retry
+     * 
*/ default long auto(@NotNull TinyMail message, boolean retry) { final LocalDateTime md = message.getDate(); if (md == null || md.isBefore(ThreadNow.localDateTime())) { - final boolean ok = send(message, retry); - return ok ? 0 : -1; + return post(message, retry); } else { return emit(message, retry); @@ -122,16 +156,18 @@ default long auto(@NotNull TinyMail message, boolean retry) { } /** - * Create the mail, and auto send it in sync or async way. - * `-1` means failure, `0` means sync send, - * otherwise means async send at estimated sending time + *
+     * Save and auto post/emit by its mail-date. and retrun,
+     * - -1, if check fail.
+     * - 0, if send success.
+     * - > now(), (estimated retry time) if fail and async retry
+     * 
*/ default long auto(@NotNull TinyMailPlain message) { final long id = save(message); final LocalDateTime md = message.getDate(); if (md == null || md.isBefore(ThreadNow.localDateTime())) { - final boolean ok = send(id, BoxedCastUtil.orFalse(message.getRetry()), BoxedCastUtil.orFalse(message.getCheck())); - return ok ? 0 : -1; + return post(id, BoxedCastUtil.orFalse(message.getRetry()), BoxedCastUtil.orFalse(message.getCheck())); } else { return emit(id, BoxedCastUtil.orFalse(message.getRetry()), BoxedCastUtil.orFalse(message.getCheck())); diff --git a/radiant/tiny-mail/src/main/java/pro/fessional/wings/tiny/mail/service/impl/TinyMailServiceImpl.java b/radiant/tiny-mail/src/main/java/pro/fessional/wings/tiny/mail/service/impl/TinyMailServiceImpl.java index 46a9fd81b..376080931 100644 --- a/radiant/tiny-mail/src/main/java/pro/fessional/wings/tiny/mail/service/impl/TinyMailServiceImpl.java +++ b/radiant/tiny-mail/src/main/java/pro/fessional/wings/tiny/mail/service/impl/TinyMailServiceImpl.java @@ -40,6 +40,7 @@ import pro.fessional.wings.tiny.mail.database.autogen.tables.daos.WinMailSenderDao; import pro.fessional.wings.tiny.mail.database.autogen.tables.pojos.WinMailSender; import pro.fessional.wings.tiny.mail.sender.MailConfigProvider; +import pro.fessional.wings.tiny.mail.sender.MailRetryException; import pro.fessional.wings.tiny.mail.sender.MailSenderManager; import pro.fessional.wings.tiny.mail.sender.MailSenderManager.BatchResult; import pro.fessional.wings.tiny.mail.sender.MailWaitException; @@ -112,74 +113,105 @@ public class TinyMailServiceImpl implements TinyMailService, InitializingBean { @Override public boolean send(@NotNull TinyMail message, boolean retry) { - final String conf = message.getConf(); - final TinyMailConfig config = mailConfigProvider.bynamedConfig(conf); - AssertArgs.notNull(config, "tiny-mail conf={} not found", conf); - - final WinMailSender po = saveMailSender(config, message); - final TinyMailMessage mailMessage = makeMailMessage(config, po, message); - return doSyncSend(po, mailMessage, retry, true); + return doSend(true, message, retry) == 0; } @Override - public boolean post(@NotNull TinyMail message, boolean retry) { + public long post(@NotNull TinyMail message, boolean retry) { try { - return send(message, retry); + return doSend(true, message, retry); + } + catch (MailRetryException e) { + log.warn("fail to post tiny-mail, next-retry=" + e.getNextEpoch() + ", subject=" + message.getSubject(), e.getCause()); + return e.getNextEpoch(); } catch (Exception e) { - log.error("fail to post tiny-mail, subject=" + message.getSubject(), e); - return false; + log.error("fail to post tiny-mail, retry=" + retry + ", subject=" + message.getSubject(), e); + return -2; } } @Override public long emit(@NotNull TinyMail message, boolean retry) { - final String conf = message.getConf(); - final TinyMailConfig config = mailConfigProvider.bynamedConfig(conf); - AssertArgs.notNull(config, "tiny-mail conf={} not found", conf); - - final WinMailSender po = saveMailSender(config, message); - final TinyMailMessage mailMessage = makeMailMessage(config, po, message); - return doAsyncSend(po, mailMessage, retry, true); + try { + return doSend(false, message, retry); + } + catch (MailRetryException e) { + log.warn("fail to emit tiny-mail, next-retry=" + e.getNextEpoch() + ", subject=" + message.getSubject(), e.getCause()); + return e.getNextEpoch(); + } + catch (Exception e) { + log.error("fail to emit tiny-mail, retry=" + retry + ", subject=" + message.getSubject(), e); + return -2; + } } @Override public boolean send(long id, boolean retry, boolean check) { - final WinMailSender po = winMailSenderDao.fetchOneById(id); - if (po == null) { - log.warn("tiny-mail not found by id={}, skip send", id); - return false; - } - final String conf = po.getMailConf(); - final TinyMailConfig config = mailConfigProvider.bynamedConfig(conf); - if (config == null) { - log.warn("tiny-mail conf={} not found", conf); - return false; - } - - final TinyMailMessage mailMessage = makeMailMessage(config, po, null); - return doSyncSend(po, mailMessage, retry, check); + return doSend(true, id, retry, check) == 0; } @Override - public boolean post(long id, boolean retry, boolean check) { + public long post(long id, boolean retry, boolean check) { try { - return send(id, retry, check); + return doSend(true, id, retry, check); + } + catch (MailRetryException e) { + log.warn("fail to post tiny-mail, next-retry=" + e.getNextEpoch() + ", id=" + id, e.getCause()); + return e.getNextEpoch(); } catch (Exception e) { - log.error("fail to post tiny-mail, id=" + id, e); - return false; + log.error("fail to post tiny-mail, retry=" + retry + ", id=" + id, e); + return -2; } } @Override public long emit(long id, boolean retry, boolean check) { + try { + return doSend(false, id, retry, check); + } + catch (MailRetryException e) { + log.warn("fail to emit tiny-mail, next-retry=" + e.getNextEpoch() + ", id=" + id, e.getCause()); + return e.getNextEpoch(); + } + catch (Exception e) { + log.error("fail to emit tiny-mail, retry=" + retry + ", id=" + id, e); + return -2; + } + } + + protected long doSend(boolean sync, @NotNull TinyMail message, boolean retry) { + final String conf = message.getConf(); + final TinyMailConfig config = mailConfigProvider.bynamedConfig(conf); + AssertArgs.notNull(config, "tiny-mail conf={} not found", conf); + + final WinMailSender po = saveMailSender(config, message); + + final TinyMailMessage mailMessage = makeMailMessage(config, po, message); + if (sync) { + return doSyncSend(po, mailMessage, retry, true); + } + else { + return doAsyncSend(po, mailMessage, retry, true); + } + } + + protected long doSend(boolean sync, long id, boolean retry, boolean check) { final WinMailSender po = winMailSenderDao.fetchOneById(id); - if (po == null) { - log.warn("tiny-mail not found by id={}, skip emit", id); - return -1; + AssertArgs.notNull(po, "tiny-mail not found by id={}, skip send", id); + + final String conf = po.getMailConf(); + final TinyMailConfig config = mailConfigProvider.bynamedConfig(conf); + AssertArgs.notNull(config, "tiny-mail conf={} not found", conf); + + final TinyMailMessage mailMessage = makeMailMessage(config, po, null); + if (sync) { + return doSyncSend(po, mailMessage, retry, check); + } + else { + return doAsyncSend(po, mailMessage, retry, check); } - return doAsyncSend(po, null, retry, check); } @Override @@ -497,6 +529,14 @@ protected boolean notMatchProp(@NotNull WinMailSender po) { return true; } + if (po.getMailText() == null) { + var bean = lazyBeanHolder.get(po.getLazyBean()); + if (bean == null) { + log.error("stop lazy tiny-mail, not found bean={}, id={}", bean, po.getId()); + return true; + } + } + return false; } @@ -521,6 +561,9 @@ protected boolean notNextLock(@NotNull WinMailSender po, long now) { return false; } + /** + * next if done lt max or exception and retry + */ protected long saveSendResult(@NotNull WinMailSender po, @NotNull TinyMailMessage message, long cost, long exit, Exception exception, boolean retry) { long nextSend = -1; try { @@ -635,30 +678,30 @@ protected boolean editLazyMail(@NotNull WinMailSender po, @NotNull TinyMailMessa final Map setter = new HashMap<>(); Boolean html = edit.getHtml(); - if(html != null){ + if (html != null) { setter.put(t.MailHtml, html); message.setHtml(html); } String subj = edit.getSubject(); - if(subj != null){ + if (subj != null) { setter.put(t.MailSubj, subj); message.setSubject(subj); } String text = edit.getContent(); - if(text != null){ + if (text != null) { setter.put(t.MailText, text); message.setContent(text); } Map file = edit.getAttachment(); - if(file != null && !file.isEmpty()){ + if (file != null && !file.isEmpty()) { setter.put(t.MailFile, stringResource(file)); message.setAttachment(file); } - if(setter.isEmpty()) return false; + if (setter.isEmpty()) return false; Long id = po.getId(); log.info("lazy edit tiny-mail, id={}", id); @@ -676,15 +719,15 @@ protected boolean editLazyMail(@NotNull WinMailSender po, @NotNull TinyMailMessa return true; } - private boolean doSyncSend(@NotNull WinMailSender po, @NotNull TinyMailMessage message, boolean retry, boolean check) { + private long doSyncSend(@NotNull WinMailSender po, @NotNull TinyMailMessage message, boolean retry, boolean check) { final long start; if (check) { // condition not match - if (notMatchProp(po)) return false; + if (notMatchProp(po)) return -1; start = ThreadNow.millis(); // others do it - if (notNextLock(po, start)) return false; + if (notNextLock(po, start)) return -1; } else { start = ThreadNow.millis(); @@ -704,19 +747,21 @@ private boolean doSyncSend(@NotNull WinMailSender po, @NotNull TinyMailMessage m if (nxt > 0) { planAsyncMail(new AsyncMail(po.getId(), nxt, retry, check, null, message)); log.debug("plan tiny-mail next-send, err={}, id={}, subject={}", exception == null, po.getId(), po.getMailSubj()); + if (exception != null) { + exception = new MailRetryException(nxt, exception); // runtime + } } } - if (exception != null) { - if (exception instanceof RuntimeException) { - throw (RuntimeException) exception; - } - else { - throw new MailSendException("failed tiny-mail, id=" + po.getId() + ", subject=" + po.getMailSubj(), exception); - } - } + if (exception == null) return 0; - return true; + // rethrow exception + if (exception instanceof RuntimeException) { + throw (RuntimeException) exception; + } + else { + throw new MailSendException("failed tiny-mail, id=" + po.getId() + ", subject=" + po.getMailSubj(), exception); + } } private long doAsyncSend(@NotNull WinMailSender po, @NotNull TinyMailMessage message, boolean retry, boolean check) { @@ -744,7 +789,7 @@ private long doAsyncSend(@NotNull WinMailSender po, @NotNull TinyMailMessage mes mailSenderManager.checkMessage(message); } catch (Exception e) { - log.error("tiny-mail format error", e); + log.error("tiny-mail check error, id=" + id, e); long nx = saveSendResult(po, message, 0, now, e, !lzk && retry); // retry if lazy fail if (nx > 0) { next = nx; @@ -935,7 +980,8 @@ private void sendAsyncMail() { } private final AtomicInteger trimSchedConter = new AtomicInteger(0); - @Setter @Getter + @Setter + @Getter private int maxAsyncSched = 1; private void trimAsyncMailSched() { diff --git a/radiant/tiny-mail/src/test/java/pro/fessional/wings/tiny/mail/service/TinyMailServiceDbTest.java b/radiant/tiny-mail/src/test/java/pro/fessional/wings/tiny/mail/service/TinyMailServiceDbTest.java index 573249e1e..a71d32a8c 100644 --- a/radiant/tiny-mail/src/test/java/pro/fessional/wings/tiny/mail/service/TinyMailServiceDbTest.java +++ b/radiant/tiny-mail/src/test/java/pro/fessional/wings/tiny/mail/service/TinyMailServiceDbTest.java @@ -15,6 +15,7 @@ import pro.fessional.wings.tiny.mail.TestingMailUtil; import pro.fessional.wings.tiny.mail.database.autogen.tables.daos.WinMailSenderDao; import pro.fessional.wings.tiny.mail.database.autogen.tables.pojos.WinMailSender; +import pro.fessional.wings.tiny.mail.sender.MailRetryException; import pro.fessional.wings.tiny.mail.service.impl.TinyMailServiceImpl; import pro.fessional.wings.tiny.mail.spring.prop.TinyMailServiceProp; @@ -127,8 +128,8 @@ void sendError() { tinyMailService.send(id, true, true); if (err) Assertions.fail(); } - catch (Exception e) { - Assertions.assertTrue(e.getMessage().contains("Mock")); + catch (MailRetryException e) { + Assertions.assertTrue(e.getCause().getMessage().contains("Mock")); } WinMailSender po = winMailSenderDao.fetchOneById(id); From df6ed7e54a9edb4ad6bdf6bbbd25babd8c6df3c7 Mon Sep 17 00:00:00 2001 From: trydofor Date: Mon, 15 Jul 2024 14:59:37 +0800 Subject: [PATCH 22/51] =?UTF-8?q?=E2=9C=85=20tinymail=20unittest=20#272?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- WingsBoot.t.md | 2 + .../tiny/mail/service/TinyMailService.java | 108 ++++++++----- .../service/impl/TinyMailServiceImpl.java | 122 ++++++++------- .../app/service/TestMailSenderManager.java | 24 +-- .../tiny/app/service/TestTinyMailLazy.java | 11 +- .../mail/service/TinyMailServiceDbTest.java | 142 +++++++++++++----- 6 files changed, 263 insertions(+), 146 deletions(-) diff --git a/WingsBoot.t.md b/WingsBoot.t.md index 48f4511b0..d432f47d2 100644 --- a/WingsBoot.t.md +++ b/WingsBoot.t.md @@ -433,3 +433,5 @@ Use `t.md` as local [Test Management](https://www.jetbrains.com/help/idea/test-m * 15014 TinyTaskExecServiceTest: sleep 70s and check task * 15015 MailNoticeTest: title dryrun mailNotice * 15016 MailSenderManagerTest: title dryrun batch mail +* 15017 TinyMailServiceDbTest: mock fail and check database + diff --git a/radiant/tiny-mail/src/main/java/pro/fessional/wings/tiny/mail/service/TinyMailService.java b/radiant/tiny-mail/src/main/java/pro/fessional/wings/tiny/mail/service/TinyMailService.java index f29d08938..203503cd1 100644 --- a/radiant/tiny-mail/src/main/java/pro/fessional/wings/tiny/mail/service/TinyMailService.java +++ b/radiant/tiny-mail/src/main/java/pro/fessional/wings/tiny/mail/service/TinyMailService.java @@ -15,44 +15,65 @@ */ public interface TinyMailService { + /** + * send success + */ + int Success = 0; + + /** + * failed to check before send. e.g. prop, lock or format + */ + int ErrCheck = -1; + + /** + * other than MailRetryException after check + */ + int ErrOther = -2; + /** *
-     * Save and Sync single send. and return,
-     * - false, if check fail.
+     * Save first, then Sync single send. and return,
+     * - true, if send success.
+     * - false, if check fail, e.g. prop, lock or format.
      * - throw if send fail, MailRetryException if async retry.
-     * - true, otherwise.
      * 
+ * + * @throws MailRetryException if retry + * @throws Exception if unhandled */ boolean send(@NotNull TinyMail message, boolean retry); /** *
-     * Save and Sync single send, fire and forget, no exception throw. and return,
-     * - -2, if throw non MailRetryException.
-     * - -1, if check fail.
-     * - 0, if send success.
-     * - > now(), (estimated retry time) if fail and async retry
+     * Save first, then Sync single send, fire and forget, no exception throw. and return,
+     * - {@value #ErrOther}, if throw non MailRetryException.
+     * - {@value #ErrCheck}, if check fail, e.g. prop, lock or format.
+     * - {@value #Success}, if send success.
+     * - mills > now(), estimated retry time, if fail and async retry
      * 
*/ long post(@NotNull TinyMail message, boolean retry); /** *
-     * Async batch send, no exception throw. auto in batch send. and return,
-     * - -2, if throw non MailRetryException.
-     * - -1 if check fail.
-     * - > now() estimated retry time if fail and async retry
+     * Save first, then Async batch send, fire and forget, no exception throw. and return,
+     * - {@value #ErrOther}, if throw non MailRetryException.
+     * - {@value #ErrCheck}, if check fail, e.g. prop, lock or format.
+     * - mills > now(), estimated send or retry (when error) time
      * 
*/ long emit(@NotNull TinyMail message, boolean retry); /** *
-     * Save and Sync single send. and return,
-     * - false, if check fail.
+     * Save first, then Sync single send. and return,
+     * - true, if send success.
+     * - false, if check fail, e.g. prop, lock or format.
      * - throw if send fail, MailRetryException if async retry.
-     * - true, otherwise.
      * 
+ * + * @throws MailRetryException if retry + * @throws Exception if unhandled */ default boolean send(@NotNull TinyMailPlain message) { final long id = save(message); @@ -61,10 +82,11 @@ default boolean send(@NotNull TinyMailPlain message) { /** *
-     * Save and Sync single send, fire and forget, no exception throw. and return,
-     * - -1, if check fail.
-     * - 0, if send success.
-     * - > now(), (estimated retry time) if fail and async retry
+     * Save first, then Sync single send, fire and forget, no exception throw. and return,
+     * - {@value #ErrOther}, if throw non MailRetryException.
+     * - {@value #ErrCheck}, if check fail, e.g. prop, lock or format.
+     * - {@value #Success}, if send success.
+     * - mills > now(), estimated retry time, if fail and async retry
      * 
*/ default long post(@NotNull TinyMailPlain message) { @@ -74,9 +96,10 @@ default long post(@NotNull TinyMailPlain message) { /** *
-     * Save and Async batch send, no exception throw. auto in batch send. and return,
-     * - -1 if check fail.
-     * - > now() estimated retry time if fail and async retry
+     * Save first, then Async batch send, fire and forget, no exception throw. and return,
+     * - {@value #ErrOther}, if throw non MailRetryException.
+     * - {@value #ErrCheck}, if check fail, e.g. prop, lock or format.
+     * - mills > now(), estimated send or retry (when error) time
      * 
*/ default long emit(@NotNull TinyMailPlain message) { @@ -86,29 +109,34 @@ default long emit(@NotNull TinyMailPlain message) { /** *
-     * Load and Sync single send. and return,
-     * - false, if check fail.
+     * Save first, then Sync single send. and return,
+     * - true, if send success.
+     * - false, if check fail, e.g. prop, lock or format.
      * - throw if send fail, MailRetryException if async retry.
-     * - true, otherwise.
      * 
+ * + * @throws MailRetryException if retry + * @throws Exception if unhandled */ boolean send(long id, boolean retry, boolean check); /** *
-     * Load and Sync single send, fire and forget, no exception throw. and return,
-     * - -1, if check fail.
-     * - 0, if send success.
-     * - > now(), (estimated retry time) if fail and async retry
+     * Save first, then Sync single send, fire and forget, no exception throw. and return,
+     * - {@value #ErrOther}, if throw non MailRetryException.
+     * - {@value #ErrCheck}, if check fail, e.g. prop, lock or format.
+     * - {@value #Success}, if send success.
+     * - mills > now(), estimated retry time, if fail and async retry
      * 
*/ long post(long id, boolean retry, boolean check); /** *
-     * Load and Async batch send, no exception throw. auto in batch send. and return,
-     * - -1 if check fail.
-     * - > now() estimated retry time if fail and async retry
+     * Save first, then Async batch send, fire and forget, no exception throw. and return,
+     * - {@value #ErrOther}, if throw non MailRetryException.
+     * - {@value #ErrCheck}, if check fail, e.g. prop, lock or format.
+     * - mills > now(), estimated send or retry (when error) time
      * 
*/ long emit(long id, boolean retry, boolean check); @@ -139,10 +167,10 @@ default int scan() { /** *
-     * Save and auto post/emit by its mail-date. and retrun,
-     * - -1, if check fail.
-     * - 0, if send success.
-     * - > now(), (estimated retry time) if fail and async retry
+     * Save first, then auto post/emit by its mail-date. and retrun,
+     * - {@value #ErrCheck}, if check fail, e.g. prop, lock or format.
+     * - {@value #Success}, if send success.
+     * - mills > now(), estimated retry time, if fail and async retry
      * 
*/ default long auto(@NotNull TinyMail message, boolean retry) { @@ -157,10 +185,10 @@ default long auto(@NotNull TinyMail message, boolean retry) { /** *
-     * Save and auto post/emit by its mail-date. and retrun,
-     * - -1, if check fail.
-     * - 0, if send success.
-     * - > now(), (estimated retry time) if fail and async retry
+     * Save first, then auto post/emit by its mail-date. and retrun,
+     * - {@value #ErrCheck}, if check fail, e.g. prop, lock or format.
+     * - {@value #Success}, if send success.
+     * - mills > now(), estimated retry time, if fail and async retry
      * 
*/ default long auto(@NotNull TinyMailPlain message) { diff --git a/radiant/tiny-mail/src/main/java/pro/fessional/wings/tiny/mail/service/impl/TinyMailServiceImpl.java b/radiant/tiny-mail/src/main/java/pro/fessional/wings/tiny/mail/service/impl/TinyMailServiceImpl.java index 376080931..222987985 100644 --- a/radiant/tiny-mail/src/main/java/pro/fessional/wings/tiny/mail/service/impl/TinyMailServiceImpl.java +++ b/radiant/tiny-mail/src/main/java/pro/fessional/wings/tiny/mail/service/impl/TinyMailServiceImpl.java @@ -21,6 +21,7 @@ import org.springframework.stereotype.Service; import pro.fessional.mirana.best.AssertArgs; import pro.fessional.mirana.best.AssertState; +import pro.fessional.mirana.best.Param; import pro.fessional.mirana.cast.BoxedCastUtil; import pro.fessional.mirana.cond.IfSetter; import pro.fessional.mirana.pain.ThrowableUtil; @@ -113,7 +114,7 @@ public class TinyMailServiceImpl implements TinyMailService, InitializingBean { @Override public boolean send(@NotNull TinyMail message, boolean retry) { - return doSend(true, message, retry) == 0; + return doSend(true, message, retry) == Success; } @Override @@ -127,7 +128,7 @@ public long post(@NotNull TinyMail message, boolean retry) { } catch (Exception e) { log.error("fail to post tiny-mail, retry=" + retry + ", subject=" + message.getSubject(), e); - return -2; + return ErrOther; } } @@ -142,13 +143,13 @@ public long emit(@NotNull TinyMail message, boolean retry) { } catch (Exception e) { log.error("fail to emit tiny-mail, retry=" + retry + ", subject=" + message.getSubject(), e); - return -2; + return ErrOther; } } @Override public boolean send(long id, boolean retry, boolean check) { - return doSend(true, id, retry, check) == 0; + return doSend(true, id, retry, check) == Success; } @Override @@ -162,7 +163,7 @@ public long post(long id, boolean retry, boolean check) { } catch (Exception e) { log.error("fail to post tiny-mail, retry=" + retry + ", id=" + id, e); - return -2; + return ErrOther; } } @@ -177,14 +178,14 @@ public long emit(long id, boolean retry, boolean check) { } catch (Exception e) { log.error("fail to emit tiny-mail, retry=" + retry + ", id=" + id, e); - return -2; + return ErrOther; } } protected long doSend(boolean sync, @NotNull TinyMail message, boolean retry) { final String conf = message.getConf(); final TinyMailConfig config = mailConfigProvider.bynamedConfig(conf); - AssertArgs.notNull(config, "tiny-mail conf={} not found", conf); + AssertArgs.notNull(config, "skip tiny-mail conf={} not found", conf); final WinMailSender po = saveMailSender(config, message); @@ -199,11 +200,11 @@ protected long doSend(boolean sync, @NotNull TinyMail message, boolean retry) { protected long doSend(boolean sync, long id, boolean retry, boolean check) { final WinMailSender po = winMailSenderDao.fetchOneById(id); - AssertArgs.notNull(po, "tiny-mail not found by id={}, skip send", id); + AssertArgs.notNull(po, "skip tiny-mail not found by id={}", id); final String conf = po.getMailConf(); final TinyMailConfig config = mailConfigProvider.bynamedConfig(conf); - AssertArgs.notNull(config, "tiny-mail conf={} not found", conf); + AssertArgs.notNull(config, "skip tiny-mail conf={} not found, id={}", conf, id); final TinyMailMessage mailMessage = makeMailMessage(config, po, null); if (sync) { @@ -219,7 +220,7 @@ protected long doSend(boolean sync, long id, boolean retry, boolean check) { public long save(@NotNull TinyMailPlain msg) { final String conf = msg.getConf(); final TinyMailConfig config = mailConfigProvider.bynamedConfig(conf); - AssertArgs.notNull(config, "tiny-mail conf={} not found", conf); + AssertArgs.notNull(config, "skip tiny-mail conf={} not found", conf); final WinMailSender po = new WinMailSender(); final boolean isNew = msg.getId() == null || msg.getId() <= 0; @@ -329,17 +330,17 @@ protected int scanIdle() { if (idle < 0) { // reset to prop idle = tinyMailServiceProp.getScanIdle().toMillis(); idleScanMills.set(idle); - log.info("schedule reset tiny-mail scan, idle={} ms", idle); + log.info("reset tiny-mail scan idle to prop={} ms", idle); } if (idle > 0) { var task = taskScheduler.schedule(this::scanIdle, Instant.ofEpochMilli(ThreadNow.millis() + idle)); idleScanTask.set(task); - log.info("schedule next tiny-mail scan, idle={} ms", idle); + log.info("plan tiny-mail scan, idle={} ms", idle); } else { idleScanTask.set(null); - log.info("schedule stop tiny-mail scan, idle={} ms", idle); + log.info("stop tiny-mail scan, idle={} ms", idle); } return size; @@ -349,7 +350,7 @@ protected int scanSync() { final long now = ThreadNow.millis(); final LocalDateTime min = DateLocaling.sysLdt(now - tinyMailServiceProp.getMaxNext().toMillis()); final LocalDateTime max = DateLocaling.sysLdt(now + tinyMailServiceProp.getTryNext().toMillis()); - log.info("scan tiny-mail to queue, min={}, max={}", min, max); + log.info("scan tiny-mail to queue, next-send min={}, max={}", min, max); final WinMailSenderTable t = winMailSenderDao.getTable(); final List mails = winMailSenderDao @@ -383,7 +384,7 @@ public void afterPropertiesSet() { taskScheduler = TaskSchedulerHelper.Ttl(builder); taskScheduler.initialize(); - log.info("tiny-mail mailScheduler, prefix=" + taskScheduler.getThreadNamePrefix()); + log.info("tiny-mail taskScheduler, prefix=" + taskScheduler.getThreadNamePrefix()); if (namedLazyBean != null && !namedLazyBean.isEmpty()) { lazyBeanHolder = new ConcurrentHashMap<>(); @@ -394,7 +395,7 @@ public void afterPropertiesSet() { throw new IllegalStateException("lazy bean name existed, name=" + old.lazyBean() + ", new-bean=" + en.getKey()); } } - log.info("tiny-mail TinyMailLazy, size=" + lazyBeanHolder.size()); + log.info("tiny-mail TinyMailLazy beans, size=" + lazyBeanHolder.size()); } final long idle = tinyMailServiceProp.getBootScan().toMillis(); @@ -664,12 +665,14 @@ else if (exception instanceof MailParseException || exception instanceof Messagi return nextSend; } - protected boolean editLazyMail(@NotNull WinMailSender po, @NotNull TinyMailMessage message) { + protected boolean editLazyMail(@NotNull WinMailSender po, @NotNull @Param.Out TinyMailMessage message) { // nonnull means no need to edit if (message.getContent() != null) return false; - var bean = lazyBeanHolder.get(po.getLazyBean()); - AssertState.notNull(bean, "TinyMailLazy not found, bean={}", po.getLazyBean()); + final Long id = po.getId(); + final String bn = po.getLazyBean(); + var bean = lazyBeanHolder.get(bn); + AssertState.notNull(bean, "skip tiny-mail lazy-edit bean not found, bean={}, mail-id={}", bn, id); var edit = bean.lazyEdit(po.getLazyPara()); if (edit == null) return false; @@ -703,8 +706,7 @@ protected boolean editLazyMail(@NotNull WinMailSender po, @NotNull TinyMailMessa if (setter.isEmpty()) return false; - Long id = po.getId(); - log.info("lazy edit tiny-mail, id={}", id); + log.debug("lazy-edit tiny-mail, id={}", id); journalService.commit(Jane.Lazify, journal -> { setter.put(t.CommitId, journal.getCommitId()); @@ -723,19 +725,28 @@ private long doSyncSend(@NotNull WinMailSender po, @NotNull TinyMailMessage mess final long start; if (check) { // condition not match - if (notMatchProp(po)) return -1; + if (notMatchProp(po)) return ErrCheck; start = ThreadNow.millis(); // others do it - if (notNextLock(po, start)) return -1; + if (notNextLock(po, start)) return ErrCheck; } else { start = ThreadNow.millis(); } - Exception exception = null; + final Long id = po.getId(); try { editLazyMail(po, message); + } + catch (Exception e) { + log.error("stop tiny-mail for lazy-edit error, id=" + id, e); + saveSendResult(po, message, 0, start, e, false); // no retry is lazy fail + return ErrCheck; + } + + Exception exception = null; + try { mailSenderManager.singleSend(message); } catch (Exception e) { @@ -745,57 +756,65 @@ private long doSyncSend(@NotNull WinMailSender po, @NotNull TinyMailMessage mess final long end = ThreadNow.millis(); long nxt = saveSendResult(po, message, end - start, end, exception, retry); if (nxt > 0) { - planAsyncMail(new AsyncMail(po.getId(), nxt, retry, check, null, message)); - log.debug("plan tiny-mail next-send, err={}, id={}, subject={}", exception == null, po.getId(), po.getMailSubj()); + planAsyncMail(new AsyncMail(id, nxt, retry, check, null, message)); + log.debug("plan tiny-mail next-send, err={}, id={}, subject={}", exception == null, id, po.getMailSubj()); if (exception != null) { exception = new MailRetryException(nxt, exception); // runtime } } } - if (exception == null) return 0; + if (exception == null) return Success; // rethrow exception if (exception instanceof RuntimeException) { throw (RuntimeException) exception; } else { - throw new MailSendException("failed tiny-mail, id=" + po.getId() + ", subject=" + po.getMailSubj(), exception); + throw new MailSendException("failed tiny-mail, id=" + id + ", subject=" + po.getMailSubj(), exception); } } private long doAsyncSend(@NotNull WinMailSender po, @NotNull TinyMailMessage message, boolean retry, boolean check) { // condition not match - if (check && notMatchProp(po)) return -1; + if (check && notMatchProp(po)) return ErrCheck; + + final long start = ThreadNow.millis(); + final Long id = po.getId(); + try { + editLazyMail(po, message); + } + catch (Exception e) { + log.error("stop tiny-mail for lazy-edit error, id=" + id, e); + saveSendResult(po, message, 0, start, e, false); // no retry is lazy fail + return ErrCheck; + } final LocalDateTime ns = po.getNextSend(); final long nsm = ns == null ? 0 : DateLocaling.sysEpoch(ns); - final long now = ThreadNow.millis(); - final Long id = po.getId(); + long next; - if (nsm > now) { + if (nsm > start) { next = nsm; log.debug("plan async tiny-mail date={} id={}", ns, id); } else { - next = now; + next = start; log.debug("plan async tiny-mail date=now id={}", id); } - boolean lzk = false; try { - lzk = editLazyMail(po, message); // lazy ok mailSenderManager.checkMessage(message); } catch (Exception e) { log.error("tiny-mail check error, id=" + id, e); - long nx = saveSendResult(po, message, 0, now, e, !lzk && retry); // retry if lazy fail + long nx = saveSendResult(po, message, 0, start, e, retry); if (nx > 0) { next = nx; } else { - return -1; + return ErrCheck; } } @@ -804,7 +823,7 @@ private long doAsyncSend(@NotNull WinMailSender po, @NotNull TinyMailMessage mes } private void planAsyncMail(@NotNull AsyncMail mail) { - log.info("plan async tiny-mail, id={}", mail.id); + log.debug("plan async tiny-mail, id={}", mail.id); synchronized (asyncMailQueue) { asyncMailQueue.removeIf(it -> it.id == mail.id); asyncMailQueue.add(mail); @@ -827,7 +846,7 @@ else if (m.next < next) { } } - log.info("plan async tiny-mail, size={}", ids.size()); + log.debug("plan async tiny-mail, size={}", ids.size()); synchronized (asyncMailQueue) { asyncMailQueue.removeIf(it -> ids.contains(it.id)); asyncMailQueue.addAll(mails); @@ -905,14 +924,15 @@ private void sendAsyncMail() { } for (WinMailSender po : freshPo.values()) { - final AsyncMail am = mails.get(po.getId()); + final Long id = po.getId(); + final AsyncMail am = mails.get(id); if (am == null) continue; // never null if (am.check && (notMatchProp(po) || notNextLock(po, start))) { continue; } - TinyMailMessage msg = null; + final TinyMailMessage msg; if (am.message != null) { msg = am.message; } @@ -920,26 +940,22 @@ private void sendAsyncMail() { final String conf = po.getMailConf(); final TinyMailConfig config = mailConfigProvider.bynamedConfig(conf); if (config == null) { - log.warn("tiny-mail conf={} not found", conf); + log.warn("tiny-mail conf={} not found, id={}", conf, id); + continue; } else { msg = makeMailMessage(config, po, null); } } - if (msg != null) { - try { - editLazyMail(po, msg); - } - catch (Exception e) { - log.error("tiny-mail lazy error", e); - long nxt = saveSendResult(po, msg, 0, start, e, am.retry); - if (nxt > 0) { - nexts.add(new AsyncMail(po.getId(), nxt, am.retry, am.check, null, msg)); - } - } + try { + editLazyMail(po, msg); messages.add(msg); } + catch (Exception e) { + log.error("stop tiny-mail for lazy-edit error, id=" + id, e); + saveSendResult(po, msg, 0, start, e, false); // no retry is lazy fail + } } final List brs = mailSenderManager.batchSend(messages); diff --git a/radiant/tiny-mail/src/test/java/pro/fessional/wings/tiny/app/service/TestMailSenderManager.java b/radiant/tiny-mail/src/test/java/pro/fessional/wings/tiny/app/service/TestMailSenderManager.java index 64287c95e..7f1df90dc 100644 --- a/radiant/tiny-mail/src/test/java/pro/fessional/wings/tiny/app/service/TestMailSenderManager.java +++ b/radiant/tiny-mail/src/test/java/pro/fessional/wings/tiny/app/service/TestMailSenderManager.java @@ -32,20 +32,20 @@ public TestMailSenderManager(TinyMailSenderProp senderProp, MailSenderProvider s public void singleSend(@NotNull TinyMailMessage message, long maxWait, @Nullable MimeMessagePrepareHelper preparer) { super.singleSend(message, maxWait, preparer); - String subj = message.getSubject(); - if (subj.contains("AlwaysRuntimeException")) { - throw new RuntimeException("Mock " + subj); + String text = message.getContent(); + if (text.contains("AlwaysRuntimeException")) { + throw new RuntimeException("Mock " + text); } if (exception1st.add(message.getBizId())) { - if (subj.contains("MailWaitException")) { - throw new MailWaitException(ThreadNow.millis() + 5_000, false, false, new IllegalStateException("Mock " + subj)); + if (text.contains("MailWaitException")) { + throw new MailWaitException(ThreadNow.millis() + 5_000, false, false, new IllegalStateException("Mock " + text)); } - if (subj.contains("MailParseException")) { - throw new MailParseException("Mock " + subj); + if (text.contains("MailParseException")) { + throw new MailParseException("Mock " + text); } - if (subj.contains("RuntimeException")) { - throw new RuntimeException("Mock " + subj); + if (text.contains("RuntimeException")) { + throw new RuntimeException("Mock " + text); } } } @@ -55,9 +55,9 @@ public List batchSend(Collection message List results = super.batchSend(messages, maxWait, preparer); for (BatchResult result : results) { - String subj = result.getTinyMessage().getSubject(); - if (subj.contains("AlwaysRuntimeException")) { - result.setException(new RuntimeException("Mock " + subj)); + String text = result.getTinyMessage().getContent(); + if (text.contains("AlwaysRuntimeException")) { + result.setException(new RuntimeException("Mock " + text)); } } return results; diff --git a/radiant/tiny-mail/src/test/java/pro/fessional/wings/tiny/app/service/TestTinyMailLazy.java b/radiant/tiny-mail/src/test/java/pro/fessional/wings/tiny/app/service/TestTinyMailLazy.java index 0c933046f..fdcae1a85 100644 --- a/radiant/tiny-mail/src/test/java/pro/fessional/wings/tiny/app/service/TestTinyMailLazy.java +++ b/radiant/tiny-mail/src/test/java/pro/fessional/wings/tiny/app/service/TestTinyMailLazy.java @@ -2,6 +2,7 @@ import org.jetbrains.annotations.Nullable; import org.springframework.stereotype.Service; +import pro.fessional.wings.slardar.fastjson.FastJsonHelper; import pro.fessional.wings.tiny.mail.service.TinyMailLazy; import java.util.HashSet; @@ -17,16 +18,16 @@ public class TestTinyMailLazy implements TinyMailLazy { @Override public @Nullable Edit lazyEdit(@Nullable String para) { - if(para == null) return null; - - if (exception1st.add(para)) { + if (para == null) return null; + String txt = FastJsonHelper.object(para, String.class); + if (exception1st.add(txt)) { if (para.contains("RuntimeException")) { - throw new RuntimeException("Mock "+ para); + throw new RuntimeException("Mock " + txt); } } Edit edit = new Edit(); - edit.setContent(para); + edit.setContent(txt); return edit; } } diff --git a/radiant/tiny-mail/src/test/java/pro/fessional/wings/tiny/mail/service/TinyMailServiceDbTest.java b/radiant/tiny-mail/src/test/java/pro/fessional/wings/tiny/mail/service/TinyMailServiceDbTest.java index a71d32a8c..a7d4a07a6 100644 --- a/radiant/tiny-mail/src/test/java/pro/fessional/wings/tiny/mail/service/TinyMailServiceDbTest.java +++ b/radiant/tiny-mail/src/test/java/pro/fessional/wings/tiny/mail/service/TinyMailServiceDbTest.java @@ -57,7 +57,7 @@ class TinyMailServiceDbTest { protected TinyMailLazy tinyMailLazy; @Test - @TmsLink("C15006") + @TmsLink("C15017") void mockData() { bootScan(); sendError(); @@ -67,7 +67,7 @@ void bootScan() { String subject = TestingMailUtil.dryrun("TinyMailService bootScan", mailProperties); TinyMailPlain mail0 = new TinyMailPlain(); mail0.setSubject(subject); - mail0.setContent("bootScan"); + mail0.setContent("boot scan"); long id = tinyMailService.save(mail0); Assertions.assertTrue(id > 0); // before boot scan @@ -96,44 +96,76 @@ void bootScan() { } void sendError() { - int time = 10; - String etk = "RuntimeException"; - String atk = "AlwaysRuntimeException"; - Set ids = new HashSet<>(); - String subj = TestingMailUtil.dryrun("TinyMailService", mailProperties); + + final String subj = TestingMailUtil.dryrun("TinyMailService", mailProperties); + int time = 5; + final ArrayList ids = new ArrayList<>(time); + final Set awlNg = new HashSet<>(); + final Set lzyNg = new HashSet<>(); + final Set txtNg = new HashSet<>(); for (int i = 0; i < time; i++) { - TinyMailPlain ml = new TinyMailPlain(); - boolean err = i % 3 == 0; - String tkn = err ? " " + etk + " " : " "; + final TinyMailPlain ml = new TinyMailPlain(); - if (i == 0) { - ml.setSubject(subj + " " + atk + " " + i); + final long id; + if (i % 5 == 0) { + ml.setSubject(subj + " sendError AlwaysRuntimeException " + i); + ml.setContent("text AlwaysRuntimeException " + i); + id = tinyMailService.save(ml); + awlNg.add(id); } - else { - ml.setSubject(subj + tkn + i); + else if (i % 5 == 1) { // lazy ng + ml.setSubject(subj + " sendError lazy RuntimeException " + i); + ml.setMailLazy(tinyMailLazy, "lazy RuntimeException " + i); + id = tinyMailService.save(ml); + lzyNg.add(id); } - - if (i % 2 == 0) { - ml.setContent("mail text " + i); + else if (i % 5 == 2) { // text ng + ml.setSubject(subj + " sendError text RuntimeException " + i); + ml.setContent("text RuntimeException " + i); + id = tinyMailService.save(ml); + txtNg.add(id); } - else { - ml.setMailLazy(tinyMailLazy, "lazy" + tkn + i); + else if (i % 5 == 3) { // lzy ok + ml.setSubject(subj + " sendError lazy " + i); + ml.setMailLazy(tinyMailLazy, "lazy " + i); + id = tinyMailService.save(ml); + } + else { // text ok + ml.setSubject(subj + " sendError text " + i); + ml.setContent("text " + i); + id = tinyMailService.save(ml); } - long id = tinyMailService.save(ml); ids.add(id); try { - tinyMailService.send(id, true, true); - if (err) Assertions.fail(); + boolean rc = tinyMailService.send(id, true, true); + if (lzyNg.contains(id)) { + Assertions.assertFalse(rc); + } + else if (awlNg.contains(id) || txtNg.contains(id)) { + Assertions.fail(); + } + else { + Assertions.assertTrue(rc); + } } catch (MailRetryException e) { Assertions.assertTrue(e.getCause().getMessage().contains("Mock")); } WinMailSender po = winMailSenderDao.fetchOneById(id); - if (err) { + + if (lzyNg.contains(id)) { + Assertions.assertTrue(EmptySugar.asEmptyValue(po.getNextSend())); // stop next + Assertions.assertTrue(StringUtils.isNotBlank(po.getLastFail())); + Assertions.assertTrue(StringUtils.isBlank(po.getMailText())); + Assertions.assertEquals(1, po.getSumFail()); + Assertions.assertEquals(1, po.getSumSend()); + Assertions.assertEquals(0, po.getSumDone()); + } + else if (awlNg.contains(id) || txtNg.contains(id)) { Assertions.assertTrue(po.getNextSend().isAfter(ThreadNow.localDateTime())); Assertions.assertTrue(StringUtils.isNotBlank(po.getLastFail())); Assertions.assertEquals(1, po.getSumFail()); @@ -154,29 +186,34 @@ void sendError() { log.info("after try next, slept={}", ms); List pos = winMailSenderDao.fetchById(ids); + int maxFail = tinyMailServiceProp.getMaxFail(); for (WinMailSender po : pos) { Assertions.assertTrue(EmptySugar.asEmptyValue(po.getNextSend())); Assertions.assertTrue(EmptySugar.nonEmptyValue(po.getLastSend())); - int sumFail = 0; - - String sub = po.getMailSubj(); - if (sub.contains(etk) || sub.contains(atk)) { - sumFail++; - } - else if (po.getLazyPara() != null && po.getLazyPara().contains(etk)) { - sumFail++; - } - if (sub.contains(atk)) { - int maxFail = tinyMailServiceProp.getMaxFail(); + Long id = po.getId(); + if (awlNg.contains(id)) { Assertions.assertEquals(maxFail, po.getSumSend()); Assertions.assertEquals(maxFail, po.getSumFail()); Assertions.assertEquals(0, po.getSumDone()); Assertions.assertTrue(StringUtils.isNotBlank(po.getLastFail())); } + else if (lzyNg.contains(id)) { + Assertions.assertEquals(1, po.getSumSend()); + Assertions.assertEquals(1, po.getSumFail()); + Assertions.assertEquals(0, po.getSumDone()); + Assertions.assertTrue(StringUtils.isBlank(po.getMailText())); + Assertions.assertTrue(StringUtils.isNotBlank(po.getLastFail())); + } + else if (txtNg.contains(id)) { + Assertions.assertEquals(2, po.getSumSend()); + Assertions.assertEquals(1, po.getSumFail()); + Assertions.assertEquals(1, po.getSumDone()); + Assertions.assertTrue(StringUtils.isBlank(po.getLastFail())); + } else { - Assertions.assertEquals(sumFail + 1, po.getSumSend()); - Assertions.assertEquals(sumFail, po.getSumFail()); + Assertions.assertEquals(1, po.getSumSend()); + Assertions.assertEquals(0, po.getSumFail()); Assertions.assertEquals(1, po.getSumDone()); Assertions.assertTrue(StringUtils.isBlank(po.getLastFail())); } @@ -187,5 +224,38 @@ else if (po.getLazyPara() != null && po.getLazyPara().contains(etk)) { Assertions.assertTrue(queue.isEmpty()); TreeMap> sched = tinyMailService.listAsyncMailSched(); Assertions.assertTrue(sched.isEmpty()); + + // retry as if it was fixed, but 1st send error + for (Long id : lzyNg) { + long rc = tinyMailService.post(id, false, true); + Assertions.assertEquals(TinyMailService.ErrOther, rc); + } + + // retry, no 1st error + for (Long id : lzyNg) { + long rc = tinyMailService.post(id, false, true); + Assertions.assertEquals(TinyMailService.Success, rc); + } + + // retry with check + for (Long id : lzyNg) { + long rc = tinyMailService.post(id, false, true); + Assertions.assertEquals(TinyMailService.ErrCheck, rc); + } + + // force to send without check + for (Long id : lzyNg) { + long rc = tinyMailService.post(id, false, false); + Assertions.assertEquals(TinyMailService.Success, rc); + } + + List pvz = winMailSenderDao.fetchById(lzyNg); + for (WinMailSender po : pvz) { + Assertions.assertEquals(4, po.getSumSend()); + Assertions.assertEquals(2, po.getSumFail()); + Assertions.assertEquals(2, po.getSumDone()); + Assertions.assertTrue(StringUtils.isNotBlank(po.getMailText())); + Assertions.assertTrue(StringUtils.isBlank(po.getLastFail())); + } } } From 93a1045e519dcfa41f16f95a491e2cae5b9884a6 Mon Sep 17 00:00:00 2001 From: trydofor Date: Tue, 16 Jul 2024 09:53:15 +0800 Subject: [PATCH 23/51] =?UTF-8?q?=E2=9C=A8=20tinymail=20lazy=20stop=20send?= =?UTF-8?q?ing=20#273?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../tiny/mail/sender/MailRetryException.java | 2 + .../tiny/mail/sender/MailStopException.java | 22 +++++ .../tiny/mail/sender/MailWaitException.java | 2 + .../wings/tiny/mail/service/TinyMailLazy.java | 3 +- .../tiny/mail/service/TinyMailService.java | 13 ++- .../service/impl/TinyMailServiceImpl.java | 84 +++++++++---------- 6 files changed, 78 insertions(+), 48 deletions(-) create mode 100644 radiant/tiny-mail/src/main/java/pro/fessional/wings/tiny/mail/sender/MailStopException.java diff --git a/radiant/tiny-mail/src/main/java/pro/fessional/wings/tiny/mail/sender/MailRetryException.java b/radiant/tiny-mail/src/main/java/pro/fessional/wings/tiny/mail/sender/MailRetryException.java index 2198258d2..2324a774f 100644 --- a/radiant/tiny-mail/src/main/java/pro/fessional/wings/tiny/mail/sender/MailRetryException.java +++ b/radiant/tiny-mail/src/main/java/pro/fessional/wings/tiny/mail/sender/MailRetryException.java @@ -4,6 +4,8 @@ import org.springframework.mail.MailException; /** + * should retry at nextEpoch + * * @author trydofor * @since 2023-01-03 */ diff --git a/radiant/tiny-mail/src/main/java/pro/fessional/wings/tiny/mail/sender/MailStopException.java b/radiant/tiny-mail/src/main/java/pro/fessional/wings/tiny/mail/sender/MailStopException.java new file mode 100644 index 000000000..3f5bb0126 --- /dev/null +++ b/radiant/tiny-mail/src/main/java/pro/fessional/wings/tiny/mail/sender/MailStopException.java @@ -0,0 +1,22 @@ +package pro.fessional.wings.tiny.mail.sender; + +import lombok.Getter; +import org.springframework.mail.MailException; + +/** + * stop sending, maybe format, prepare error + * + * @author trydofor + * @since 2023-01-03 + */ +@Getter +public class MailStopException extends MailException { + + public MailStopException(String msg) { + super(msg); + } + + public MailStopException(String msg, Throwable cause) { + super(msg, cause); + } +} diff --git a/radiant/tiny-mail/src/main/java/pro/fessional/wings/tiny/mail/sender/MailWaitException.java b/radiant/tiny-mail/src/main/java/pro/fessional/wings/tiny/mail/sender/MailWaitException.java index f9d6796a7..e07522b8f 100644 --- a/radiant/tiny-mail/src/main/java/pro/fessional/wings/tiny/mail/sender/MailWaitException.java +++ b/radiant/tiny-mail/src/main/java/pro/fessional/wings/tiny/mail/sender/MailWaitException.java @@ -4,6 +4,8 @@ import org.springframework.mail.MailException; /** + * should wait until waitEpoch, then may retry + * * @author trydofor * @since 2023-01-03 */ diff --git a/radiant/tiny-mail/src/main/java/pro/fessional/wings/tiny/mail/service/TinyMailLazy.java b/radiant/tiny-mail/src/main/java/pro/fessional/wings/tiny/mail/service/TinyMailLazy.java index 4ccbdecc0..5a838856c 100644 --- a/radiant/tiny-mail/src/main/java/pro/fessional/wings/tiny/mail/service/TinyMailLazy.java +++ b/radiant/tiny-mail/src/main/java/pro/fessional/wings/tiny/mail/service/TinyMailLazy.java @@ -25,7 +25,8 @@ default String lazyPara(@Nullable Object para) { } /** - * use lazyPara to edit the lazy mail if returned items is nonnull + * use lazyPara to edit the lazy mail if get nonnull item. + * stop sending if get exception or all null items */ @Nullable Edit lazyEdit(@Nullable String para); diff --git a/radiant/tiny-mail/src/main/java/pro/fessional/wings/tiny/mail/service/TinyMailService.java b/radiant/tiny-mail/src/main/java/pro/fessional/wings/tiny/mail/service/TinyMailService.java index 203503cd1..c96abb87f 100644 --- a/radiant/tiny-mail/src/main/java/pro/fessional/wings/tiny/mail/service/TinyMailService.java +++ b/radiant/tiny-mail/src/main/java/pro/fessional/wings/tiny/mail/service/TinyMailService.java @@ -21,7 +21,7 @@ public interface TinyMailService { int Success = 0; /** - * failed to check before send. e.g. prop, lock or format + * failed to check before send. e.g. prepare and check prop, lock, format */ int ErrCheck = -1; @@ -142,10 +142,17 @@ default long emit(@NotNull TinyMailPlain message) { long emit(long id, boolean retry, boolean check); /** - * Create(id is empty) or edit a mail, return the id. + * Create(id is empty) or edit a mail with check, return the id. * NOTE: no schedule to send, need manually send/post/emit it. */ - long save(@NotNull TinyMailPlain message); + default long save(@NotNull TinyMailPlain message){ + return save(message, true); + } + /** + * Create(id is empty) or edit a mail with check, return the id. + * NOTE: no schedule to send, need manually send/post/emit it. + */ + long save(@NotNull TinyMailPlain message, boolean check); /** *
diff --git a/radiant/tiny-mail/src/main/java/pro/fessional/wings/tiny/mail/service/impl/TinyMailServiceImpl.java b/radiant/tiny-mail/src/main/java/pro/fessional/wings/tiny/mail/service/impl/TinyMailServiceImpl.java
index 222987985..ea0eff818 100644
--- a/radiant/tiny-mail/src/main/java/pro/fessional/wings/tiny/mail/service/impl/TinyMailServiceImpl.java
+++ b/radiant/tiny-mail/src/main/java/pro/fessional/wings/tiny/mail/service/impl/TinyMailServiceImpl.java
@@ -20,7 +20,6 @@
 import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
 import org.springframework.stereotype.Service;
 import pro.fessional.mirana.best.AssertArgs;
-import pro.fessional.mirana.best.AssertState;
 import pro.fessional.mirana.best.Param;
 import pro.fessional.mirana.cast.BoxedCastUtil;
 import pro.fessional.mirana.cond.IfSetter;
@@ -44,6 +43,7 @@
 import pro.fessional.wings.tiny.mail.sender.MailRetryException;
 import pro.fessional.wings.tiny.mail.sender.MailSenderManager;
 import pro.fessional.wings.tiny.mail.sender.MailSenderManager.BatchResult;
+import pro.fessional.wings.tiny.mail.sender.MailStopException;
 import pro.fessional.wings.tiny.mail.sender.MailWaitException;
 import pro.fessional.wings.tiny.mail.sender.TinyMailConfig;
 import pro.fessional.wings.tiny.mail.sender.TinyMailMessage;
@@ -217,7 +217,7 @@ protected long doSend(boolean sync, long id, boolean retry, boolean check) {
 
     @Override
     @SuppressWarnings("DuplicatedCode")
-    public long save(@NotNull TinyMailPlain msg) {
+    public long save(@NotNull TinyMailPlain msg, boolean check) {
         final String conf = msg.getConf();
         final TinyMailConfig config = mailConfigProvider.bynamedConfig(conf);
         AssertArgs.notNull(config, "skip tiny-mail conf={} not found", conf);
@@ -270,9 +270,11 @@ public long save(@NotNull TinyMailPlain msg) {
         IfSetter.nonnull(po::setRefKey1, msg.getRefKey1());
         IfSetter.nonnull(po::setRefKey2, msg.getRefKey2());
 
-        // try to check message format
-        final TinyMailMessage tms = makeMailMessage(config, po, null);
-        mailSenderManager.checkMessage(tms);
+        if (check) {
+            // try to check message format
+            final TinyMailMessage tms = makeMailMessage(config, po, null);
+            mailSenderManager.checkMessage(tms);
+        }
 
         journalService.commit(Jane.Insert, journal -> {
             if (isNew) {
@@ -565,8 +567,9 @@ protected boolean notNextLock(@NotNull WinMailSender po, long now) {
     /**
      * next if done lt max or exception and retry
      */
-    protected long saveSendResult(@NotNull WinMailSender po, @NotNull TinyMailMessage message, long cost, long exit, Exception exception, boolean retry) {
+    protected long saveSendResult(@NotNull WinMailSender po, long cost, long exit, Exception exception, boolean retry) {
         long nextSend = -1;
+        final Long id = po.getId();
         try {
             final WinMailSenderTable t = winMailSenderDao.getTable();
             final Map setter = new HashMap<>();
@@ -578,11 +581,11 @@ protected long saveSendResult(@NotNull WinMailSender po, @NotNull TinyMailMessag
                 final int poDone = BoxedCastUtil.orZero(po.getMaxDone());
                 final int maxDone = poDone > 0 ? poDone : tinyMailServiceProp.getMaxDone();
                 if (po.getSumDone() + 1 >= maxDone) {
-                    log.debug("done tiny-mail by max-send id={}, subject={}", po.getId(), po.getMailSubj());
+                    log.debug("done tiny-mail by max-send id={}, subject={}", id, po.getMailSubj());
                 }
                 else {
                     nextSend = exit + tinyMailServiceProp.getTryNext().toMillis();
-                    log.debug("next done tiny-mail id={}, subject={}", po.getId(), po.getMailSubj());
+                    log.debug("next done tiny-mail id={}, subject={}", id, po.getMailSubj());
                 }
 
                 setter.put(t.SumSend, t.SumSend.add(1));
@@ -596,27 +599,31 @@ protected long saveSendResult(@NotNull WinMailSender po, @NotNull TinyMailMessag
                 final int poFail = BoxedCastUtil.orZero(po.getMaxFail());
                 final int maxFail = poFail > 0 ? poFail : tinyMailServiceProp.getMaxFail();
                 if (po.getSumFail() + 1 >= maxFail) {
-                    log.debug("done tiny-mail by max-fail id={}, subject={}", po.getId(), po.getMailSubj());
+                    log.debug("done tiny-mail by max-fail id={}, subject={}", id, po.getMailSubj());
                 }
                 else if (retry) {
-                    if (exception instanceof MailWaitException mwe) {
+                    if (exception instanceof MailStopException) {
+                        log.warn("stop tiny-mail by stop-exception, id=" + id, exception);
+                    }
+                    else if (exception instanceof MailWaitException mwe) {
                         if (mwe.isStopRetry()) {
-                            log.error("stop stop-retry tiny-mail, id=" + po.getId(), exception);
+                            log.error("stop tiny-mail by stop-retry, id=" + id, exception);
                         }
                         else {
                             nextSend = mwe.getWaitEpoch();
                         }
                     }
                     else if (exception instanceof MailParseException || exception instanceof MessagingException) {
-                        log.error("failed to parse, stop tiny-mail, id=" + po.getId(), exception);
+                        log.error("stop tiny-mail by failed parse, id=" + id, exception);
                     }
                     else {
                         nextSend = exit + tinyMailServiceProp.getTryNext().toMillis();
                     }
                 }
                 else {
-                    log.error("stop not-retry tiny-mail, id=" + po.getId(), exception);
+                    log.error("stop tiny-mail by not-retry, id=" + id, exception);
                 }
+
                 setter.put(t.SumSend, t.SumSend.add(1));
                 setter.put(t.SumFail, t.SumFail.add(1));
             }
@@ -636,12 +643,12 @@ else if (exception instanceof MailParseException || exception instanceof Messagi
             }
 
             if (hookStop) {
-                log.debug("hook stop tiny-mail, id={}", po.getId());
+                log.debug("stop tiny-mail by hook, id={}", id);
             }
 
             if (nextSend > 0) {
                 setter.put(t.NextSend, DateLocaling.sysLdt(nextSend));
-                log.debug("next tiny-mail id={}, subject={}", po.getId(), po.getMailSubj());
+                log.debug("next tiny-mail id={}, subject={}", id, po.getMailSubj());
             }
             else {
                 setter.put(t.NextSend, EmptyValue.DATE_TIME);
@@ -653,29 +660,33 @@ else if (exception instanceof MailParseException || exception instanceof Messagi
                 winMailSenderDao.ctx()
                                 .update(t)
                                 .set(setter)
-                                .where(t.Id.eq(po.getId()))
+                                .where(t.Id.eq(id))
                                 .execute();
             });
         }
         catch (Exception e) {
-            log.error("failed to save tiny-mail status, id=" + po.getId() + ", subject=" + po.getMailSubj(), e);
+            log.error("failed to save tiny-mail status, id=" + id + ", subject=" + po.getMailSubj(), e);
             nextSend = exit + tinyMailServiceProp.getTryNext().toMillis();
         }
 
         return nextSend;
     }
 
-    protected boolean editLazyMail(@NotNull WinMailSender po, @NotNull @Param.Out TinyMailMessage message) {
+    protected void editLazyMail(@NotNull WinMailSender po, @NotNull @Param.Out TinyMailMessage message) {
         // nonnull means no need to edit
-        if (message.getContent() != null) return false;
+        if (message.getContent() != null) return;
 
         final Long id = po.getId();
         final String bn = po.getLazyBean();
         var bean = lazyBeanHolder.get(bn);
-        AssertState.notNull(bean, "skip tiny-mail lazy-edit bean not found, bean={}, mail-id={}", bn, id);
+        if (bean == null) {
+            throw new MailStopException("tiny-mail lazy-edit, not-found bean=" + bn + ", id=" + id);
+        }
 
         var edit = bean.lazyEdit(po.getLazyPara());
-        if (edit == null) return false;
+        if (edit == null) {
+            throw new MailStopException("tiny-mail lazy-edit, edit is null, id=" + id);
+        }
 
         final WinMailSenderTable t = winMailSenderDao.getTable();
         final Map setter = new HashMap<>();
@@ -704,7 +715,9 @@ protected boolean editLazyMail(@NotNull WinMailSender po, @NotNull @Param.Out Ti
             message.setAttachment(file);
         }
 
-        if (setter.isEmpty()) return false;
+        if (setter.isEmpty()) {
+            throw new MailStopException("tiny-mail lazy-edit, edit is empty, id=" + id);
+        }
 
         log.debug("lazy-edit tiny-mail, id={}", id);
 
@@ -717,8 +730,6 @@ protected boolean editLazyMail(@NotNull WinMailSender po, @NotNull @Param.Out Ti
                             .where(t.Id.eq(id))
                             .execute();
         });
-
-        return true;
     }
 
     private long doSyncSend(@NotNull WinMailSender po, @NotNull TinyMailMessage message, boolean retry, boolean check) {
@@ -741,7 +752,7 @@ private long doSyncSend(@NotNull WinMailSender po, @NotNull TinyMailMessage mess
         }
         catch (Exception e) {
             log.error("stop tiny-mail for lazy-edit error, id=" + id, e);
-            saveSendResult(po, message, 0, start, e, false); // no retry is lazy fail
+            saveSendResult(po, 0, start, e, false); // no retry is lazy fail
             return ErrCheck;
         }
 
@@ -754,7 +765,7 @@ private long doSyncSend(@NotNull WinMailSender po, @NotNull TinyMailMessage mess
         }
         finally {
             final long end = ThreadNow.millis();
-            long nxt = saveSendResult(po, message, end - start, end, exception, retry);
+            long nxt = saveSendResult(po, end - start, end, exception, retry);
             if (nxt > 0) {
                 planAsyncMail(new AsyncMail(id, nxt, retry, check, null, message));
                 log.debug("plan tiny-mail next-send, err={}, id={}, subject={}", exception == null, id, po.getMailSubj());
@@ -786,14 +797,13 @@ private long doAsyncSend(@NotNull WinMailSender po, @NotNull TinyMailMessage mes
         }
         catch (Exception e) {
             log.error("stop tiny-mail for lazy-edit error, id=" + id, e);
-            saveSendResult(po, message, 0, start, e, false); // no retry is lazy fail
+            saveSendResult(po, 0, start, e, false); // no retry is lazy fail
             return ErrCheck;
         }
 
         final LocalDateTime ns = po.getNextSend();
         final long nsm = ns == null ? 0 : DateLocaling.sysEpoch(ns);
 
-
         long next;
         if (nsm > start) {
             next = nsm;
@@ -804,20 +814,6 @@ private long doAsyncSend(@NotNull WinMailSender po, @NotNull TinyMailMessage mes
             log.debug("plan async tiny-mail date=now id={}", id);
         }
 
-        try {
-            mailSenderManager.checkMessage(message);
-        }
-        catch (Exception e) {
-            log.error("tiny-mail check error, id=" + id, e);
-            long nx = saveSendResult(po, message, 0, start, e, retry);
-            if (nx > 0) {
-                next = nx;
-            }
-            else {
-                return ErrCheck;
-            }
-        }
-
         planAsyncMail(new AsyncMail(id, next, retry, check, po, message));
         return next;
     }
@@ -954,7 +950,7 @@ private void sendAsyncMail() {
                     }
                     catch (Exception e) {
                         log.error("stop tiny-mail for lazy-edit error, id=" + id, e);
-                        saveSendResult(po, msg, 0, start, e, false); // no retry is lazy fail
+                        saveSendResult(po, 0, start, e, false); // no retry is lazy fail
                     }
                 }
 
@@ -966,7 +962,7 @@ private void sendAsyncMail() {
                     final AsyncMail am = mails.get(po.getId());
                     if (am == null) continue; // never null
 
-                    long nxt = saveSendResult(po, msg, br.getCostMillis(), br.getExitMillis(), br.getException(), am.retry);
+                    long nxt = saveSendResult(po, br.getCostMillis(), br.getExitMillis(), br.getException(), am.retry);
                     if (nxt > 0) {
                         nexts.add(new AsyncMail(po.getId(), nxt, am.retry, am.check, null, msg));
                     }

From 262e598bde1c8a9b14c483f123cfce59fd3e1c9b Mon Sep 17 00:00:00 2001
From: trydofor 
Date: Wed, 17 Jul 2024 10:38:53 +0800
Subject: [PATCH 24/51] =?UTF-8?q?=F0=9F=8E=A8=20avoid=20circular=20referen?=
 =?UTF-8?q?ce=20#270?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 observe/docs                                  |   2 +-
 .../service/impl/TinyMailServiceImpl.java     | 155 +++++++++---------
 .../spring/bean/TinyMailConfiguration.java    |  31 ++++
 .../tiny/app/service/TestTinyMailLazy.java    |  16 ++
 .../spring/help/ApplicationContextHelper.java |  45 +++++
 5 files changed, 171 insertions(+), 78 deletions(-)

diff --git a/observe/docs b/observe/docs
index b7f98fdbc..2f1f881be 160000
--- a/observe/docs
+++ b/observe/docs
@@ -1 +1 @@
-Subproject commit b7f98fdbcca854143856b6032bf8c1819b601f15
+Subproject commit 2f1f881be0c8e67207eea41c5818a1fb5801a89f
diff --git a/radiant/tiny-mail/src/main/java/pro/fessional/wings/tiny/mail/service/impl/TinyMailServiceImpl.java b/radiant/tiny-mail/src/main/java/pro/fessional/wings/tiny/mail/service/impl/TinyMailServiceImpl.java
index ea0eff818..25d0b5ce7 100644
--- a/radiant/tiny-mail/src/main/java/pro/fessional/wings/tiny/mail/service/impl/TinyMailServiceImpl.java
+++ b/radiant/tiny-mail/src/main/java/pro/fessional/wings/tiny/mail/service/impl/TinyMailServiceImpl.java
@@ -9,6 +9,7 @@
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
 import org.springframework.beans.factory.InitializingBean;
+import org.springframework.beans.factory.ObjectProvider;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Value;
 import org.springframework.boot.autoconfigure.task.TaskSchedulingProperties;
@@ -19,6 +20,7 @@
 import org.springframework.mail.MailSendException;
 import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
 import org.springframework.stereotype.Service;
+import org.springframework.util.function.SingletonSupplier;
 import pro.fessional.mirana.best.AssertArgs;
 import pro.fessional.mirana.best.Param;
 import pro.fessional.mirana.cast.BoxedCastUtil;
@@ -66,7 +68,6 @@
 import java.util.PriorityQueue;
 import java.util.Set;
 import java.util.TreeMap;
-import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ScheduledFuture;
 import java.util.concurrent.atomic.AtomicInteger;
 import java.util.concurrent.atomic.AtomicLong;
@@ -100,14 +101,15 @@ public class TinyMailServiceImpl implements TinyMailService, InitializingBean {
     protected TinyMailServiceProp tinyMailServiceProp;
     @Setter(onMethod_ = { @Autowired })
     protected ResourceLoader resourceLoader;
-    @Setter(onMethod_ = { @Autowired(required = false) })
-    protected List statusHooks;
-    @Setter(onMethod_ = { @Autowired(required = false) })
-    protected Map namedLazyBean;
+    @Setter(onMethod_ = { @Autowired })
+    protected ObjectProvider statusHookProvider;
+    @Setter(onMethod_ = { @Autowired })
+    protected ObjectProvider lazyBeanProvider;
 
     // init by afterPropertiesSet
     protected ThreadPoolTaskScheduler taskScheduler;
-    protected Map lazyBeanHolder;
+    protected SingletonSupplier> lazyBeanHolder;
+    protected SingletonSupplier> statusHookHolder;
 
     protected final PriorityQueue asyncMailQueue = new PriorityQueue<>();
     protected final TreeMap> asyncMailSched = new TreeMap<>();
@@ -182,37 +184,37 @@ public long emit(long id, boolean retry, boolean check) {
         }
     }
 
-    protected long doSend(boolean sync, @NotNull TinyMail message, boolean retry) {
-        final String conf = message.getConf();
-        final TinyMailConfig config = mailConfigProvider.bynamedConfig(conf);
-        AssertArgs.notNull(config, "skip tiny-mail conf={} not found", conf);
+    @Override
+    public void afterPropertiesSet() {
+        ThreadPoolTaskSchedulerBuilder builder = new ThreadPoolTaskSchedulerBuilder();
+        TaskSchedulingProperties scheduler = tinyMailServiceProp.getScheduler();
+        builder = builder.poolSize(scheduler.getPool().getSize());
+        builder = builder.threadNamePrefix(scheduler.getThreadNamePrefix());
+        TaskSchedulingProperties.Shutdown shutdown = scheduler.getShutdown();
+        builder = builder.awaitTermination(shutdown.isAwaitTermination());
+        builder = builder.awaitTerminationPeriod(shutdown.getAwaitTerminationPeriod());
 
-        final WinMailSender po = saveMailSender(config, message);
+        taskScheduler = TaskSchedulerHelper.Ttl(builder);
+        taskScheduler.initialize();
+        log.info("tiny-mail taskScheduler, prefix=" + taskScheduler.getThreadNamePrefix());
 
-        final TinyMailMessage mailMessage = makeMailMessage(config, po, message);
-        if (sync) {
-            return doSyncSend(po, mailMessage, retry, true);
-        }
-        else {
-            return doAsyncSend(po, mailMessage, retry, true);
+        final long idle = tinyMailServiceProp.getBootScan().toMillis();
+        if (idle > 0) {
+            log.info("tiny-mail schedule boot-scan after={} ms", idle);
+            taskScheduler.schedule(this::scanIdle, Instant.ofEpochMilli(ThreadNow.millis() + idle));
         }
-    }
-
-    protected long doSend(boolean sync, long id, boolean retry, boolean check) {
-        final WinMailSender po = winMailSenderDao.fetchOneById(id);
-        AssertArgs.notNull(po, "skip tiny-mail not found by id={}", id);
-
-        final String conf = po.getMailConf();
-        final TinyMailConfig config = mailConfigProvider.bynamedConfig(conf);
-        AssertArgs.notNull(config, "skip tiny-mail conf={} not found, id={}", conf, id);
 
-        final TinyMailMessage mailMessage = makeMailMessage(config, po, null);
-        if (sync) {
-            return doSyncSend(po, mailMessage, retry, check);
-        }
-        else {
-            return doAsyncSend(po, mailMessage, retry, check);
-        }
+        statusHookHolder = SingletonSupplier.of(() -> statusHookProvider.orderedStream().toList());
+        lazyBeanHolder = SingletonSupplier.of(() -> {
+            Map map = new HashMap<>();
+            for (TinyMailLazy bean : lazyBeanProvider) {
+                TinyMailLazy old = map.put(bean.lazyBean(), bean);
+                if (old != null) {
+                    log.error("lazy bean name existed, name={}, new-bean={}", old.lazyBean(), bean.getClass());
+                }
+            }
+            return map.isEmpty() ? Collections.emptyMap() : map;
+        });
     }
 
     @Override
@@ -374,39 +376,6 @@ protected int scanSync() {
         return size;
     }
 
-    @Override
-    public void afterPropertiesSet() {
-        ThreadPoolTaskSchedulerBuilder builder = new ThreadPoolTaskSchedulerBuilder();
-        TaskSchedulingProperties scheduler = tinyMailServiceProp.getScheduler();
-        builder = builder.poolSize(scheduler.getPool().getSize());
-        builder = builder.threadNamePrefix(scheduler.getThreadNamePrefix());
-        TaskSchedulingProperties.Shutdown shutdown = scheduler.getShutdown();
-        builder = builder.awaitTermination(shutdown.isAwaitTermination());
-        builder = builder.awaitTerminationPeriod(shutdown.getAwaitTerminationPeriod());
-
-        taskScheduler = TaskSchedulerHelper.Ttl(builder);
-        taskScheduler.initialize();
-        log.info("tiny-mail taskScheduler, prefix=" + taskScheduler.getThreadNamePrefix());
-
-        if (namedLazyBean != null && !namedLazyBean.isEmpty()) {
-            lazyBeanHolder = new ConcurrentHashMap<>();
-            for (var en : namedLazyBean.entrySet()) {
-                TinyMailLazy bean = en.getValue();
-                TinyMailLazy old = lazyBeanHolder.put(bean.lazyBean(), bean);
-                if (old != null) {
-                    throw new IllegalStateException("lazy bean name existed, name=" + old.lazyBean() + ", new-bean=" + en.getKey());
-                }
-            }
-            log.info("tiny-mail TinyMailLazy beans, size=" + lazyBeanHolder.size());
-        }
-
-        final long idle = tinyMailServiceProp.getBootScan().toMillis();
-        if (idle > 0) {
-            log.info("tiny-mail schedule boot-scan after={} ms", idle);
-            taskScheduler.schedule(this::scanIdle, Instant.ofEpochMilli(ThreadNow.millis() + idle));
-        }
-    }
-
     protected TinyMailMessage makeMailMessage(@NotNull TinyMailConfig config, @NotNull WinMailSender po, @Nullable TinyMail msg) {
         final TinyMailMessage message = new TinyMailMessage();
         TinyMailConfig.ConfSetter.toAny(message, config);
@@ -533,7 +502,7 @@ protected boolean notMatchProp(@NotNull WinMailSender po) {
         }
 
         if (po.getMailText() == null) {
-            var bean = lazyBeanHolder.get(po.getLazyBean());
+            var bean = lazyBeanHolder.obtain().get(po.getLazyBean());
             if (bean == null) {
                 log.error("stop lazy tiny-mail, not found bean={}, id={}", bean, po.getId());
                 return true;
@@ -564,6 +533,39 @@ protected boolean notNextLock(@NotNull WinMailSender po, long now) {
         return false;
     }
 
+    protected long doSend(boolean sync, @NotNull TinyMail message, boolean retry) {
+        final String conf = message.getConf();
+        final TinyMailConfig config = mailConfigProvider.bynamedConfig(conf);
+        AssertArgs.notNull(config, "skip tiny-mail conf={} not found", conf);
+
+        final WinMailSender po = saveMailSender(config, message);
+
+        final TinyMailMessage mailMessage = makeMailMessage(config, po, message);
+        if (sync) {
+            return doSyncSend(po, mailMessage, retry, true);
+        }
+        else {
+            return doAsyncSend(po, mailMessage, retry, true);
+        }
+    }
+
+    protected long doSend(boolean sync, long id, boolean retry, boolean check) {
+        final WinMailSender po = winMailSenderDao.fetchOneById(id);
+        AssertArgs.notNull(po, "skip tiny-mail not found by id={}", id);
+
+        final String conf = po.getMailConf();
+        final TinyMailConfig config = mailConfigProvider.bynamedConfig(conf);
+        AssertArgs.notNull(config, "skip tiny-mail conf={} not found, id={}", conf, id);
+
+        final TinyMailMessage mailMessage = makeMailMessage(config, po, null);
+        if (sync) {
+            return doSyncSend(po, mailMessage, retry, check);
+        }
+        else {
+            return doAsyncSend(po, mailMessage, retry, check);
+        }
+    }
+
     /**
      * next if done lt max or exception and retry
      */
@@ -629,17 +631,16 @@ else if (exception instanceof MailParseException || exception instanceof Messagi
             }
 
             boolean hookStop = false;
-            if (statusHooks != null) {
-                for (StatusHook sh : statusHooks) {
-                    try {
-                        if (sh.stop(po, cost, exception)) {
-                            hookStop = true;
-                        }
-                    }
-                    catch (Exception e) {
-                        log.error("should NOT throw in hook, hook-class=" + sh.getClass().getName(), e);
+
+            for (StatusHook sh : statusHookHolder.obtain()) {
+                try {
+                    if (sh.stop(po, cost, exception)) {
+                        hookStop = true;
                     }
                 }
+                catch (Exception e) {
+                    log.error("should NOT throw in hook, hook-class=" + sh.getClass().getName(), e);
+                }
             }
 
             if (hookStop) {
@@ -678,7 +679,7 @@ protected void editLazyMail(@NotNull WinMailSender po, @NotNull @Param.Out TinyM
 
         final Long id = po.getId();
         final String bn = po.getLazyBean();
-        var bean = lazyBeanHolder.get(bn);
+        var bean = lazyBeanHolder.obtain().get(bn);
         if (bean == null) {
             throw new MailStopException("tiny-mail lazy-edit, not-found bean=" + bn + ", id=" + id);
         }
diff --git a/radiant/tiny-mail/src/main/java/pro/fessional/wings/tiny/mail/spring/bean/TinyMailConfiguration.java b/radiant/tiny-mail/src/main/java/pro/fessional/wings/tiny/mail/spring/bean/TinyMailConfiguration.java
index 7928c1d35..f832f175a 100644
--- a/radiant/tiny-mail/src/main/java/pro/fessional/wings/tiny/mail/spring/bean/TinyMailConfiguration.java
+++ b/radiant/tiny-mail/src/main/java/pro/fessional/wings/tiny/mail/spring/bean/TinyMailConfiguration.java
@@ -2,12 +2,15 @@
 
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
+import org.jetbrains.annotations.NotNull;
 import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
 import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.ComponentScan;
 import org.springframework.context.annotation.Configuration;
 import org.springframework.mail.javamail.JavaMailSender;
 import org.springframework.web.bind.annotation.RestController;
+import pro.fessional.wings.silencer.runner.ApplicationReadyEventRunner;
+import pro.fessional.wings.silencer.spring.WingsOrdered;
 import pro.fessional.wings.silencer.spring.boot.ConditionalWingsEnabled;
 import pro.fessional.wings.tiny.mail.controller.MailListController;
 import pro.fessional.wings.tiny.mail.database.TinyMailDatabase;
@@ -15,10 +18,14 @@
 import pro.fessional.wings.tiny.mail.sender.MailNotice;
 import pro.fessional.wings.tiny.mail.sender.MailSenderManager;
 import pro.fessional.wings.tiny.mail.sender.MailSenderProvider;
+import pro.fessional.wings.tiny.mail.service.TinyMailLazy;
 import pro.fessional.wings.tiny.mail.service.TinyMailService;
 import pro.fessional.wings.tiny.mail.spring.prop.TinyMailConfigProp;
 import pro.fessional.wings.tiny.mail.spring.prop.TinyMailSenderProp;
 
+import java.util.HashMap;
+import java.util.Map;
+
 /**
  * @author trydofor
  * @since 2022-08-03
@@ -77,4 +84,28 @@ public MailSenderProvider mailSenderProvider(JavaMailSender defaultSender) {
         log.info("TinyMail spring-bean mailSenderProvider");
         return new MailSenderProvider(defaultSender);
     }
+
+    /**
+     * Check if the bean name is duplicated
+     */
+    @Bean
+    @ConditionalWingsEnabled
+    public ApplicationReadyEventRunner tinyMailLazyRunner(@NotNull Map lazyMap) {
+        log.info("TinyMail spring-runs tinyMailLazyRunner");
+        return new ApplicationReadyEventRunner(WingsOrdered.Lv3Service, ignored -> {
+            Map map = new HashMap<>();
+            for (var en : lazyMap.entrySet()) {
+                TinyMailLazy bean = en.getValue();
+                TinyMailLazy old = map.put(bean.lazyBean(), bean);
+                if (old != null) {
+                    throw new IllegalStateException(
+                        "lazy bean name existed, name=" + old.lazyBean() +
+                        ", new-bean-name=" + en.getKey() +
+                        ", old-bean-class=" + old.getClass()
+                    );
+                }
+            }
+            log.info("tiny-mail TinyMailLazy beans, size=" + map.size());
+        });
+    }
 }
diff --git a/radiant/tiny-mail/src/test/java/pro/fessional/wings/tiny/app/service/TestTinyMailLazy.java b/radiant/tiny-mail/src/test/java/pro/fessional/wings/tiny/app/service/TestTinyMailLazy.java
index fdcae1a85..bf5c02c93 100644
--- a/radiant/tiny-mail/src/test/java/pro/fessional/wings/tiny/app/service/TestTinyMailLazy.java
+++ b/radiant/tiny-mail/src/test/java/pro/fessional/wings/tiny/app/service/TestTinyMailLazy.java
@@ -1,9 +1,13 @@
 package pro.fessional.wings.tiny.app.service;
 
+import lombok.Setter;
 import org.jetbrains.annotations.Nullable;
+import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 import pro.fessional.wings.slardar.fastjson.FastJsonHelper;
+import pro.fessional.wings.tiny.mail.service.TinyMail;
 import pro.fessional.wings.tiny.mail.service.TinyMailLazy;
+import pro.fessional.wings.tiny.mail.service.TinyMailService;
 
 import java.util.HashSet;
 
@@ -16,6 +20,18 @@ public class TestTinyMailLazy implements TinyMailLazy {
 
     private final HashSet exception1st = new HashSet<>();
 
+    @Setter(onMethod_ = { @Autowired })
+    protected TinyMailService tinyMailService;
+
+    /**
+     * Testing::
+     * Requested bean is currently in creation:
+     * Is there an unresolvable circular reference?
+     */
+    public void send(TinyMail mail) {
+        tinyMailService.send(mail, true);
+    }
+
     @Override
     public @Nullable Edit lazyEdit(@Nullable String para) {
         if (para == null) return null;
diff --git a/wings/silencer/src/main/java/pro/fessional/wings/silencer/spring/help/ApplicationContextHelper.java b/wings/silencer/src/main/java/pro/fessional/wings/silencer/spring/help/ApplicationContextHelper.java
index f8c96f8a7..2e668152c 100644
--- a/wings/silencer/src/main/java/pro/fessional/wings/silencer/spring/help/ApplicationContextHelper.java
+++ b/wings/silencer/src/main/java/pro/fessional/wings/silencer/spring/help/ApplicationContextHelper.java
@@ -5,6 +5,7 @@
 import org.springframework.beans.factory.ObjectProvider;
 import org.springframework.boot.context.properties.source.ConfigurationPropertySources;
 import org.springframework.context.ConfigurableApplicationContext;
+import org.springframework.core.ResolvableType;
 import org.springframework.core.env.CompositePropertySource;
 import org.springframework.core.env.ConfigurableEnvironment;
 import org.springframework.core.env.EnumerablePropertySource;
@@ -14,6 +15,7 @@
 import pro.fessional.mirana.best.Param;
 
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.LinkedHashMap;
 import java.util.LinkedHashSet;
 import java.util.List;
@@ -182,6 +184,11 @@ public static  ObjectProvider getBeanProvider(Class type) {
         return context.getBeanProvider(type);
     }
 
+    @NotNull
+    public static  ObjectProvider getBeanProvider(ResolvableType type) {
+        return context.getBeanProvider(type);
+    }
+
     @NotNull
     public static  SingletonSupplier getSingletonSupplier(Class type) {
         return SingletonSupplier.of(() -> context.getBean(type));
@@ -192,6 +199,44 @@ public static  SingletonSupplier getSingletonSupplier(Class type, Suppl
         return SingletonSupplier.of(() -> context.getBeanProvider(type).getIfAvailable(elze));
     }
 
+    /**
+     * SingletonSupplier of ordered bean list
+     */
+    @NotNull
+    public static  SingletonSupplier> getSingletonSupplierOfList(Class type) {
+        return getSingletonSupplierOfList(type, Collections::emptyList);
+    }
+
+    /**
+     * SingletonSupplier of ordered bean list, elze if empty
+     */
+    @NotNull
+    public static  SingletonSupplier> getSingletonSupplierOfList(Class type, Supplier> elze) {
+        return SingletonSupplier.of(() -> {
+            var lst = context.getBeanProvider(type).orderedStream().toList();
+            return lst.isEmpty() ? elze.get() : lst;
+        });
+    }
+
+    /**
+     * SingletonSupplier of bean and its name map
+     */
+    @NotNull
+    public static  SingletonSupplier> getSingletonSupplierOfMap(Class type) {
+        return getSingletonSupplierOfMap(type, Collections::emptyMap);
+    }
+
+    /**
+     * SingletonSupplier of bean and its name map, elze if empty
+     */
+    @NotNull
+    public static  SingletonSupplier> getSingletonSupplierOfMap(Class type, Supplier> elze) {
+        return SingletonSupplier.of(() -> {
+            var map = context.getBeansOfType(type);
+            return map.isEmpty() ? elze.get() : map;
+        });
+    }
+
     public static String getMessage(String code, Locale locale, Object... arg) {
         return context.getMessage(code, arg, locale);
     }

From 30c0800d46cfb18908aca2523994bee2bd5c0d9a Mon Sep 17 00:00:00 2001
From: trydofor 
Date: Thu, 18 Jul 2024 14:42:40 +0800
Subject: [PATCH 25/51] =?UTF-8?q?=F0=9F=92=9A=20get=20rid=20of=20Qodana=20?=
 =?UTF-8?q?warning?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../service/impl/TinyMailServiceImpl.java     | 29 +++++---
 .../faceless/flywave/SchemaJournalManager.kt  | 72 ++++++++-----------
 .../flywave/impl/DefaultRevisionManager.kt    |  4 +-
 .../slardar/cache/cache2k/NullsCache2k.java   |  3 +-
 4 files changed, 55 insertions(+), 53 deletions(-)

diff --git a/radiant/tiny-mail/src/main/java/pro/fessional/wings/tiny/mail/service/impl/TinyMailServiceImpl.java b/radiant/tiny-mail/src/main/java/pro/fessional/wings/tiny/mail/service/impl/TinyMailServiceImpl.java
index 25d0b5ce7..089268a7b 100644
--- a/radiant/tiny-mail/src/main/java/pro/fessional/wings/tiny/mail/service/impl/TinyMailServiceImpl.java
+++ b/radiant/tiny-mail/src/main/java/pro/fessional/wings/tiny/mail/service/impl/TinyMailServiceImpl.java
@@ -459,6 +459,16 @@ protected WinMailSender saveMailSender(@NotNull TinyMailConfig config, @NotNull
         return po;
     }
 
+    @Nullable
+    protected TinyMailLazy findLazyBean(String name) {
+        return lazyBeanHolder.obtain().get(name);
+    }
+
+    @NotNull
+    protected List findStatusHook() {
+        return statusHookHolder.obtain();
+    }
+
     /**
      * should skip sending, condition not match
      */
@@ -502,9 +512,10 @@ protected boolean notMatchProp(@NotNull WinMailSender po) {
         }
 
         if (po.getMailText() == null) {
-            var bean = lazyBeanHolder.obtain().get(po.getLazyBean());
+            String bn = po.getLazyBean();
+            var bean = findLazyBean(bn);
             if (bean == null) {
-                log.error("stop lazy tiny-mail, not found bean={}, id={}", bean, po.getId());
+                log.error("stop lazy tiny-mail, not found bean={}, id={}", bn, po.getId());
                 return true;
             }
         }
@@ -632,7 +643,7 @@ else if (exception instanceof MailParseException || exception instanceof Messagi
 
             boolean hookStop = false;
 
-            for (StatusHook sh : statusHookHolder.obtain()) {
+            for (StatusHook sh : findStatusHook()) {
                 try {
                     if (sh.stop(po, cost, exception)) {
                         hookStop = true;
@@ -679,7 +690,7 @@ protected void editLazyMail(@NotNull WinMailSender po, @NotNull @Param.Out TinyM
 
         final Long id = po.getId();
         final String bn = po.getLazyBean();
-        var bean = lazyBeanHolder.obtain().get(bn);
+        var bean = findLazyBean(bn);
         if (bean == null) {
             throw new MailStopException("tiny-mail lazy-edit, not-found bean=" + bn + ", id=" + id);
         }
@@ -776,11 +787,11 @@ private long doSyncSend(@NotNull WinMailSender po, @NotNull TinyMailMessage mess
             }
         }
 
-        if (exception == null) return Success;
-
-        // rethrow exception
-        if (exception instanceof RuntimeException) {
-            throw (RuntimeException) exception;
+        if (exception == null) {
+            return Success;
+        }
+        else if (exception instanceof RuntimeException re) {
+            throw re; // rethrow exception
         }
         else {
             throw new MailSendException("failed tiny-mail, id=" + id + ", subject=" + po.getMailSubj(), exception);
diff --git a/wings/faceless-flywave/src/main/kotlin/pro/fessional/wings/faceless/flywave/SchemaJournalManager.kt b/wings/faceless-flywave/src/main/kotlin/pro/fessional/wings/faceless/flywave/SchemaJournalManager.kt
index 6d3cc0b64..5c05625c6 100644
--- a/wings/faceless-flywave/src/main/kotlin/pro/fessional/wings/faceless/flywave/SchemaJournalManager.kt
+++ b/wings/faceless-flywave/src/main/kotlin/pro/fessional/wings/faceless/flywave/SchemaJournalManager.kt
@@ -327,8 +327,15 @@ class SchemaJournalManager(
         val isInsert = "insert".equals(event, true)
         val isUpdate = "update".equals(event, true)
         val isDelete = "delete".equals(event, true)
-        val selectSql = when {
-            isInsert -> {
+
+        val logDate = if (enable) {
+            "NOW(3)"
+        } else {
+            "'1000-01-01 00:00:00.000'"
+        }
+
+        val (selectSql, updateSql) = when {
+            isInsert -> Pair(
                 """
                 SELECT
                     ddl_instbl ddl_tbl,
@@ -336,9 +343,16 @@ class SchemaJournalManager(
                     log_insert apply_dt
                 FROM $schemaJournalTable
                 WHERE table_name = ?
+                """.trimIndent(),
+                """
+                UPDATE $schemaJournalTable SET
+                    log_insert = $logDate,
+                    commit_id = ?
+                WHERE table_name = ?
                 """.trimIndent()
-            }
-            isUpdate -> {
+            )
+
+            isUpdate -> Pair(
                 """
                 SELECT
                     ddl_updtbl ddl_tbl,
@@ -346,9 +360,16 @@ class SchemaJournalManager(
                     log_update apply_dt
                 FROM $schemaJournalTable
                 WHERE table_name = ?
+                """.trimIndent(),
+                """
+                UPDATE $schemaJournalTable SET
+                    log_update = $logDate,
+                    commit_id = ?
+                WHERE table_name = ?
                 """.trimIndent()
-            }
-            isDelete -> {
+            )
+
+            isDelete -> Pair(
                 """
                 SELECT
                     ddl_deltbl ddl_tbl,
@@ -356,47 +377,16 @@ class SchemaJournalManager(
                     log_delete apply_dt
                 FROM $schemaJournalTable
                 WHERE table_name = ?
-                """.trimIndent()
-            }
-            else -> {
-                throw RuntimeException("unsupported event $event")
-            }
-        }
-
-        val logDate = if (enable) {
-            "NOW(3)"
-        } else {
-            "'1000-01-01 00:00:00.000'"
-        }
-
-        val updateSql = when {
-            isInsert -> {
-                """
-                UPDATE $schemaJournalTable SET
-                    log_insert = $logDate,
-                    commit_id = ?
-                WHERE table_name = ?
-                """.trimIndent()
-            }
-            isUpdate -> {
-                """
-                UPDATE $schemaJournalTable SET
-                    log_update = $logDate,
-                    commit_id = ?
-                WHERE table_name = ?
-                """.trimIndent()
-            }
-            isDelete -> {
+                """.trimIndent(),
                 """
                 UPDATE $schemaJournalTable SET
                     log_delete = $logDate,
                     commit_id = ?
                 WHERE table_name = ?
                 """.trimIndent()
-            }
-            else -> {
-                throw RuntimeException("unsupported event $event")
-            }
+            )
+
+            else -> throw RuntimeException("unsupported event $event")
         }
 
         val model = HashMap()
diff --git a/wings/faceless-flywave/src/main/kotlin/pro/fessional/wings/faceless/flywave/impl/DefaultRevisionManager.kt b/wings/faceless-flywave/src/main/kotlin/pro/fessional/wings/faceless/flywave/impl/DefaultRevisionManager.kt
index 3e77999d3..2a1b6d93b 100644
--- a/wings/faceless-flywave/src/main/kotlin/pro/fessional/wings/faceless/flywave/impl/DefaultRevisionManager.kt
+++ b/wings/faceless-flywave/src/main/kotlin/pro/fessional/wings/faceless/flywave/impl/DefaultRevisionManager.kt
@@ -369,12 +369,12 @@ class DefaultRevisionManager(
             val msgAly = applyMessage(reviSql.second)
 
             if (isUpto && !notAppd) {
-                interactive.log(ERROR, here, "skip, $msgAly upto, need force to undo first, revi=$revision, isUpto=$isUpto, db=$plainName")
+                interactive.log(ERROR, here, "skip, $msgAly upto, need force to undo first, revi=$revision, isUpto=true, db=$plainName")
                 continue
             }
 
             if (!isUpto && notAppd) {
-                interactive.log(ERROR, here, "skip, not $msgAly undo, revi=$revision, isUpto=$isUpto, db=$plainName")
+                interactive.log(ERROR, here, "skip, not $msgAly undo, revi=$revision, isUpto=false, db=$plainName")
                 continue
             }
 
diff --git a/wings/slardar/src/main/java/pro/fessional/wings/slardar/cache/cache2k/NullsCache2k.java b/wings/slardar/src/main/java/pro/fessional/wings/slardar/cache/cache2k/NullsCache2k.java
index bce2be1bd..80b4a93f6 100644
--- a/wings/slardar/src/main/java/pro/fessional/wings/slardar/cache/cache2k/NullsCache2k.java
+++ b/wings/slardar/src/main/java/pro/fessional/wings/slardar/cache/cache2k/NullsCache2k.java
@@ -49,9 +49,10 @@ public  T get(@NotNull Object key, @NotNull Callable valueLoader) {
         return value;
     }
 
-    @SuppressWarnings("NullableProblems")
+    @SuppressWarnings({ "NullableProblems", "ConstantConditions" })
     @Override
     public void put(@NotNull Object key, Object value) {
+        // SuppressWarnings Condition `value == null` is always `false`
         if (value == null) {
             if (nulls != null) {
                 nulls.put(key, Boolean.TRUE);

From a32c3a283880b614c180ce3d19bb0c22af9b3eb9 Mon Sep 17 00:00:00 2001
From: trydofor 
Date: Fri, 19 Jul 2024 18:03:54 +0800
Subject: [PATCH 26/51] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20change=20ApiAuth=20s?=
 =?UTF-8?q?ignature,=20compatible=20to=20session=20level=20#274?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 observe/docs                                  |   2 +-
 .../api/AbstractApiAuthController.java        | 179 +++++++++--------
 .../bean/WarlockOauthTicketConfiguration.java |   8 +-
 .../spring/prop/WarlockApiAuthProp.java       |   9 -
 .../wings-warlock-apiauth-77.properties       |   3 -
 .../wings-warlock-ticket-77.properties        |   2 +
 .../app/controller/TestToyApiController.java  |  43 ++--
 .../controller/api/ApiAuthControllerTest.java | 189 ++++++++++--------
 .../controller/api/OkHttpTokenizeTest.java    |   6 +-
 9 files changed, 236 insertions(+), 205 deletions(-)

diff --git a/observe/docs b/observe/docs
index 2f1f881be..e50479062 160000
--- a/observe/docs
+++ b/observe/docs
@@ -1 +1 @@
-Subproject commit 2f1f881be0c8e67207eea41c5818a1fb5801a89f
+Subproject commit e5047906276d1422188d9ac445a6f40124aea0a5
diff --git a/wings/warlock-shadow/src/main/java/pro/fessional/wings/warlock/controller/api/AbstractApiAuthController.java b/wings/warlock-shadow/src/main/java/pro/fessional/wings/warlock/controller/api/AbstractApiAuthController.java
index 4e83112c1..b0227cb33 100644
--- a/wings/warlock-shadow/src/main/java/pro/fessional/wings/warlock/controller/api/AbstractApiAuthController.java
+++ b/wings/warlock-shadow/src/main/java/pro/fessional/wings/warlock/controller/api/AbstractApiAuthController.java
@@ -4,7 +4,6 @@
 import jakarta.servlet.http.HttpServletResponse;
 import jakarta.servlet.http.Part;
 import lombok.Data;
-import lombok.Getter;
 import lombok.Setter;
 import lombok.SneakyThrows;
 import org.jetbrains.annotations.NotNull;
@@ -19,7 +18,6 @@
 import pro.fessional.mirana.io.InputStreams;
 import pro.fessional.mirana.text.FormatUtil;
 import pro.fessional.wings.slardar.constants.SlardarServletConst;
-import pro.fessional.wings.slardar.context.Now;
 import pro.fessional.wings.slardar.context.TerminalContext;
 import pro.fessional.wings.slardar.context.TerminalContext.Context;
 import pro.fessional.wings.slardar.context.TerminalInterceptor;
@@ -59,12 +57,6 @@ public abstract class AbstractApiAuthController {
     public static final int SHA1_LEN = MdHelp.LEN_SHA1_HEX;
     public static final int HMAC_LEN = 64;
 
-    /**
-     * Whether it is compatible mode (send clientId directly), or only the ticket mode.
-     */
-    @Setter @Getter
-    private boolean compatible = true;
-
     @Setter(onMethod_ = { @Autowired })
     protected WarlockApiAuthProp apiAuthProp;
 
@@ -75,22 +67,44 @@ public abstract class AbstractApiAuthController {
     protected TerminalInterceptor terminalInterceptor;
 
     /**
-     * To annotate `@RequestMapping`, Need subclass Override
+     * annotate `@RequestMapping` as api entry to invoke super.requestMapping with ticket, signed
+     *
+     * @see #requestMapping(HttpServletRequest, HttpServletResponse, boolean, boolean)
      */
     public void requestMapping(@NotNull HttpServletRequest request, @NotNull HttpServletResponse response) {
+        requestMapping(request, response, true, true);
+    }
+
+    /**
+     * After passing validate, this method performs business logic.
+     * `true` means it has been processed and can response,
+     * `false` means it has not been processed.
+     */
+    public abstract boolean handle(@NotNull HttpServletRequest request, @NotNull ApiEntity entity) throws IOException;
+
+    /**
+     * called by subclass as API entry
+     *
+     * @param request  request from client
+     * @param response response to client
+     * @param ticket   clientId is ticket format, otherwise is simple key
+     * @param signed   have signature and digest check
+     */
+    protected void requestMapping(@NotNull HttpServletRequest request, @NotNull HttpServletResponse response, boolean ticket, boolean signed) {
         //
         Pass pass = null;
         final String cid = request.getHeader(apiAuthProp.getClientHeader());
         if (cid != null) {
-            final Term term = ticketService.decode(cid);
-            if (term != null) {
-                pass = ticketService.findPass(term.getClientId());
-            }
-            else { // invalid token or compatible mode
-                if (compatible) {
-                    pass = ticketService.findPass(cid);
+            if (ticket) {
+                final Term term = ticketService.decode(cid);
+                if (term != null) {
+                    pass = ticketService.findPass(term.getClientId());
                 }
             }
+            // ticket compatible simple key
+            if(pass == null) {
+                pass = ticketService.findPass(cid);
+            }
         }
 
         if (pass == null) {
@@ -99,7 +113,7 @@ public void requestMapping(@NotNull HttpServletRequest request, @NotNull HttpSer
         }
 
         //
-        final ApiEntity entity = validate(request, pass.getSecret());
+        final ApiEntity entity = validate(request, pass, signed);
         if (entity.error != null) {
             responseText(response, apiAuthProp.getErrorSignature(), entity.error);
             return;
@@ -112,7 +126,7 @@ public void requestMapping(@NotNull HttpServletRequest request, @NotNull HttpSer
         try {
             entity.terminal = ctx;
             if (handle(request, entity)) {
-                responseBody(response, entity, pass);
+                responseBody(response, entity, pass, signed);
                 handled = true;
             }
         }
@@ -129,67 +143,78 @@ public void requestMapping(@NotNull HttpServletRequest request, @NotNull HttpSer
     }
 
     @SneakyThrows
-    protected void responseBody(@NotNull HttpServletResponse response, @NotNull ApiEntity entity, @NotNull Pass pass) {
+    protected void responseBody(@NotNull HttpServletResponse response, @NotNull ApiEntity entity, @NotNull Pass pass, boolean signed) {
         // Auth-Client
         response.setHeader(apiAuthProp.getClientHeader(), pass.getClient());
 
         // Auth-Timestamp
-        final String timestamp = entity.timestamp.isEmpty() ? String.valueOf(Now.millis()) : entity.timestamp;
-        response.setHeader(apiAuthProp.getTimestampHeader(), timestamp);
+        final String timestamp = entity.timestamp;
+        if(!timestamp.isEmpty()) {
+            response.setHeader(apiAuthProp.getTimestampHeader(), timestamp);
+        }
 
         // Other Headers
         for (Map.Entry en : entity.resHead.entrySet()) {
             response.setHeader(en.getKey(), en.getValue());
         }
 
-        final int sgnLen = entity.signature.length();
-        final String secret = pass.getSecret();
         // response json
         if (entity.resFile == null) {
             final String body = entity.resText;
-            final String data = body + secret + timestamp;
-            // Auth-Signature
-            String signature = signature(data, sgnLen, secret);
-            if (!signature.isEmpty()) {
-                response.setHeader(apiAuthProp.getSignatureHeader(), signature);
+
+            if (signed) {
+                final String secret = pass.getSecret();
+                final String data = body + secret + timestamp;
+                // Auth-Signature
+                String signature = signature(data, entity.signature.length(), secret);
+                if (!signature.isEmpty()) {
+                    response.setHeader(apiAuthProp.getSignatureHeader(), signature);
+                }
             }
+
             // Content-Type
             response.setContentType(APPLICATION_JSON_VALUE);
             responseText(response, HttpStatus.OK.value(), body);
         }
         else {
             // response file
-            final int size = entity.resFile.available();
-            int sumLen = 0; // Digest Algorithm
-            if (size < apiAuthProp.getDigestMax().toBytes()) {
-                for (Map.Entry en : entity.reqPara.entrySet()) {
-                    if (en.getKey().endsWith(".sum")) {
-                        sumLen = en.getValue().length();
-                        break;
-                    }
-                }
-                if (sumLen == 0) {
-                    sumLen = entity.digest.length();
-                }
-            }
-
-            final String data;
             final InputStream body;
-            if (sumLen == MD5_LEN || sumLen == SHA1_LEN) {
-                body = new CircleInputStream(entity.resFile);
-                final String digest = digest(body, sumLen);
-                data = digest + secret + timestamp;
-                response.setHeader(apiAuthProp.getDigestHeader(), digest);
-            }
-            else {
+            if (!signed) {
                 body = entity.resFile;
-                data = secret + timestamp;
             }
+            else {
+                final int size = entity.resFile.available();
+                int sumLen = 0; // Digest Algorithm
+                if (size < apiAuthProp.getDigestMax().toBytes()) {
+                    for (Map.Entry en : entity.reqPara.entrySet()) {
+                        if (en.getKey().endsWith(".sum")) {
+                            sumLen = en.getValue().length();
+                            break;
+                        }
+                    }
+                    if (sumLen == 0) {
+                        sumLen = entity.digest.length();
+                    }
+                }
 
-            // Auth-Signature
-            String signature = signature(data, sgnLen, secret);
-            if (!signature.isEmpty()) {
-                response.setHeader(apiAuthProp.getSignatureHeader(), signature);
+                final String data;
+                final String secret = pass.getSecret();
+                if (sumLen == MD5_LEN || sumLen == SHA1_LEN) {
+                    body = new CircleInputStream(entity.resFile);
+                    final String digest = digest(body, sumLen);
+                    data = digest + secret + timestamp;
+                    response.setHeader(apiAuthProp.getDigestHeader(), digest);
+                }
+                else {
+                    body = entity.resFile;
+                    data = secret + timestamp;
+                }
+
+                // Auth-Signature
+                String signature = signature(data, entity.signature.length(), secret);
+                if (!signature.isEmpty()) {
+                    response.setHeader(apiAuthProp.getSignatureHeader(), signature);
+                }
             }
 
             // Content-Type
@@ -222,24 +247,26 @@ protected void responseText(@NotNull HttpServletResponse response, int status, @
 
     @NotNull
     @SneakyThrows
-    public ApiEntity parse(@NotNull HttpServletRequest request, boolean mustSign) {
+    protected ApiEntity parse(@NotNull HttpServletRequest request, boolean signed) {
         final ApiEntity entity = new ApiEntity();
-        final String sgn = request.getHeader(apiAuthProp.getSignatureHeader());
-        if (sgn == null || sgn.isEmpty()) {
-            if (mustSign) {
+
+        if (signed) {
+            final String sgn = request.getHeader(apiAuthProp.getSignatureHeader());
+            if (sgn == null || sgn.isEmpty()) {
                 entity.error = ApiError.SignatureMissing;
                 return entity;
             }
-        }
-        else {
-            entity.signature = sgn;
-        }
+            else {
+                entity.signature = sgn;
+            }
 
-        final String sum = request.getHeader(apiAuthProp.getDigestHeader());
-        if (sum != null) {
-            entity.digest = sum;
+            final String sum = request.getHeader(apiAuthProp.getDigestHeader());
+            if (sum != null) {
+                entity.digest = sum;
+            }
         }
 
+        // identify request and sign
         final String tms = request.getHeader(apiAuthProp.getTimestampHeader());
         if (tms != null) {
             entity.timestamp = tms;
@@ -293,14 +320,16 @@ else if (vls.length == 1) {
     /**
      * Validate an Api request and returns Entity if it does not fail (successful or unvalidated),
      * otherwise it returns null.
+     * check digest if secret is not empty
      */
     @SneakyThrows
     @NotNull
-    public ApiEntity validate(@NotNull HttpServletRequest request, @NotNull String secret) {
-        final boolean mustSign = apiAuthProp.isMustSignature();
-        final ApiEntity entity = parse(request, mustSign);
-        if (entity.error != null) return entity;
+    protected ApiEntity validate(@NotNull HttpServletRequest request, @NotNull Pass pass, boolean signed) {
+        final ApiEntity entity = parse(request, signed);
 
+        if (!signed || entity.error != null) return entity; // not signed or error
+
+        final String secret = Null.notNull(pass.getSecret());
         final String para = FormatUtil.sortParam(entity.reqPara);
         //
         final String data;
@@ -334,13 +363,12 @@ else if (cpt != pt) {
 
         // validate signature
         final String sign = signature(data, entity.signature.length(), secret);
-        if (mustSign && !sign.equalsIgnoreCase(entity.signature)) {
+        if (!sign.equalsIgnoreCase(entity.signature)) {
             entity.error = ApiError.SignatureInvalid;
         }
         return entity;
     }
 
-
     @SneakyThrows
     private Part checkDigest(String sum, Part pt) {
         if (sum == null || sum.isEmpty()) return pt;
@@ -401,13 +429,6 @@ else if (len == HMAC_LEN) {
         }
     }
 
-    /**
-     * After passing validate, this method performs business logic.
-     * `true` means it has been processed and can response,
-     * `false` means it has not been processed.
-     */
-    public abstract boolean handle(@NotNull HttpServletRequest request, @NotNull ApiEntity entity) throws IOException;
-
     public enum ApiError {
         SignatureMissing,
         SignatureInvalid,
diff --git a/wings/warlock-shadow/src/main/java/pro/fessional/wings/warlock/spring/bean/WarlockOauthTicketConfiguration.java b/wings/warlock-shadow/src/main/java/pro/fessional/wings/warlock/spring/bean/WarlockOauthTicketConfiguration.java
index b4c7378f2..a3cd282df 100644
--- a/wings/warlock-shadow/src/main/java/pro/fessional/wings/warlock/spring/bean/WarlockOauthTicketConfiguration.java
+++ b/wings/warlock-shadow/src/main/java/pro/fessional/wings/warlock/spring/bean/WarlockOauthTicketConfiguration.java
@@ -54,13 +54,17 @@ public SimpleTicketServiceImpl warlockTicketService(WarlockTicketProp warlockTic
 
         for (Map.Entry en : warlockTicketProp.getClient().entrySet()) {
             final WarlockTicketService.Pass pass = en.getValue();
-            final String client = en.getKey();
+            String client = pass.getClient();
+            if (client == null || client.isBlank()) {
+                client = en.getKey();
+                pass.setClient(client);
+            }
+
             final String secret = pass.getSecret();
             if (secret == null || secret.isEmpty()) {
                 log.warn("WarlockShadow spring-conf skip warlockTicketService.client=" + client + " for empty secret");
                 continue;
             }
-            pass.setClient(client);
             log.info("WarlockShadow spring-conf warlockTicketService.client=" + client);
             bean.addClient(pass);
         }
diff --git a/wings/warlock-shadow/src/main/java/pro/fessional/wings/warlock/spring/prop/WarlockApiAuthProp.java b/wings/warlock-shadow/src/main/java/pro/fessional/wings/warlock/spring/prop/WarlockApiAuthProp.java
index 9cbb9d2c6..4021ef445 100644
--- a/wings/warlock-shadow/src/main/java/pro/fessional/wings/warlock/spring/prop/WarlockApiAuthProp.java
+++ b/wings/warlock-shadow/src/main/java/pro/fessional/wings/warlock/spring/prop/WarlockApiAuthProp.java
@@ -61,15 +61,6 @@ public class WarlockApiAuthProp {
     private DataSize digestMax = DataSize.ofMegabytes(10);
     public static final String Key$digestMax = Key + ".digest-max";
 
-    /**
-     * whether it must be signed, compatible with the old api.
-     *
-     * @see #Key$mustSignature
-     */
-    private boolean mustSignature = true;
-    public static final String Key$mustSignature = Key + ".must-signature";
-
-
     /**
      * if there is both a file and a json,
      * use this name for the json body and submit it as a File.
diff --git a/wings/warlock-shadow/src/main/resources/wings-conf/wings-warlock-apiauth-77.properties b/wings/warlock-shadow/src/main/resources/wings-conf/wings-warlock-apiauth-77.properties
index c6d5a2d40..412967915 100644
--- a/wings/warlock-shadow/src/main/resources/wings-conf/wings-warlock-apiauth-77.properties
+++ b/wings/warlock-shadow/src/main/resources/wings-conf/wings-warlock-apiauth-77.properties
@@ -13,9 +13,6 @@ wings.warlock.apiauth.digest-header=Auth-Digest
 ## no digest over this size, default 5M.
 wings.warlock.apiauth.digest-max=5MB
 
-## whether it must be signed, compatible with the old api.
-wings.warlock.apiauth.must-signature=true
-
 ## if there is both a file and a json,
 ## use this name for the json body and submit it as a File.
 wings.warlock.apiauth.file-json-body=FILE_JSON_BODY
diff --git a/wings/warlock-shadow/src/main/resources/wings-conf/wings-warlock-ticket-77.properties b/wings/warlock-shadow/src/main/resources/wings-conf/wings-warlock-ticket-77.properties
index 847330e3b..9f3fed538 100644
--- a/wings/warlock-shadow/src/main/resources/wings-conf/wings-warlock-ticket-77.properties
+++ b/wings/warlock-shadow/src/main/resources/wings-conf/wings-warlock-ticket-77.properties
@@ -11,6 +11,8 @@ wings.warlock.ticket.token-max=5
 
 ## static config of client login.
 #wings.warlock.ticket.client[wings-trydofor].user-id=79
+## recommend to use key as client
+##wings.warlock.ticket.client[wings-trydofor].client=wings-trydofor
 #wings.warlock.ticket.client[wings-trydofor].secret=wings-trydofor-secret
 #wings.warlock.ticket.client[wings-trydofor].hosts=localhost
 #wings.warlock.ticket.client[wings-trydofor].scopes=api1, api2
diff --git a/wings/warlock-shadow/src/test/java/pro/fessional/wings/warlock/app/controller/TestToyApiController.java b/wings/warlock-shadow/src/test/java/pro/fessional/wings/warlock/app/controller/TestToyApiController.java
index ca400da22..d84833671 100644
--- a/wings/warlock-shadow/src/test/java/pro/fessional/wings/warlock/app/controller/TestToyApiController.java
+++ b/wings/warlock-shadow/src/test/java/pro/fessional/wings/warlock/app/controller/TestToyApiController.java
@@ -22,6 +22,7 @@
 import pro.fessional.wings.slardar.spring.prop.SlardarSessionProp;
 import pro.fessional.wings.warlock.app.service.TestWatchingService;
 import pro.fessional.wings.warlock.controller.api.AbstractApiAuthController;
+import pro.fessional.wings.warlock.spring.prop.WarlockApiAuthProp;
 
 import java.io.ByteArrayInputStream;
 import java.io.IOException;
@@ -40,29 +41,31 @@
 @Slf4j
 public class TestToyApiController extends AbstractApiAuthController {
 
-    @Setter(onMethod_ = {@Autowired})
+    @Setter(onMethod_ = { @Autowired })
     protected TestWatchingService testWatchingService;
-    @Setter(onMethod_ = {@Autowired})
+    @Setter(onMethod_ = { @Autowired })
     private SlardarSessionProp slardarSessionProp;
+    @Setter(onMethod_ = { @Autowired })
+    protected WarlockApiAuthProp warlockApiAuthProp;
 
     @PostMapping(value = "/api/test.json", consumes = MediaType.APPLICATION_JSON_VALUE)
     public ResponseEntity testJsonApi(
-            @RequestHeader("Auth-Client") String client,
-            @RequestHeader("Auth-Signature") String signature,
-            @RequestHeader(value = "Auth-Timestamp", required = false) Long timestamp,
-            @RequestParam Map para,
-            @RequestBody String body
+        @RequestHeader("Auth-Client") String client,
+        @RequestHeader("Auth-Signature") String signature,
+        @RequestHeader(value = "Auth-Timestamp", required = false) Long timestamp,
+        @RequestParam Map para,
+        @RequestBody String body
     ) {
         return ResponseEntity.ok("ok");
     }
 
     @PostMapping(value = "/api/test.json", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
     public ResponseEntity testFileApi(
-            @RequestHeader("Auth-Client") String client,
-            @RequestHeader("Auth-Signature") String signature,
-            @RequestHeader(value = "Auth-Timestamp", required = false) Long timestamp,
-            @RequestParam Map para,
-            @RequestParam Map files
+        @RequestHeader("Auth-Client") String client,
+        @RequestHeader("Auth-Signature") String signature,
+        @RequestHeader(value = "Auth-Timestamp", required = false) Long timestamp,
+        @RequestParam Map para,
+        @RequestParam Map files
     ) {
         return ResponseEntity.ok("ok");
     }
@@ -95,13 +98,6 @@ public ResponseEntity testFormLogin(@NotNull HttpServletRequest request)
 
     public static final String ApiSimple = "/api/simple.json";
 
-    @Override
-    @PostMapping(ApiSimple)
-    public void requestMapping(@NotNull HttpServletRequest request, @NotNull HttpServletResponse response) {
-        log.info("ApiRequestMapping...");
-        super.requestMapping(request, response);
-    }
-
     public static final String ReqJsonBody = "ReqJsonBody";
     public static final String ReqFileKey = "ReqFileKey";
     public static final String ReqFileName = "ReqFileName";
@@ -118,6 +114,15 @@ public void requestMapping(@NotNull HttpServletRequest request, @NotNull HttpSer
     public static final String ModJsonJson = "ModJsonJson";
     public static final String ModFileJson = "ModFileJson";
 
+    @Override
+    @PostMapping(ApiSimple)
+    public void requestMapping(@NotNull HttpServletRequest request, @NotNull HttpServletResponse response) {
+        log.info("ApiRequestMapping...");
+        boolean ticket = "true".equalsIgnoreCase(request.getHeader("ticket"));
+        boolean signed = "true".equalsIgnoreCase(request.getHeader("signed"));
+        super.requestMapping(request, response, ticket, signed);
+    }
+
     @Override
     public boolean handle(@NotNull HttpServletRequest request, @NotNull ApiEntity entity) throws IOException {
         final HashMap head = new HashMap<>();
diff --git a/wings/warlock-shadow/src/test/java/pro/fessional/wings/warlock/controller/api/ApiAuthControllerTest.java b/wings/warlock-shadow/src/test/java/pro/fessional/wings/warlock/controller/api/ApiAuthControllerTest.java
index 28bfc1387..900851bf5 100644
--- a/wings/warlock-shadow/src/test/java/pro/fessional/wings/warlock/controller/api/ApiAuthControllerTest.java
+++ b/wings/warlock-shadow/src/test/java/pro/fessional/wings/warlock/controller/api/ApiAuthControllerTest.java
@@ -19,6 +19,7 @@
 import pro.fessional.mirana.bits.MdHelp;
 import pro.fessional.mirana.data.Null;
 import pro.fessional.mirana.text.FormatUtil;
+import pro.fessional.wings.faceless.convention.EmptySugar;
 import pro.fessional.wings.slardar.context.Now;
 import pro.fessional.wings.slardar.fastjson.FastJsonHelper;
 import pro.fessional.wings.slardar.httprest.okhttp.OkHttpClientHelper;
@@ -56,24 +57,23 @@
  * @since 2022-11-16
  */
 @SpringBootTest(
-        webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT,
-        properties = {
-                "wings.warlock.apiauth.must-signature=false",
-                "wings.enabled.slardar.restream=false",
-        })
+    webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT,
+    properties = {
+        "wings.enabled.slardar.restream=false",
+    })
 @Slf4j
 class ApiAuthControllerTest {
 
-    @Setter(onMethod_ = {@Autowired})
+    @Setter(onMethod_ = { @Autowired })
     private WarlockApiAuthProp apiAuthProp;
 
-    @Setter(onMethod_ = {@Autowired})
+    @Setter(onMethod_ = { @Autowired })
     private WarlockUrlmapProp urlmapProp;
 
-    @Setter(onMethod_ = {@Value("${local.server.port}")})
+    @Setter(onMethod_ = { @Value("${local.server.port}") })
     private int apiPort;
 
-    @Setter(onMethod_ = {@Autowired})
+    @Setter(onMethod_ = { @Autowired })
     private OkHttpClient okHttpClient;
 
     private final String client = "wings-trydofor";
@@ -93,10 +93,10 @@ class ApiAuthControllerTest {
 
     private HttpUrl.Builder urlBuilder() {
         return new HttpUrl.Builder()
-                .scheme("http")
-                .host("localhost")
-                .port(apiPort)
-                .encodedPath(ApiSimple);
+            .scheme("http")
+            .host("localhost")
+            .port(apiPort)
+            .encodedPath(ApiSimple);
     }
 
     private String accessToken = null;
@@ -104,33 +104,33 @@ private HttpUrl.Builder urlBuilder() {
     private String getToken() {
         if (accessToken != null) return accessToken;
         final HttpUrl.Builder u1 = new HttpUrl.Builder()
-                .scheme("http")
-                .host("localhost")
-                .port(apiPort)
-                .encodedPath(urlmapProp.getOauthAuthorize())
-                .addQueryParameter(WarlockOauthService.ClientId, client);
+            .scheme("http")
+            .host("localhost")
+            .port(apiPort)
+            .encodedPath(urlmapProp.getOauthAuthorize())
+            .addQueryParameter(WarlockOauthService.ClientId, client);
         final String t1 = OkHttpClientHelper.getText(okHttpClient, u1.toString());
         final String code = FastJsonHelper.object(t1).getString(WarlockOauthService.Code);
 
         final HttpUrl.Builder u2 = new HttpUrl.Builder()
-                .scheme("http")
-                .host("localhost")
-                .port(apiPort)
-                .encodedPath(urlmapProp.getOauthAccessToken())
-                .addQueryParameter(WarlockOauthService.ClientId, client)
-                .addQueryParameter(WarlockOauthService.ClientSecret, secret)
-                .addQueryParameter(WarlockOauthService.Code, code);
+            .scheme("http")
+            .host("localhost")
+            .port(apiPort)
+            .encodedPath(urlmapProp.getOauthAccessToken())
+            .addQueryParameter(WarlockOauthService.ClientId, client)
+            .addQueryParameter(WarlockOauthService.ClientSecret, secret)
+            .addQueryParameter(WarlockOauthService.Code, code);
 
         final String t2 = OkHttpClientHelper.postJson(okHttpClient, u2.toString(), "");
-        accessToken =  FastJsonHelper.object(t2).getString(WarlockOauthService.AccessToken);
+        accessToken = FastJsonHelper.object(t2).getString(WarlockOauthService.AccessToken);
         return accessToken;
     }
 
     @Test
     @TmsLink("C14024")
     public void testJsonJson() throws IOException {
-        String[] clients = {client, getToken()};
-        String[] timestamps = {String.valueOf(Now.millis()), Null.Str};
+        String[] clients = { client, getToken() };
+        String[] timestamps = { String.valueOf(Now.millis()), Null.Str };
         for (String c : clients) {
             for (String t : timestamps) {
                 jsonJson(c, t, md5);
@@ -158,17 +158,19 @@ private void jsonJson(String client, String timestamp, Function
 
         final String para = FormatUtil.sortParam(param);
         final String signature = sumFun == null
-                                 ? Null.Str
-                                 : sumFun.apply(para + jsonBody + secret + timestamp);
-
+            ? Null.Str
+            : sumFun.apply(para + jsonBody + secret + timestamp);
+        final boolean signed = !signature.isEmpty();
         RequestBody body = RequestBody.create(jsonBody, APPLICATION_JSON_VALUE);
         okhttp3.Request request = new okhttp3.Request.Builder()
-                .url(ubd.build())
-                .header(apiAuthProp.getClientHeader(), client)
-                .header(apiAuthProp.getTimestampHeader(), timestamp)
-                .header(apiAuthProp.getSignatureHeader(), signature)
-                .post(body)
-                .build();
+            .url(ubd.build())
+            .header(apiAuthProp.getClientHeader(), client)
+            .header(apiAuthProp.getTimestampHeader(), timestamp)
+            .header(apiAuthProp.getSignatureHeader(), signature)
+            .header("ticket", String.valueOf(client.startsWith("win-")))
+            .header("signed", String.valueOf(signed))
+            .post(body)
+            .build();
 
         final Response r2 = OkHttpClientHelper.execute(okHttpClient, request, false);
         Assertions.assertNotNull(r2);
@@ -179,12 +181,12 @@ private void jsonJson(String client, String timestamp, Function
         final String text = resBody.string();
         Assertions.assertEquals(jsonBody, text);
 
-        final String stmp = r2.header(apiAuthProp.getTimestampHeader());
+        final String stmp = EmptySugar.nullToEmpty(r2.header(apiAuthProp.getTimestampHeader()));
         if (!timestamp.isEmpty()) {
             Assertions.assertEquals(timestamp, stmp);
         }
 
-        if (sumFun != null) {
+        if (signed) {
             final String sign = r2.header(apiAuthProp.getSignatureHeader());
             Assertions.assertNotNull(sign);
             final String data1 = text + secret + stmp;
@@ -201,8 +203,8 @@ private void jsonJson(String client, String timestamp, Function
     @Test
     @TmsLink("C14025")
     public void testFileJson() throws IOException {
-        String[] clients = {client, getToken()};
-        String[] timestamps = {String.valueOf(Now.millis()), Null.Str};
+        String[] clients = { client, getToken() };
+        String[] timestamps = { String.valueOf(Now.millis()), Null.Str };
         for (String c : clients) {
             for (String t : timestamps) {
                 fileJson(c, t, md5, true);
@@ -231,20 +233,23 @@ private void fileJson(String client, String timestamp, Function
 
         final String para = FormatUtil.sortParam(param);
         final String signature = sumFun == null
-                                 ? Null.Str
-                                 : sumFun.apply(para + secret + timestamp);
+            ? Null.Str
+            : sumFun.apply(para + secret + timestamp);
+        final boolean signed = !signature.isEmpty();
 
         MultipartBody.Builder body = new MultipartBody.Builder()
-                .setType(MultipartBody.FORM)
-                .addFormDataPart(fileKey, fileName, RequestBody.create(fileBody.getBytes(UTF_8), MULTIPART_FORM_DATA_VALUE));
+            .setType(MultipartBody.FORM)
+            .addFormDataPart(fileKey, fileName, RequestBody.create(fileBody.getBytes(UTF_8), MULTIPART_FORM_DATA_VALUE));
 
         okhttp3.Request request = new okhttp3.Request.Builder()
-                .url(ubd.build())
-                .header(apiAuthProp.getClientHeader(), client)
-                .header(apiAuthProp.getTimestampHeader(), timestamp)
-                .header(apiAuthProp.getSignatureHeader(), signature)
-                .post(body.build())
-                .build();
+            .url(ubd.build())
+            .header(apiAuthProp.getClientHeader(), client)
+            .header(apiAuthProp.getTimestampHeader(), timestamp)
+            .header(apiAuthProp.getSignatureHeader(), signature)
+            .header("ticket", String.valueOf(client.startsWith("win-")))
+            .header("signed", String.valueOf(signed))
+            .post(body.build())
+            .build();
 
         final Response r2 = OkHttpClientHelper.execute(okHttpClient, request, false);
         Assertions.assertNotNull(r2);
@@ -260,12 +265,12 @@ private void fileJson(String client, String timestamp, Function
         final String text = resBody.string();
         Assertions.assertEquals(jsonBody, text);
 
-        final String stmp = r2.header(apiAuthProp.getTimestampHeader());
+        final String stmp = EmptySugar.nullToEmpty(r2.header(apiAuthProp.getTimestampHeader()));
         if (!timestamp.isEmpty()) {
             Assertions.assertEquals(timestamp, stmp);
         }
 
-        if (sumFun != null) {
+        if (signed) {
             final String sign = r2.header(apiAuthProp.getSignatureHeader());
             Assertions.assertNotNull(sign);
             final String data1 = text + secret + stmp;
@@ -283,8 +288,8 @@ private void fileJson(String client, String timestamp, Function
     @Test
     @TmsLink("C14026")
     public void testJsonFile() throws IOException {
-        String[] clients = {client, getToken()};
-        String[] timestamps = {String.valueOf(Now.millis()), Null.Str};
+        String[] clients = { client, getToken() };
+        String[] timestamps = { String.valueOf(Now.millis()), Null.Str };
         for (String c : clients) {
             for (String t : timestamps) {
                 jsonFile(c, t, md5, true);
@@ -311,18 +316,21 @@ private void jsonFile(String client, String timestamp, Function
 
         final String para = FormatUtil.sortParam(param);
         final String signature = sumFun == null
-                                 ? Null.Str
-                                 : sumFun.apply(para + jsonBody + secret + timestamp);
-        final String dgst = digest && sumFun != null ? sumFun.apply(jsonBody) : Null.Str;
+            ? Null.Str
+            : sumFun.apply(para + jsonBody + secret + timestamp);
+        final boolean signed = !signature.isEmpty();
+        final String dgst = signed && digest ? sumFun.apply(jsonBody) : Null.Str;
         RequestBody body = RequestBody.create(jsonBody, APPLICATION_JSON_VALUE);
         okhttp3.Request request = new okhttp3.Request.Builder()
-                .url(ubd.build())
-                .header(apiAuthProp.getClientHeader(), client)
-                .header(apiAuthProp.getTimestampHeader(), timestamp)
-                .header(apiAuthProp.getSignatureHeader(), signature)
-                .header(apiAuthProp.getDigestHeader(), dgst)
-                .post(body)
-                .build();
+            .url(ubd.build())
+            .header(apiAuthProp.getClientHeader(), client)
+            .header(apiAuthProp.getTimestampHeader(), timestamp)
+            .header(apiAuthProp.getSignatureHeader(), signature)
+            .header(apiAuthProp.getDigestHeader(), dgst)
+            .header("ticket", String.valueOf(client.startsWith("win-")))
+            .header("signed", String.valueOf(signed))
+            .post(body)
+            .build();
 
         final Response r2 = OkHttpClientHelper.execute(okHttpClient, request, false);
         Assertions.assertNotNull(r2);
@@ -333,7 +341,7 @@ private void jsonFile(String client, String timestamp, Function
         final String text = resBody.string();
         Assertions.assertEquals(fileBody, text);
 
-        final String stmp = r2.header(apiAuthProp.getTimestampHeader());
+        final String stmp = EmptySugar.nullToEmpty(r2.header(apiAuthProp.getTimestampHeader()));
         if (!timestamp.isEmpty()) {
             Assertions.assertEquals(timestamp, stmp);
         }
@@ -344,7 +352,7 @@ private void jsonFile(String client, String timestamp, Function
         Assertions.assertEquals(fileName, disposition.getFilename());
 
         final String data1;
-        if (digest && sumFun != null) {
+        if (signed && digest) {
             final String sum = sumFun.apply(fileBody);
             Assertions.assertEquals(sum, r2.header(apiAuthProp.getDigestHeader()));
             data1 = sum + secret + stmp;
@@ -353,7 +361,7 @@ private void jsonFile(String client, String timestamp, Function
             data1 = secret + stmp;
         }
 
-        if (sumFun != null) {
+        if (signed) {
             final String sign = r2.header(apiAuthProp.getSignatureHeader());
             Assertions.assertNotNull(sign);
 
@@ -369,8 +377,8 @@ private void jsonFile(String client, String timestamp, Function
     @Test
     @TmsLink("C14027")
     public void testFileFile() throws IOException {
-        String[] clients = {client, getToken()};
-        String[] timestamps = {String.valueOf(Now.millis()), Null.Str};
+        String[] clients = { client, getToken() };
+        String[] timestamps = { String.valueOf(Now.millis()), Null.Str };
         for (String c : clients) {
             for (String t : timestamps) {
                 fileFile(c, t, md5, true);
@@ -386,8 +394,10 @@ private void fileFile(String client, String timestamp, Function
         param.put(ReqMethod, ModFileFile);
         param.put(ResFileName, fileName);
         param.put(ResFileBody, fileBody);
+
+        final boolean signed = sumFun != null;
         final String dgst;
-        if (digest && sumFun != null) {
+        if (signed && digest) {
             dgst = sumFun.apply(fileBody);
             param.put(fileSum, dgst);
         }
@@ -396,7 +406,7 @@ private void fileFile(String client, String timestamp, Function
         }
 
         final String para = FormatUtil.sortParam(param);
-        param.remove(fileSum);
+        param.remove(fileSum); // remove from query string, post by form
 
         HttpUrl.Builder ubd = urlBuilder();
         for (Map.Entry en : param.entrySet()) {
@@ -406,22 +416,27 @@ private void fileFile(String client, String timestamp, Function
             }
         }
 
-        final String signature = sumFun == null
-                                 ? Null.Str
-                                 : sumFun.apply(para + jsonBody + secret + timestamp);
+        final String signature = !signed
+            ? Null.Str
+            : sumFun.apply(para + secret + timestamp);
 
         MultipartBody.Builder body = new MultipartBody.Builder()
-                .setType(MultipartBody.FORM)
-                .addFormDataPart(fileKey, fileName, RequestBody.create(fileBody.getBytes(UTF_8), MULTIPART_FORM_DATA_VALUE))
-                .addFormDataPart(fileSum, dgst);
+            .setType(MultipartBody.FORM)
+            .addFormDataPart(fileKey, fileName, RequestBody.create(fileBody.getBytes(UTF_8), MULTIPART_FORM_DATA_VALUE));
+
+        if (!dgst.isEmpty()) {
+            body.addFormDataPart(fileSum, dgst); // pass fileSum by form
+        }
 
         okhttp3.Request request = new okhttp3.Request.Builder()
-                .url(ubd.build())
-                .header(apiAuthProp.getClientHeader(), client)
-                .header(apiAuthProp.getTimestampHeader(), timestamp)
-                .header(apiAuthProp.getSignatureHeader(), signature)
-                .post(body.build())
-                .build();
+            .url(ubd.build())
+            .header(apiAuthProp.getClientHeader(), client)
+            .header(apiAuthProp.getTimestampHeader(), timestamp)
+            .header(apiAuthProp.getSignatureHeader(), signature)
+            .header("ticket", String.valueOf(client.startsWith("win-")))
+            .header("signed", String.valueOf(signed))
+            .post(body.build())
+            .build();
 
         final Response r2 = OkHttpClientHelper.execute(okHttpClient, request, false);
         Assertions.assertNotNull(r2);
@@ -432,7 +447,7 @@ private void fileFile(String client, String timestamp, Function
         final String text = resBody.string();
         Assertions.assertEquals(fileBody, text);
 
-        final String stmp = r2.header(apiAuthProp.getTimestampHeader());
+        final String stmp = EmptySugar.nullToEmpty(r2.header(apiAuthProp.getTimestampHeader()));
         if (!timestamp.isEmpty()) {
             Assertions.assertEquals(timestamp, stmp);
         }
@@ -443,7 +458,7 @@ private void fileFile(String client, String timestamp, Function
         Assertions.assertEquals(fileName, disposition.getFilename());
 
         final String data1;
-        if (digest && sumFun != null) {
+        if (signed && digest) {
             final String sum = sumFun.apply(fileBody);
             Assertions.assertEquals(sum, r2.header(apiAuthProp.getDigestHeader()));
             data1 = sum + secret + stmp;
@@ -452,7 +467,7 @@ private void fileFile(String client, String timestamp, Function
             data1 = secret + stmp;
         }
 
-        if (sumFun != null) {
+        if (signed) {
             final String sign = r2.header(apiAuthProp.getSignatureHeader());
             Assertions.assertNotNull(sign);
 
diff --git a/wings/warlock-shadow/src/test/java/pro/fessional/wings/warlock/controller/api/OkHttpTokenizeTest.java b/wings/warlock-shadow/src/test/java/pro/fessional/wings/warlock/controller/api/OkHttpTokenizeTest.java
index 53f48119c..f9fc42b5c 100644
--- a/wings/warlock-shadow/src/test/java/pro/fessional/wings/warlock/controller/api/OkHttpTokenizeTest.java
+++ b/wings/warlock-shadow/src/test/java/pro/fessional/wings/warlock/controller/api/OkHttpTokenizeTest.java
@@ -22,11 +22,7 @@
  * @author trydofor
  * @since 2022-11-16
  */
-@SpringBootTest(
-        webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT,
-        properties = {
-                "wings.warlock.apiauth.must-signature=false",
-        })
+@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
 @Slf4j
 class OkHttpTokenizeTest {
 

From 7ae36777217bb6f0010f922c1fe75a79cb5d1ca4 Mon Sep 17 00:00:00 2001
From: trydofor 
Date: Tue, 23 Jul 2024 12:20:23 +0800
Subject: [PATCH 27/51] =?UTF-8?q?=F0=9F=8E=A8=20table=20num,=20tiny=20deps?=
 =?UTF-8?q?,=20docs?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 observe/docs                                           |  2 +-
 observe/mirana                                         |  2 +-
 radiant/tiny-mail/pom.xml                              | 10 +++++-----
 .../master/07-mail/2020-10-27u01-tiny_mail.sql         |  2 +-
 .../master/07-mail/2020-10-27v01-tiny_mail.sql         |  2 +-
 radiant/tiny-task/pom.xml                              | 10 +++++-----
 .../master/06-task/2020-10-26u01-tiny_task.sql         |  4 ++--
 .../master/06-task/2020-10-26v01-tiny_task.sql         |  4 ++--
 8 files changed, 18 insertions(+), 18 deletions(-)

diff --git a/observe/docs b/observe/docs
index e50479062..40c4da890 160000
--- a/observe/docs
+++ b/observe/docs
@@ -1 +1 @@
-Subproject commit e5047906276d1422188d9ac445a6f40124aea0a5
+Subproject commit 40c4da8905e9abea371d262fc1d41e14a7f0df46
diff --git a/observe/mirana b/observe/mirana
index 48abc9b94..b0bc380b8 160000
--- a/observe/mirana
+++ b/observe/mirana
@@ -1 +1 @@
-Subproject commit 48abc9b9441629850ef73730f875de739b913eb2
+Subproject commit b0bc380b8af5882887620a4ca54ace9d03b1c253
diff --git a/radiant/tiny-mail/pom.xml b/radiant/tiny-mail/pom.xml
index 098c2991c..9681f8dc5 100644
--- a/radiant/tiny-mail/pom.xml
+++ b/radiant/tiny-mail/pom.xml
@@ -16,6 +16,10 @@
     Tiny Mail component
 
     
+        
+            pro.fessional.wings
+            faceless-jooq
+        
         
             pro.fessional.wings
             slardar
@@ -29,11 +33,7 @@
             slardar-webmvc
             true
         
-        
-            pro.fessional.wings
-            faceless-codegen
-            true
-        
+        
         
             pro.fessional.wings
             faceless-flywave
diff --git a/radiant/tiny-mail/src/main/resources/wings-flywave/master/07-mail/2020-10-27u01-tiny_mail.sql b/radiant/tiny-mail/src/main/resources/wings-flywave/master/07-mail/2020-10-27u01-tiny_mail.sql
index 101848bec..3f6ae752c 100644
--- a/radiant/tiny-mail/src/main/resources/wings-flywave/master/07-mail/2020-10-27u01-tiny_mail.sql
+++ b/radiant/tiny-mail/src/main/resources/wings-flywave/master/07-mail/2020-10-27u01-tiny_mail.sql
@@ -1,3 +1,3 @@
-DROP TABLE IF EXISTS `win_mail_sender`; -- 124/Mail Sending;
+DROP TABLE IF EXISTS `win_mail_sender`; -- 143/Mail Sending;
 
 -- CALL FLYWAVE('2020-10-27u01-tiny_mail.sql');
\ No newline at end of file
diff --git a/radiant/tiny-mail/src/main/resources/wings-flywave/master/07-mail/2020-10-27v01-tiny_mail.sql b/radiant/tiny-mail/src/main/resources/wings-flywave/master/07-mail/2020-10-27v01-tiny_mail.sql
index 7d6fe929e..61d8920ae 100644
--- a/radiant/tiny-mail/src/main/resources/wings-flywave/master/07-mail/2020-10-27v01-tiny_mail.sql
+++ b/radiant/tiny-mail/src/main/resources/wings-flywave/master/07-mail/2020-10-27v01-tiny_mail.sql
@@ -42,6 +42,6 @@ CREATE TABLE `win_mail_sender` (
     INDEX ix_ref_key1 (`ref_key1`),
     INDEX ix_ref_key2 (`ref_key2`)
 ) ENGINE = InnoDB
-  DEFAULT CHARSET = utf8mb4 COMMENT ='124/Mail Sending';
+  DEFAULT CHARSET = utf8mb4 COMMENT ='143/Mail Sending';
 
 -- CALL FLYWAVE('2020-10-27v01-tiny_mail.sql');
\ No newline at end of file
diff --git a/radiant/tiny-task/pom.xml b/radiant/tiny-task/pom.xml
index 04282d17a..4628e0ca8 100644
--- a/radiant/tiny-task/pom.xml
+++ b/radiant/tiny-task/pom.xml
@@ -18,21 +18,21 @@
     
         
             pro.fessional.wings
-            slardar
+            faceless-jooq
         
         
             pro.fessional.wings
-            slardar-webmvc
-            true
+            slardar
         
         
             pro.fessional.wings
-            faceless-flywave
+            slardar-webmvc
             true
         
+        
         
             pro.fessional.wings
-            faceless-codegen
+            faceless-flywave
             true
         
         
diff --git a/radiant/tiny-task/src/main/resources/wings-flywave/master/06-task/2020-10-26u01-tiny_task.sql b/radiant/tiny-task/src/main/resources/wings-flywave/master/06-task/2020-10-26u01-tiny_task.sql
index efc6b392f..345e8749f 100644
--- a/radiant/tiny-task/src/main/resources/wings-flywave/master/06-task/2020-10-26u01-tiny_task.sql
+++ b/radiant/tiny-task/src/main/resources/wings-flywave/master/06-task/2020-10-26u01-tiny_task.sql
@@ -1,4 +1,4 @@
-DROP TABLE IF EXISTS `win_task_define`; -- 120/Task Define;
-DROP TABLE IF EXISTS `win_task_result`; -- 122/Task Result;
+DROP TABLE IF EXISTS `win_task_define`; -- 141/Task Define;
+DROP TABLE IF EXISTS `win_task_result`; -- 142/Task Result;
 
 -- CALL FLYWAVE('2020-10-26u01-tiny_task.sql');
\ No newline at end of file
diff --git a/radiant/tiny-task/src/main/resources/wings-flywave/master/06-task/2020-10-26v01-tiny_task.sql b/radiant/tiny-task/src/main/resources/wings-flywave/master/06-task/2020-10-26v01-tiny_task.sql
index c617eec77..63834535a 100644
--- a/radiant/tiny-task/src/main/resources/wings-flywave/master/06-task/2020-10-26v01-tiny_task.sql
+++ b/radiant/tiny-task/src/main/resources/wings-flywave/master/06-task/2020-10-26v01-tiny_task.sql
@@ -44,7 +44,7 @@ CREATE TABLE `win_task_define` (
     PRIMARY KEY (`id`),
     UNIQUE INDEX uq_tasker_bean (`tasker_bean`)
 ) ENGINE = InnoDB
-  DEFAULT CHARSET = utf8mb4 COMMENT ='120/Task Define';
+  DEFAULT CHARSET = utf8mb4 COMMENT ='141/Task Define';
 
 CREATE TABLE `win_task_result` (
     `id`        BIGINT(20)   NOT NULL COMMENT 'primary key',
@@ -60,6 +60,6 @@ CREATE TABLE `win_task_result` (
     PRIMARY KEY (`id`),
     INDEX ix_task_id (`task_id`)
 ) ENGINE = InnoDB
-  DEFAULT CHARSET = utf8mb4 COMMENT ='122/Task Result';
+  DEFAULT CHARSET = utf8mb4 COMMENT ='142/Task Result';
 
 -- CALL FLYWAVE('2020-10-26v01-tiny_task.sql');
\ No newline at end of file

From 85cf1453a336255047bc33c73f9f872484c61b29 Mon Sep 17 00:00:00 2001
From: trydofor 
Date: Tue, 23 Jul 2024 17:00:54 +0800
Subject: [PATCH 28/51] =?UTF-8?q?=E2=9C=A8=20optimise=20log=20monitor=20wi?=
 =?UTF-8?q?th=20stracktrace=20#277?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 WingsBoot.t.md                                |  1 +
 observe/docs                                  |  2 +-
 .../slardar/monitor/viewer/WebLogViewer.java  | 40 +++++++++++++
 .../monitor/report/DingTalkReport.java        |  4 +-
 .../wings/slardar/monitor/viewer/LogConf.java |  9 +++
 .../slardar/monitor/viewer/LogViewer.java     | 53 +++++-----------
 .../wings-conf/wings-monitor-79.properties    |  6 +-
 .../slardar/monitor/viewer/LogViewerTest.java | 60 +++++++++++++++++++
 8 files changed, 134 insertions(+), 41 deletions(-)
 create mode 100644 wings/slardar-webmvc/src/main/java/pro/fessional/wings/slardar/monitor/viewer/WebLogViewer.java
 rename wings/{slardar-webmvc => slardar}/src/main/java/pro/fessional/wings/slardar/monitor/viewer/LogViewer.java (67%)
 create mode 100644 wings/slardar/src/test/java/pro/fessional/wings/slardar/monitor/viewer/LogViewerTest.java

diff --git a/WingsBoot.t.md b/WingsBoot.t.md
index d432f47d2..5284d7b42 100644
--- a/WingsBoot.t.md
+++ b/WingsBoot.t.md
@@ -325,6 +325,7 @@ Use `t.md` as local [Test Management](https://www.jetbrains.com/help/idea/test-m
 * 13125 JsonHelperCompatibleTest: jackson basic type compatible
 * 13126 FastJsonTest: fastjson helper json path
 * 13127 TypeReferenceTest: TypeReference, TypeDescriptor, ResolvableType
+* 13128 LogViewerTest: only match header line
 
 ## 14 Warlock
 
diff --git a/observe/docs b/observe/docs
index 40c4da890..6f308b4bd 160000
--- a/observe/docs
+++ b/observe/docs
@@ -1 +1 @@
-Subproject commit 40c4da8905e9abea371d262fc1d41e14a7f0df46
+Subproject commit 6f308b4bd5396fd27b0cad1e23710a9b13a9d4f4
diff --git a/wings/slardar-webmvc/src/main/java/pro/fessional/wings/slardar/monitor/viewer/WebLogViewer.java b/wings/slardar-webmvc/src/main/java/pro/fessional/wings/slardar/monitor/viewer/WebLogViewer.java
new file mode 100644
index 000000000..12ed55802
--- /dev/null
+++ b/wings/slardar-webmvc/src/main/java/pro/fessional/wings/slardar/monitor/viewer/WebLogViewer.java
@@ -0,0 +1,40 @@
+package pro.fessional.wings.slardar.monitor.viewer;
+
+import io.swagger.v3.oas.annotations.Operation;
+import jakarta.servlet.http.HttpServletResponse;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+import pro.fessional.wings.silencer.spring.boot.ConditionalWingsEnabled;
+import pro.fessional.wings.slardar.spring.prop.SlardarMonitorProp;
+
+import java.io.IOException;
+
+/**
+ * @author trydofor
+ * @since 2021-07-20
+ */
+@Slf4j
+@RestController
+@ConditionalWingsEnabled(abs = LogConf.Key$enable)
+public class WebLogViewer extends LogViewer {
+
+    @Autowired
+    public WebLogViewer(SlardarMonitorProp prop) {
+        super(prop.getView());
+    }
+
+    @Operation(summary = "Alarm logs can be viewed in conjunction with alarm notifications when self-monitoring is enabled.", description = """
+        # Usage
+        Pass the log id to view the log.
+        ## Params
+        * @param id - log id, max 2k caches in 36H
+        ## Returns
+        * @return {200 | string} log context or empty""")
+    @GetMapping(value = "${" + LogConf.Key$mapping + "}")
+    public void view(@RequestParam("id") String id, HttpServletResponse res) throws IOException {
+        super.view(id, res.getOutputStream());
+    }
+}
diff --git a/wings/slardar/src/main/java/pro/fessional/wings/slardar/monitor/report/DingTalkReport.java b/wings/slardar/src/main/java/pro/fessional/wings/slardar/monitor/report/DingTalkReport.java
index 616d6bb9c..a4a42f1aa 100644
--- a/wings/slardar/src/main/java/pro/fessional/wings/slardar/monitor/report/DingTalkReport.java
+++ b/wings/slardar/src/main/java/pro/fessional/wings/slardar/monitor/report/DingTalkReport.java
@@ -12,6 +12,7 @@
 
 import java.util.List;
 import java.util.Map;
+import java.util.concurrent.atomic.AtomicLong;
 import java.util.function.Consumer;
 
 import static pro.fessional.wings.silencer.datetime.DateTimePattern.FMT_FULL_19Z;
@@ -28,6 +29,7 @@ public class DingTalkReport implements WarnReport {
 
     private final String dingConfig;
     private final DingTalkNotice dingTalkNotice;
+    private final AtomicLong counter = new AtomicLong(1);
 
     protected String gitInfo = null;
 
@@ -81,7 +83,7 @@ public Sts report(String appName, String jvmName, Map cache;
 
-    @Autowired
-    public LogViewer(SlardarMonitorProp prop) {
-        this(prop.getView());
-    }
-
     public LogViewer(LogConf conf) {
         this.conf = conf;
         this.cache = WingsCache2k.builder(LogViewer.class, "cache", 2_000, conf.getAlive(), null, String.class, String.class).build();
     }
 
-    @Operation(summary = "Alarm logs can be viewed in conjunction with alarm notifications when self-monitoring is enabled.", description = """
-        # Usage
-        Pass the log id to view the log.
-        ## Params
-        * @param id - log id, max 2k caches in 36H
-        ## Returns
-        * @return {200 | string} log context or empty""")
-    @GetMapping(value = "${" + LogConf.Key$mapping + "}")
-    public void view(@RequestParam("id") String id, HttpServletResponse res) throws IOException {
+    public void view(String id, OutputStream output) throws IOException {
         if (id == null) return;
         final String log = cache.get(id);
         if (log == null) return;
@@ -69,11 +47,10 @@ public void view(@RequestParam("id") String id, HttpServletResponse res) throws
 
         try (FileInputStream fis = new FileInputStream(file)) {
             final long len = conf.getLength().toBytes();
-            final ServletOutputStream outputStream = res.getOutputStream();
-            IOUtils.copyLarge(fis, res.getOutputStream(), 0L, len);
+            IOUtils.copyLarge(fis, output, 0L, len);
             if (file.length() - len > 0) {
                 final String more = String.format("\n\n...... %,d / %,d bytes", len, file.length());
-                outputStream.write(more.getBytes());
+                output.write(more.getBytes());
             }
         }
     }
@@ -116,30 +93,32 @@ public void filter(Map> warns) {
         }
     }
 
-    private boolean canIgnoreHead(String out) {
-        if (conf.getIgnore().isEmpty()) return false;
+    protected boolean canIgnoreHead(String out) {
+        final Collection ignores = conf.getIgnore().values();
+        if (ignores.isEmpty()) return false;
 
         long max = conf.getLength().toBytes();
         final File file = new File(out);
         if (file.length() > max || !file.canRead()) return false;
 
+        final Pattern head = conf.getHeader();
         try (BufferedReader reader = new BufferedReader(new FileReader(file))) {
-            final Collection ign = conf.getIgnore().values();
             String line;
             int tol = 0;
             int cnt = 0;
-            out:
             while ((line = reader.readLine()) != null && max > 0) {
-                if (line.isEmpty()) {
+                max -= line.length() + 1; // loose calculation
+
+                if (line.isEmpty() || (head != null && !head.matcher(line).find())) {
                     continue;
                 }
-                //
-                max -= line.length(); // loose calculation
+
+                // only match header line
                 tol++;
-                for (String s : ign) {
+                for (String s : ignores) {
                     if (line.contains(s)) {
                         cnt++;
-                        continue out;
+                        break;
                     }
                 }
             }
diff --git a/wings/slardar/src/main/resources/wings-conf/wings-monitor-79.properties b/wings/slardar/src/main/resources/wings-conf/wings-monitor-79.properties
index 79ee26c42..328e3b8e6 100644
--- a/wings/slardar/src/main/resources/wings-conf/wings-monitor-79.properties
+++ b/wings/slardar/src/main/resources/wings-conf/wings-monitor-79.properties
@@ -69,6 +69,8 @@ wings.slardar.monitor.view.alive=36H
 wings.slardar.monitor.view.length=1MB
 ## host or ip for external access.
 wings.slardar.monitor.view.domain=http://${server.address:localhost}:${server.port:80}
+## regexp of section header, e.g. `2023-02-04T11:09:32.692+08:00`, `2024-07-23 01:31:59.063`
+wings.slardar.monitor.view.header=^\\d{4}-\\d{2}-\\d{2}[T ]\\d{2}:\\d{2}:\\d{2}[-+.:0-9]*\\s+
 
 ## ignored alert string in logs.
 ## kotlin is support, but not really used
@@ -81,8 +83,8 @@ wings.slardar.monitor.view.ignore[AutoLog-Switch]=Auto Switch the following Appe
 wings.slardar.monitor.view.ignore[No-MessageSource]=not found for MessageSource
 ## PersistenceProviderResolverHolder, Using jooq can logging.level.javax.persistence.spi=ERROR
 wings.slardar.monitor.view.ignore[Jpa-Persistence]=.persistence.spi::No valid providers found
-## UT005071: Undertow request failed HttpServerExchange{ CONNECT ; CONNECT
-wings.slardar.monitor.view.ignore[UT005071-CONNECT]=UT005071: Undertow request failed HttpServerExchange{ CONNECT
+## UT005071: Undertow request failed HttpServerExchange{ CONNECT
+wings.slardar.monitor.view.ignore[UT005071-CONNECT]=UT005071: Undertow request failed HttpServerExchange
 wings.slardar.monitor.view.ignore[Spring-WebIgnore]=You are asking Spring Security to ignore
 
 ## use DingTalk bot by default with the key `monitor`.
diff --git a/wings/slardar/src/test/java/pro/fessional/wings/slardar/monitor/viewer/LogViewerTest.java b/wings/slardar/src/test/java/pro/fessional/wings/slardar/monitor/viewer/LogViewerTest.java
new file mode 100644
index 000000000..5c9a501b2
--- /dev/null
+++ b/wings/slardar/src/test/java/pro/fessional/wings/slardar/monitor/viewer/LogViewerTest.java
@@ -0,0 +1,60 @@
+package pro.fessional.wings.slardar.monitor.viewer;
+
+import io.qameta.allure.TmsLink;
+import lombok.Setter;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import pro.fessional.wings.slardar.spring.prop.SlardarMonitorProp;
+
+import java.nio.file.Files;
+import java.nio.file.Path;
+
+/**
+ * @author trydofor
+ * @since 2024-07-23
+ */
+@SpringBootTest
+class LogViewerTest {
+
+    @Setter(onMethod_ = { @Autowired })
+    protected SlardarMonitorProp slardarMonitorProp;
+
+    @TmsLink("13128")
+    @Test
+    void canIgnoreHead() throws Exception {
+        final LogViewer lv = new LogViewer(slardarMonitorProp.getView());
+
+        final Path tmp0 = Files.createTempFile("test-", null);
+        tmp0.toFile().deleteOnExit();
+        Files.writeString(tmp0, """
+            2024-07-21 22:05:22.957 ERROR 10884 --- [kite-front] [XNIO-1 I/O-4] io.undertow.request                      : UT005071: Undertow request failed HttpServerExchange{ CONNECT api.ipify.org:443}
+                        
+            java.lang.IllegalArgumentException: UT000068: Servlet path match failed
+            	at io.undertow.servlet.handlers.ServletPathMatchesData.getServletHandlerByPath(ServletPathMatchesData.java:83) ~[undertow-servlet-2.3.10.Final.jar!/:2.3.10.Final]
+            """.stripIndent());
+
+
+        boolean b0 = lv.canIgnoreHead(tmp0.toAbsolutePath().toString());
+        Assertions.assertTrue(b0);
+
+        final Path tmp1 = Files.createTempFile("test-", null);
+        tmp1.toFile().deleteOnExit();
+        Files.writeString(tmp1, """
+            2024-07-21 22:05:22.957 ERROR 10884 --- [kite-front] [XNIO-1 I/O-4] io.undertow.request                      : UT005071: Undertow request failed HttpServerExchange{ CONNECT api.ipify.org:443}
+                        
+            java.lang.IllegalArgumentException: UT000068: Servlet path match failed
+            	at io.undertow.servlet.handlers.ServletPathMatchesData.getServletHandlerByPath(ServletPathMatchesData.java:83) ~[undertow-servlet-2.3.10.Final.jar!/:2.3.10.Final]
+            	at io.undertow.servlet.handlers.ServletPathMatches.getServletHandlerByPath(ServletPathMatches.java:133) ~[undertow-servlet-2.3.10.Final.jar!/:2.3.10.Final]
+
+            2024-07-23 01:33:05.446 ERROR 10884 --- [kite-front] [XNIO-1 task-4] p.f.w.w.e.DefaultExceptionResolver       : unhandled exception, response default
+              
+            java.lang.NumberFormatException: For input string
+                      """.stripIndent());
+
+
+        boolean b1 = lv.canIgnoreHead(tmp1.toAbsolutePath().toString());
+        Assertions.assertFalse(b1);
+    }
+}
\ No newline at end of file

From 79436d5ccd5e159206e33d2c6fabb14dfa7ee610 Mon Sep 17 00:00:00 2001
From: trydofor 
Date: Wed, 24 Jul 2024 09:55:44 +0800
Subject: [PATCH 29/51] =?UTF-8?q?=E2=9C=A8=20disable=20oss=20repo=20in=20s?=
 =?UTF-8?q?ome=20case=20#279?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .github/workflows/release.yml |  6 +++---
 pom.xml                       | 30 ++++++++++++++++++------------
 2 files changed, 21 insertions(+), 15 deletions(-)

diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index b6bcea9b7..49a4d99bc 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -156,7 +156,7 @@ jobs:
       - name: Test Coverage ${{ steps.settings.outputs.WINGS_VERSION }} ${{ steps.settings.outputs.GIT_BRANCH }}
         if: steps.settings.outputs.MVN_COVERAGE == 'true'
         run: |
-          mvn -P '!module-example,!module-devs' -Dmaven.test.skip=true clean install
+          mvn -P 'repo-snapshot,!module-example,!module-devs' -Dmaven.test.skip=true clean install
           mvn -pl ':devs-codegen' -Ddevs-initdb=true clean test
           mvn -P 'report-coverage,!module-example,!module-devs' -Dmaven.test.failure.ignore=$TESTFAILS_IGNORE test
           mvn -P 'report-coverage' -pl ':devs-coverage' -am jacoco:report-aggregate
@@ -181,7 +181,7 @@ jobs:
         if: steps.settings.outputs.MVN_DEPLOY_OSSRH == 'true'
         run: >
           mvn 
-          -P 'deploy,deploy-oss,!module-example,!module-devs'
+          -P 'repo-snapshot,deploy,deploy-oss,!module-example,!module-devs'
           ${{ steps.settings.outputs.MVN_REVISION }}
           -Dgpg.passphrase=${MVN_GPG_PASS}
           -Dorg.slf4j.simpleLogger.log.lombok=WARN
@@ -200,7 +200,7 @@ jobs:
         continue-on-error: ${{ inputs.deployAltrh != 'true' }}
         run: >
           mvn 
-          -P 'deploy,deploy-alt,deploy-old,!module-example,!module-devs'
+          -P 'repo-snapshot,deploy,deploy-alt,deploy-old,!module-example,!module-devs'
           ${{ steps.settings.outputs.MVN_REVISION }}
           -Dgpg.passphrase=${MVN_GPG_PASS}
           -Dorg.slf4j.simpleLogger.log.lombok=WARN
diff --git a/pom.xml b/pom.xml
index 335988b36..b61a7be9d 100644
--- a/pom.xml
+++ b/pom.xml
@@ -959,18 +959,6 @@
             
         
     
-    
-        
-            oss-sonatype
-            https://oss.sonatype.org/content/repositories/snapshots/
-            
-                false
-            
-            
-                true
-            
-        
-    
     
         
             module-example
@@ -981,6 +969,24 @@
                 example
             
         
+        
+            repo-snapshot
+            
+                true
+            
+            
+                
+                    oss-sonatype
+                    https://oss.sonatype.org/content/repositories/snapshots/
+                    
+                        false
+                    
+                    
+                        true
+                    
+                
+            
+        
         
             wings-kotlin-1test
             

From 5778aa6a3e2ad78d64de622841d21b1bb131cc17 Mon Sep 17 00:00:00 2001
From: trydofor 
Date: Sat, 27 Jul 2024 23:42:09 +0800
Subject: [PATCH 30/51] =?UTF-8?q?=E2=9C=A8=20tiny-grow=20to=20track=20data?=
 =?UTF-8?q?,=20analyze=20grow=20#275?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 observe/docs                                  |    2 +-
 observe/mirana                                |    2 +-
 .../wings/devs/init/AutogenMainCodeTest.java  |   29 +-
 .../wings/devs/init/AutogenTestCodeTest.java  |   18 +-
 .../wings/devs/init/DatabaseExampleTest.java  |   16 +-
 .../wings/devs/init/DatabaseFacelessTest.java |   12 +-
 .../wings/devs/init/DatabaseShard0Test.java   |    8 +-
 .../wings/devs/init/DatabaseShard1Test.java   |    8 +-
 .../wings/devs/init/DatabaseTinyTest.java     |   10 +-
 .../wings/devs/init/DatabaseWarlockTest.java  |   14 +-
 .../wings/devs/init/DatabaseWingsTest.java    |   20 +-
 .../wings/devs/init/TestingDatabase.java      |    8 +-
 radiant/pom.xml                               |    1 +
 radiant/tiny-grow/pom.xml                     |   47 +
 .../tiny/grow/database/TinyGrowDatabase.java  |    8 +
 .../autogen/DefaultCatalogTinyGrow.java       |   47 +
 .../autogen/DefaultSchemaTinyGrow.java        |   62 +
 .../grow/database/autogen/TablesTinyGrow.java |   30 +
 .../autogen/tables/WinGrowTrackTable.java     |  277 +++
 .../autogen/tables/daos/WinGrowTrackDao.java  |  709 +++++++
 .../tables/interfaces/IWinGrowTrack.java      |  233 +++
 .../autogen/tables/pojos/WinGrowTrack.java    | 1851 +++++++++++++++++
 .../tables/records/WinGrowTrackRecord.java    |  888 ++++++++
 .../spring/bean/TinyTrackConfiguration.java   |   31 +
 .../conf/TinyGrowAutoConfiguration.java       |   19 +
 .../spring/prop/TinyTrackExcludeProp.java     |   45 +
 .../tiny/grow/track/TinyTrackHelper.java      |   30 +
 .../tiny/grow/track/TinyTrackService.java     |  118 ++
 .../wings/tiny/grow/track/TinyTracker.java    |   40 +
 .../tiny/grow/track/impl/TinyTrackAround.java |  153 ++
 .../track/impl/TinyTrackCollectorDaoImpl.java |  101 +
 .../grow/track/impl/TinyTrackServiceImpl.java |   84 +
 ...itional-spring-configuration-metadata.json |   17 +
 ...ot.autoconfigure.AutoConfiguration.imports |    1 +
 .../wings-flywave-fit-79.properties           |    3 +
 .../wings-tinytrack-exclude-79.properties     |   11 +
 .../08-grow/2020-10-28u01-tiny_grow.sql       |    3 +
 .../08-grow/2020-10-28v01-tiny_grow.sql       |   30 +
 .../tiny/app/TestTinyGrowApplication.java     |   19 +
 .../app/controller/TestTrackController.java   |   27 +
 .../tiny/app/service/TestTrack1Service.java   |   36 +
 .../tiny/app/service/TestTrack2Service.java   |   13 +
 .../wings/tiny/app/service/TestTrackData.java |   25 +
 .../service/impl/TestTrack2ServiceImpl.java   |   40 +
 .../service/impl/TestTrackCollectorImpl.java  |   25 +
 .../tiny/grow/track/TinyTrackServiceTest.java |  110 +
 .../src/test/resources/application.properties |    6 +
 .../spring-datasource-99.properties           |    1 +
 .../wings-conf/wings-tinytask-test.properties |   16 +
 .../wings/tiny/mail/sender/MailNotice.java    |    3 +-
 .../wings/faceless/flywave/WingsRevision.java |    1 +
 .../slardar/fastjson/FastJsonHelper.java      |   18 +
 .../filter/ComposePropertyFilter.java         |   59 +
 .../filter/ComposePropertyPreFilter.java      |   60 +
 .../filter/ExcludePropertyPreFilter.java      |   65 +
 .../wings/slardar/notice/DingTalkNotice.java  |    3 +-
 .../wings/slardar/fastjson/FastJsonTest.java  |    3 +
 57 files changed, 5444 insertions(+), 72 deletions(-)
 create mode 100644 radiant/tiny-grow/pom.xml
 create mode 100644 radiant/tiny-grow/src/main/java-gen/pro/fessional/wings/tiny/grow/database/TinyGrowDatabase.java
 create mode 100644 radiant/tiny-grow/src/main/java-gen/pro/fessional/wings/tiny/grow/database/autogen/DefaultCatalogTinyGrow.java
 create mode 100644 radiant/tiny-grow/src/main/java-gen/pro/fessional/wings/tiny/grow/database/autogen/DefaultSchemaTinyGrow.java
 create mode 100644 radiant/tiny-grow/src/main/java-gen/pro/fessional/wings/tiny/grow/database/autogen/TablesTinyGrow.java
 create mode 100644 radiant/tiny-grow/src/main/java-gen/pro/fessional/wings/tiny/grow/database/autogen/tables/WinGrowTrackTable.java
 create mode 100644 radiant/tiny-grow/src/main/java-gen/pro/fessional/wings/tiny/grow/database/autogen/tables/daos/WinGrowTrackDao.java
 create mode 100644 radiant/tiny-grow/src/main/java-gen/pro/fessional/wings/tiny/grow/database/autogen/tables/interfaces/IWinGrowTrack.java
 create mode 100644 radiant/tiny-grow/src/main/java-gen/pro/fessional/wings/tiny/grow/database/autogen/tables/pojos/WinGrowTrack.java
 create mode 100644 radiant/tiny-grow/src/main/java-gen/pro/fessional/wings/tiny/grow/database/autogen/tables/records/WinGrowTrackRecord.java
 create mode 100644 radiant/tiny-grow/src/main/java/pro/fessional/wings/tiny/grow/spring/bean/TinyTrackConfiguration.java
 create mode 100644 radiant/tiny-grow/src/main/java/pro/fessional/wings/tiny/grow/spring/conf/TinyGrowAutoConfiguration.java
 create mode 100644 radiant/tiny-grow/src/main/java/pro/fessional/wings/tiny/grow/spring/prop/TinyTrackExcludeProp.java
 create mode 100644 radiant/tiny-grow/src/main/java/pro/fessional/wings/tiny/grow/track/TinyTrackHelper.java
 create mode 100644 radiant/tiny-grow/src/main/java/pro/fessional/wings/tiny/grow/track/TinyTrackService.java
 create mode 100644 radiant/tiny-grow/src/main/java/pro/fessional/wings/tiny/grow/track/TinyTracker.java
 create mode 100644 radiant/tiny-grow/src/main/java/pro/fessional/wings/tiny/grow/track/impl/TinyTrackAround.java
 create mode 100644 radiant/tiny-grow/src/main/java/pro/fessional/wings/tiny/grow/track/impl/TinyTrackCollectorDaoImpl.java
 create mode 100644 radiant/tiny-grow/src/main/java/pro/fessional/wings/tiny/grow/track/impl/TinyTrackServiceImpl.java
 create mode 100644 radiant/tiny-grow/src/main/resources/META-INF/additional-spring-configuration-metadata.json
 create mode 100644 radiant/tiny-grow/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
 create mode 100644 radiant/tiny-grow/src/main/resources/wings-conf/wings-flywave-fit-79.properties
 create mode 100644 radiant/tiny-grow/src/main/resources/wings-conf/wings-tinytrack-exclude-79.properties
 create mode 100644 radiant/tiny-grow/src/main/resources/wings-flywave/master/08-grow/2020-10-28u01-tiny_grow.sql
 create mode 100644 radiant/tiny-grow/src/main/resources/wings-flywave/master/08-grow/2020-10-28v01-tiny_grow.sql
 create mode 100644 radiant/tiny-grow/src/test/java/pro/fessional/wings/tiny/app/TestTinyGrowApplication.java
 create mode 100644 radiant/tiny-grow/src/test/java/pro/fessional/wings/tiny/app/controller/TestTrackController.java
 create mode 100644 radiant/tiny-grow/src/test/java/pro/fessional/wings/tiny/app/service/TestTrack1Service.java
 create mode 100644 radiant/tiny-grow/src/test/java/pro/fessional/wings/tiny/app/service/TestTrack2Service.java
 create mode 100644 radiant/tiny-grow/src/test/java/pro/fessional/wings/tiny/app/service/TestTrackData.java
 create mode 100644 radiant/tiny-grow/src/test/java/pro/fessional/wings/tiny/app/service/impl/TestTrack2ServiceImpl.java
 create mode 100644 radiant/tiny-grow/src/test/java/pro/fessional/wings/tiny/app/service/impl/TestTrackCollectorImpl.java
 create mode 100644 radiant/tiny-grow/src/test/java/pro/fessional/wings/tiny/grow/track/TinyTrackServiceTest.java
 create mode 100644 radiant/tiny-grow/src/test/resources/application.properties
 create mode 100644 radiant/tiny-grow/src/test/resources/wings-conf/spring-datasource-99.properties
 create mode 100644 radiant/tiny-grow/src/test/resources/wings-conf/wings-tinytask-test.properties
 create mode 100644 wings/slardar/src/main/java/pro/fessional/wings/slardar/fastjson/filter/ComposePropertyFilter.java
 create mode 100644 wings/slardar/src/main/java/pro/fessional/wings/slardar/fastjson/filter/ComposePropertyPreFilter.java
 create mode 100644 wings/slardar/src/main/java/pro/fessional/wings/slardar/fastjson/filter/ExcludePropertyPreFilter.java

diff --git a/observe/docs b/observe/docs
index 6f308b4bd..5a0422caa 160000
--- a/observe/docs
+++ b/observe/docs
@@ -1 +1 @@
-Subproject commit 6f308b4bd5396fd27b0cad1e23710a9b13a9d4f4
+Subproject commit 5a0422caaff0d501ff16500c6115532a2de870b6
diff --git a/observe/mirana b/observe/mirana
index b0bc380b8..91b7e6040 160000
--- a/observe/mirana
+++ b/observe/mirana
@@ -1 +1 @@
-Subproject commit b0bc380b8af5882887620a4ca54ace9d03b1c253
+Subproject commit 91b7e6040f09df04319c9e36a641e39b1e0a191c
diff --git a/radiant/devs-codegen/src/test/java/pro/fessional/wings/devs/init/AutogenMainCodeTest.java b/radiant/devs-codegen/src/test/java/pro/fessional/wings/devs/init/AutogenMainCodeTest.java
index 65cd5e6be..2c840b4e1 100644
--- a/radiant/devs-codegen/src/test/java/pro/fessional/wings/devs/init/AutogenMainCodeTest.java
+++ b/radiant/devs-codegen/src/test/java/pro/fessional/wings/devs/init/AutogenMainCodeTest.java
@@ -29,13 +29,13 @@
 @EnabledIfSystemProperty(named = "devs-autogen", matches = "true")
 @TestMethodOrder(MethodOrderer.MethodName.class)
 public class AutogenMainCodeTest {
-    @Setter(onMethod_ = {@Autowired})
+    @Setter(onMethod_ = { @Autowired })
     private DataSource dataSource;
-    @Setter(onMethod_ = {@Value("${spring.datasource.url}")})
+    @Setter(onMethod_ = { @Value("${spring.datasource.url}") })
     private String jdbcUrl;
-    @Setter(onMethod_ = {@Value("${spring.datasource.username}")})
+    @Setter(onMethod_ = { @Value("${spring.datasource.username}") })
     private String jdbcUser;
-    @Setter(onMethod_ = {@Value("${spring.datasource.password}")})
+    @Setter(onMethod_ = { @Value("${spring.datasource.password}") })
     private String jdbcPass;
 
     private final String projectRoot = "../../";
@@ -48,6 +48,8 @@ void autogen01AllMainCode() {
         autogen20WarlockAutogenAuth(); // warlock/security
 
         autogen21WarlockAutogenJooq(); // warlock/database
+
+        autogen31TinyGrowAutogenJooq(); // tiny/grow
         autogen31TinyMailAutogenJooq(); // tiny/mail
         autogen31TinyTaskAutogenJooq(); // tiny/task
     }
@@ -69,7 +71,7 @@ void autogen20WarlockAutogenEnum() {
         generator.setTargetDir(projectRoot + "wings/warlock/src/main/java-gen/");
         generator.setTargetPkg("pro.fessional.wings.warlock.enums.autogen");
         generator.gen(jdbcUrl, jdbcUser, jdbcPass,
-                h -> h.includeType(Warlock2EnumGenerator.warlockEnums));
+            h -> h.includeType(Warlock2EnumGenerator.warlockEnums));
     }
 
     void autogen20WarlockAutogenAuth() {
@@ -91,13 +93,22 @@ void autogen21WarlockAutogenJooq() {
             bd -> bd.setGlobalSuffix("Warlock"));
     }
 
+    void autogen31TinyGrowAutogenJooq() {
+        ProjectJooqGenerator generator = new ProjectJooqGenerator();
+        generator.setTargetDir(projectRoot + "radiant/tiny-grow/src/main/java-gen/");
+        generator.setTargetPkg("pro.fessional.wings.tiny.grow.database.autogen");
+        generator.gen(jdbcUrl, jdbcUser, jdbcPass,
+            bd -> bd.databaseIncludes("win_grow_track"),
+            bd -> bd.setGlobalSuffix("TinyGrow"));
+    }
+
     void autogen31TinyMailAutogenJooq() {
         ProjectJooqGenerator generator = new ProjectJooqGenerator();
         generator.setTargetDir(projectRoot + "radiant/tiny-mail/src/main/java-gen/");
         generator.setTargetPkg("pro.fessional.wings.tiny.mail.database.autogen");
         generator.gen(jdbcUrl, jdbcUser, jdbcPass,
-                bd -> bd.databaseIncludes("win_mail_sender"),
-                bd -> bd.setGlobalSuffix("TinyMail"));
+            bd -> bd.databaseIncludes("win_mail_sender"),
+            bd -> bd.setGlobalSuffix("TinyMail"));
     }
 
     void autogen31TinyTaskAutogenJooq() {
@@ -105,7 +116,7 @@ void autogen31TinyTaskAutogenJooq() {
         generator.setTargetDir(projectRoot + "radiant/tiny-task/src/main/java-gen/");
         generator.setTargetPkg("pro.fessional.wings.tiny.task.database.autogen");
         generator.gen(jdbcUrl, jdbcUser, jdbcPass,
-                bd -> bd.databaseIncludes("win_task_define", "win_task_result"),
-                bd -> bd.setGlobalSuffix("TinyTask"));
+            bd -> bd.databaseIncludes("win_task_define", "win_task_result"),
+            bd -> bd.setGlobalSuffix("TinyTask"));
     }
 }
diff --git a/radiant/devs-codegen/src/test/java/pro/fessional/wings/devs/init/AutogenTestCodeTest.java b/radiant/devs-codegen/src/test/java/pro/fessional/wings/devs/init/AutogenTestCodeTest.java
index f48fab6b8..120bf54c7 100644
--- a/radiant/devs-codegen/src/test/java/pro/fessional/wings/devs/init/AutogenTestCodeTest.java
+++ b/radiant/devs-codegen/src/test/java/pro/fessional/wings/devs/init/AutogenTestCodeTest.java
@@ -8,34 +8,26 @@
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Value;
 import org.springframework.boot.test.context.SpringBootTest;
-import pro.fessional.wings.faceless.codegen.ConstantEnumGenerator;
-import pro.fessional.wings.faceless.codegen.ConstantEnumJdbcLoader;
-import pro.fessional.wings.faceless.codegen.JdbcDataLoadHelper;
 import pro.fessional.wings.faceless.enums.autogen.StandardLanguage;
-import pro.fessional.wings.faceless.project.ProjectEnumGenerator;
-import pro.fessional.wings.faceless.project.ProjectJooqGenerator;
-import pro.fessional.wings.warlock.project.Warlock2EnumGenerator;
 import pro.fessional.wings.warlock.project.Warlock3JooqGenerator;
-import pro.fessional.wings.warlock.project.Warlock4AuthGenerator;
 
 import javax.sql.DataSource;
-import java.util.List;
 
 /**
  * @author trydofor
  * @since 2023-01-23
  */
- @SpringBootTest(properties = "testing.dbname=wings_faceless")
+@SpringBootTest(properties = "testing.dbname=wings_faceless")
 @EnabledIfSystemProperty(named = "devs-autogen", matches = "true")
 @TestMethodOrder(MethodOrderer.MethodName.class)
 public class AutogenTestCodeTest {
-    @Setter(onMethod_ = {@Autowired})
+    @Setter(onMethod_ = { @Autowired })
     private DataSource dataSource;
-    @Setter(onMethod_ = {@Value("${spring.datasource.url}")})
+    @Setter(onMethod_ = { @Value("${spring.datasource.url}") })
     private String jdbcUrl;
-    @Setter(onMethod_ = {@Value("${spring.datasource.username}")})
+    @Setter(onMethod_ = { @Value("${spring.datasource.username}") })
     private String jdbcUser;
-    @Setter(onMethod_ = {@Value("${spring.datasource.password}")})
+    @Setter(onMethod_ = { @Value("${spring.datasource.password}") })
     private String jdbcPass;
 
     private final String projectRoot = "../../";
diff --git a/radiant/devs-codegen/src/test/java/pro/fessional/wings/devs/init/DatabaseExampleTest.java b/radiant/devs-codegen/src/test/java/pro/fessional/wings/devs/init/DatabaseExampleTest.java
index ad7bd0ed4..8a61a7da3 100644
--- a/radiant/devs-codegen/src/test/java/pro/fessional/wings/devs/init/DatabaseExampleTest.java
+++ b/radiant/devs-codegen/src/test/java/pro/fessional/wings/devs/init/DatabaseExampleTest.java
@@ -25,14 +25,14 @@ public class DatabaseExampleTest extends TestingDatabase {
     @Test
     void resetSchemaWings() {
         reset(
-                V00_19_0512_01_Schema,
-                V01_19_0520_01_IdLog,
-                V01_19_0521_01_EnumI18n,
-                V03_20_1023_01_AuthEnum,
-                V04_20_1024_01_UserLogin,
-                V04_20_1024_02_RolePermit,
-                V05_20_1025_01_ConfRuntime,
-                V91_22_0222_01_ExampleInit
+            V00_19_0512_01_Schema,
+            V01_19_0520_01_IdLog,
+            V01_19_0521_01_EnumI18n,
+            V03_20_1023_01_AuthEnum,
+            V04_20_1024_01_UserLogin,
+            V04_20_1024_02_RolePermit,
+            V05_20_1025_01_ConfRuntime,
+            V91_22_0222_01_ExampleInit
         );
     }
 }
diff --git a/radiant/devs-codegen/src/test/java/pro/fessional/wings/devs/init/DatabaseFacelessTest.java b/radiant/devs-codegen/src/test/java/pro/fessional/wings/devs/init/DatabaseFacelessTest.java
index 3ef4cd9a3..9ad0b5c2e 100644
--- a/radiant/devs-codegen/src/test/java/pro/fessional/wings/devs/init/DatabaseFacelessTest.java
+++ b/radiant/devs-codegen/src/test/java/pro/fessional/wings/devs/init/DatabaseFacelessTest.java
@@ -27,12 +27,12 @@ public class DatabaseFacelessTest extends TestingDatabase {
     @TmsLink("C14082")
     void resetSchemaWingsFaceless() {
         reset(
-                V00_19_0512_01_Schema,
-                V01_19_0520_01_IdLog,
-                V01_19_0521_01_EnumI18n,
-                V03_20_1023_01_AuthEnum,
-                V90_22_0601_01_TestSchema,
-                V90_22_0601_02_TestRecord
+            V00_19_0512_01_Schema,
+            V01_19_0520_01_IdLog,
+            V01_19_0521_01_EnumI18n,
+            V03_20_1023_01_AuthEnum,
+            V90_22_0601_01_TestSchema,
+            V90_22_0601_02_TestRecord
         );
     }
 }
diff --git a/radiant/devs-codegen/src/test/java/pro/fessional/wings/devs/init/DatabaseShard0Test.java b/radiant/devs-codegen/src/test/java/pro/fessional/wings/devs/init/DatabaseShard0Test.java
index 2601e20e3..9ca6ea220 100644
--- a/radiant/devs-codegen/src/test/java/pro/fessional/wings/devs/init/DatabaseShard0Test.java
+++ b/radiant/devs-codegen/src/test/java/pro/fessional/wings/devs/init/DatabaseShard0Test.java
@@ -25,10 +25,10 @@ public class DatabaseShard0Test extends TestingDatabase {
     @TmsLink("C14083")
     void resetSchemaWingsShard0() {
         reset(
-                V00_19_0512_01_Schema,
-                V01_19_0520_01_IdLog,
-                V90_22_0601_01_TestSchema,
-                V90_22_0601_02_TestRecord
+            V00_19_0512_01_Schema,
+            V01_19_0520_01_IdLog,
+            V90_22_0601_01_TestSchema,
+            V90_22_0601_02_TestRecord
         );
 
         shard("tst_sharding", 5);
diff --git a/radiant/devs-codegen/src/test/java/pro/fessional/wings/devs/init/DatabaseShard1Test.java b/radiant/devs-codegen/src/test/java/pro/fessional/wings/devs/init/DatabaseShard1Test.java
index 64c95c0ad..25c572e07 100644
--- a/radiant/devs-codegen/src/test/java/pro/fessional/wings/devs/init/DatabaseShard1Test.java
+++ b/radiant/devs-codegen/src/test/java/pro/fessional/wings/devs/init/DatabaseShard1Test.java
@@ -23,10 +23,10 @@ public class DatabaseShard1Test extends TestingDatabase {
     @TmsLink("C14084")
     void resetSchemaWingsShard1() {
         reset(
-                V00_19_0512_01_Schema,
-                V01_19_0520_01_IdLog,
-                V90_22_0601_01_TestSchema,
-                V90_22_0601_02_TestRecord
+            V00_19_0512_01_Schema,
+            V01_19_0520_01_IdLog,
+            V90_22_0601_01_TestSchema,
+            V90_22_0601_02_TestRecord
         );
 
         shard("tst_sharding", 5);
diff --git a/radiant/devs-codegen/src/test/java/pro/fessional/wings/devs/init/DatabaseTinyTest.java b/radiant/devs-codegen/src/test/java/pro/fessional/wings/devs/init/DatabaseTinyTest.java
index 79a38850f..1bf96f725 100644
--- a/radiant/devs-codegen/src/test/java/pro/fessional/wings/devs/init/DatabaseTinyTest.java
+++ b/radiant/devs-codegen/src/test/java/pro/fessional/wings/devs/init/DatabaseTinyTest.java
@@ -9,6 +9,7 @@
 import static pro.fessional.wings.faceless.flywave.WingsRevision.V01_19_0520_01_IdLog;
 import static pro.fessional.wings.faceless.flywave.WingsRevision.V06_20_1026_01_TinyTask;
 import static pro.fessional.wings.faceless.flywave.WingsRevision.V07_20_1027_01_TinyMail;
+import static pro.fessional.wings.faceless.flywave.WingsRevision.V08_20_1028_01_TinyGrow;
 
 
 /**
@@ -23,10 +24,11 @@ public class DatabaseTinyTest extends TestingDatabase {
     @TmsLink("C15010")
     void resetSchemaWingsTiny() {
         reset(
-                V00_19_0512_01_Schema,
-                V01_19_0520_01_IdLog,
-                V06_20_1026_01_TinyTask,
-                V07_20_1027_01_TinyMail
+            V00_19_0512_01_Schema,
+            V01_19_0520_01_IdLog,
+            V06_20_1026_01_TinyTask,
+            V07_20_1027_01_TinyMail,
+            V08_20_1028_01_TinyGrow
         );
     }
 }
diff --git a/radiant/devs-codegen/src/test/java/pro/fessional/wings/devs/init/DatabaseWarlockTest.java b/radiant/devs-codegen/src/test/java/pro/fessional/wings/devs/init/DatabaseWarlockTest.java
index 6cf63e5ea..99e43d1f3 100644
--- a/radiant/devs-codegen/src/test/java/pro/fessional/wings/devs/init/DatabaseWarlockTest.java
+++ b/radiant/devs-codegen/src/test/java/pro/fessional/wings/devs/init/DatabaseWarlockTest.java
@@ -26,13 +26,13 @@ public class DatabaseWarlockTest extends TestingDatabase {
     @TmsLink("C14007")
     void resetSchemaWingsWarlock() {
         reset(
-                V00_19_0512_01_Schema,
-                V01_19_0520_01_IdLog,
-                V01_19_0521_01_EnumI18n,
-                V03_20_1023_01_AuthEnum,
-                V04_20_1024_01_UserLogin,
-                V04_20_1024_02_RolePermit,
-                V05_20_1025_01_ConfRuntime
+            V00_19_0512_01_Schema,
+            V01_19_0520_01_IdLog,
+            V01_19_0521_01_EnumI18n,
+            V03_20_1023_01_AuthEnum,
+            V04_20_1024_01_UserLogin,
+            V04_20_1024_02_RolePermit,
+            V05_20_1025_01_ConfRuntime
         );
     }
 }
diff --git a/radiant/devs-codegen/src/test/java/pro/fessional/wings/devs/init/DatabaseWingsTest.java b/radiant/devs-codegen/src/test/java/pro/fessional/wings/devs/init/DatabaseWingsTest.java
index f60b83277..3dbd82269 100644
--- a/radiant/devs-codegen/src/test/java/pro/fessional/wings/devs/init/DatabaseWingsTest.java
+++ b/radiant/devs-codegen/src/test/java/pro/fessional/wings/devs/init/DatabaseWingsTest.java
@@ -14,6 +14,7 @@
 import static pro.fessional.wings.faceless.flywave.WingsRevision.V05_20_1025_01_ConfRuntime;
 import static pro.fessional.wings.faceless.flywave.WingsRevision.V06_20_1026_01_TinyTask;
 import static pro.fessional.wings.faceless.flywave.WingsRevision.V07_20_1027_01_TinyMail;
+import static pro.fessional.wings.faceless.flywave.WingsRevision.V08_20_1028_01_TinyGrow;
 
 
 /**
@@ -27,15 +28,16 @@ public class DatabaseWingsTest extends TestingDatabase {
     @TmsLink("C14081")
     void resetSchemaWings() {
         reset(
-                V00_19_0512_01_Schema,
-                V01_19_0520_01_IdLog,
-                V01_19_0521_01_EnumI18n,
-                V03_20_1023_01_AuthEnum,
-                V04_20_1024_01_UserLogin,
-                V04_20_1024_02_RolePermit,
-                V05_20_1025_01_ConfRuntime,
-                V06_20_1026_01_TinyTask,
-                V07_20_1027_01_TinyMail
+            V00_19_0512_01_Schema,
+            V01_19_0520_01_IdLog,
+            V01_19_0521_01_EnumI18n,
+            V03_20_1023_01_AuthEnum,
+            V04_20_1024_01_UserLogin,
+            V04_20_1024_02_RolePermit,
+            V05_20_1025_01_ConfRuntime,
+            V06_20_1026_01_TinyTask,
+            V07_20_1027_01_TinyMail,
+            V08_20_1028_01_TinyGrow
         );
     }
 }
diff --git a/radiant/devs-codegen/src/test/java/pro/fessional/wings/devs/init/TestingDatabase.java b/radiant/devs-codegen/src/test/java/pro/fessional/wings/devs/init/TestingDatabase.java
index 83bd924c9..ea8bcebfd 100644
--- a/radiant/devs-codegen/src/test/java/pro/fessional/wings/devs/init/TestingDatabase.java
+++ b/radiant/devs-codegen/src/test/java/pro/fessional/wings/devs/init/TestingDatabase.java
@@ -24,13 +24,13 @@
 @Slf4j
 public class TestingDatabase {
 
-    @Setter(onMethod_ = {@Autowired})
+    @Setter(onMethod_ = { @Autowired })
     protected TestingDatabaseHelper testingDatabaseHelper;
-    @Setter(onMethod_ = {@Autowired})
+    @Setter(onMethod_ = { @Autowired })
     protected TestingPropertyHelper testingPropertyHelper;
-    @Setter(onMethod_ = {@Autowired})
+    @Setter(onMethod_ = { @Autowired })
     protected SchemaRevisionManager schemaRevisionManager;
-    @Setter(onMethod_ = {@Autowired})
+    @Setter(onMethod_ = { @Autowired })
     protected SchemaShardingManager schemaShardingManager;
 
     /**
diff --git a/radiant/pom.xml b/radiant/pom.xml
index 26774b98c..87a998045 100644
--- a/radiant/pom.xml
+++ b/radiant/pom.xml
@@ -18,6 +18,7 @@
     Radiant components under GhostShip Model
 
     
+        tiny-grow
         tiny-mail
         tiny-task
     
diff --git a/radiant/tiny-grow/pom.xml b/radiant/tiny-grow/pom.xml
new file mode 100644
index 000000000..407ce54fa
--- /dev/null
+++ b/radiant/tiny-grow/pom.xml
@@ -0,0 +1,47 @@
+
+
+    4.0.0
+
+    
+        pro.fessional.wings
+        radiant
+        ${revision}
+    
+
+    tiny-grow
+    jar
+
+    Radiant::Tiny::Grow
+    Tiny data tracking, growth analysis
+
+    
+        
+            pro.fessional.wings
+            faceless-jooq
+            true
+        
+        
+            pro.fessional.wings
+            slardar-webmvc
+            true
+        
+        
+        
+            pro.fessional.wings
+            faceless-flywave
+            true
+        
+        
+        
+            pro.fessional.wings
+            faceless-codegen
+            test
+        
+        
+            pro.fessional.wings
+            testing-docker
+            test
+        
+    
+
diff --git a/radiant/tiny-grow/src/main/java-gen/pro/fessional/wings/tiny/grow/database/TinyGrowDatabase.java b/radiant/tiny-grow/src/main/java-gen/pro/fessional/wings/tiny/grow/database/TinyGrowDatabase.java
new file mode 100644
index 000000000..cfb3e64b0
--- /dev/null
+++ b/radiant/tiny-grow/src/main/java-gen/pro/fessional/wings/tiny/grow/database/TinyGrowDatabase.java
@@ -0,0 +1,8 @@
+package pro.fessional.wings.tiny.grow.database;
+
+/**
+ * @author trydofor
+ * @since 2023-11-22
+ */
+public interface TinyGrowDatabase {
+}
diff --git a/radiant/tiny-grow/src/main/java-gen/pro/fessional/wings/tiny/grow/database/autogen/DefaultCatalogTinyGrow.java b/radiant/tiny-grow/src/main/java-gen/pro/fessional/wings/tiny/grow/database/autogen/DefaultCatalogTinyGrow.java
new file mode 100644
index 000000000..9f85f9072
--- /dev/null
+++ b/radiant/tiny-grow/src/main/java-gen/pro/fessional/wings/tiny/grow/database/autogen/DefaultCatalogTinyGrow.java
@@ -0,0 +1,47 @@
+/*
+ * This file is generated by jOOQ.
+ */
+package pro.fessional.wings.tiny.grow.database.autogen;
+
+
+import org.jooq.Constants;
+import org.jooq.impl.CatalogImpl;
+
+import javax.annotation.processing.Generated;
+
+
+/**
+ * The catalog .
+ */
+@Generated(
+    value = {
+        "https://www.jooq.org",
+        "jOOQ version:3.18.9"
+    },
+    comments = "This class is generated by jOOQ"
+)
+@SuppressWarnings({ "all", "unchecked", "rawtypes", "this-escape" })
+public class DefaultCatalogTinyGrow extends CatalogImpl {
+
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * The reference instance of DEFAULT_CATALOG
+     */
+    public static final DefaultCatalogTinyGrow DEFAULT_CATALOG = new DefaultCatalogTinyGrow();
+
+    /**
+     * No further instances allowed
+     */
+    private DefaultCatalogTinyGrow() {
+        super("");
+    }
+
+    /**
+     * A reference to the 3.18 minor release of the code generator. If this
+     * doesn't compile, it's because the runtime library uses an older minor
+     * release, namely: 3.18. You can turn off the generation of this reference
+     * by specifying /configuration/generator/generate/jooqVersionReference
+     */
+    private static final String REQUIRE_RUNTIME_JOOQ_VERSION = Constants.VERSION_3_18;
+}
diff --git a/radiant/tiny-grow/src/main/java-gen/pro/fessional/wings/tiny/grow/database/autogen/DefaultSchemaTinyGrow.java b/radiant/tiny-grow/src/main/java-gen/pro/fessional/wings/tiny/grow/database/autogen/DefaultSchemaTinyGrow.java
new file mode 100644
index 000000000..00f04e7ea
--- /dev/null
+++ b/radiant/tiny-grow/src/main/java-gen/pro/fessional/wings/tiny/grow/database/autogen/DefaultSchemaTinyGrow.java
@@ -0,0 +1,62 @@
+/*
+ * This file is generated by jOOQ.
+ */
+package pro.fessional.wings.tiny.grow.database.autogen;
+
+
+import org.jooq.Catalog;
+import org.jooq.Table;
+import org.jooq.impl.SchemaImpl;
+import pro.fessional.wings.tiny.grow.database.autogen.tables.WinGrowTrackTable;
+
+import javax.annotation.processing.Generated;
+import java.util.Arrays;
+import java.util.List;
+
+
+/**
+ * The schema wings.
+ */
+@Generated(
+    value = {
+        "https://www.jooq.org",
+        "jOOQ version:3.18.9",
+        "schema version:2020102801"
+    },
+    comments = "This class is generated by jOOQ"
+)
+@SuppressWarnings({ "all", "unchecked", "rawtypes", "this-escape" })
+public class DefaultSchemaTinyGrow extends SchemaImpl {
+
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * The reference instance of DEFAULT_SCHEMA
+     */
+    public static final DefaultSchemaTinyGrow DEFAULT_SCHEMA = new DefaultSchemaTinyGrow();
+
+    /**
+     * The table win_grow_track.
+     */
+    public final WinGrowTrackTable WinGrowTrack = WinGrowTrackTable.WinGrowTrack;
+
+    /**
+     * No further instances allowed
+     */
+    private DefaultSchemaTinyGrow() {
+        super("", null);
+    }
+
+
+    @Override
+    public Catalog getCatalog() {
+        return DefaultCatalogTinyGrow.DEFAULT_CATALOG;
+    }
+
+    @Override
+    public final List> getTables() {
+        return Arrays.asList(
+            WinGrowTrackTable.WinGrowTrack
+        );
+    }
+}
diff --git a/radiant/tiny-grow/src/main/java-gen/pro/fessional/wings/tiny/grow/database/autogen/TablesTinyGrow.java b/radiant/tiny-grow/src/main/java-gen/pro/fessional/wings/tiny/grow/database/autogen/TablesTinyGrow.java
new file mode 100644
index 000000000..4617b22c0
--- /dev/null
+++ b/radiant/tiny-grow/src/main/java-gen/pro/fessional/wings/tiny/grow/database/autogen/TablesTinyGrow.java
@@ -0,0 +1,30 @@
+/*
+ * This file is generated by jOOQ.
+ */
+package pro.fessional.wings.tiny.grow.database.autogen;
+
+
+import pro.fessional.wings.tiny.grow.database.autogen.tables.WinGrowTrackTable;
+
+import javax.annotation.processing.Generated;
+
+
+/**
+ * Convenience access to all tables in the default schema.
+ */
+@Generated(
+    value = {
+        "https://www.jooq.org",
+        "jOOQ version:3.18.9",
+        "schema version:2020102801"
+    },
+    comments = "This class is generated by jOOQ"
+)
+@SuppressWarnings({ "all", "unchecked", "rawtypes", "this-escape" })
+public class TablesTinyGrow {
+
+    /**
+     * The table win_grow_track.
+     */
+    public static final WinGrowTrackTable WinGrowTrack = WinGrowTrackTable.WinGrowTrack;
+}
diff --git a/radiant/tiny-grow/src/main/java-gen/pro/fessional/wings/tiny/grow/database/autogen/tables/WinGrowTrackTable.java b/radiant/tiny-grow/src/main/java-gen/pro/fessional/wings/tiny/grow/database/autogen/tables/WinGrowTrackTable.java
new file mode 100644
index 000000000..902a859d1
--- /dev/null
+++ b/radiant/tiny-grow/src/main/java-gen/pro/fessional/wings/tiny/grow/database/autogen/tables/WinGrowTrackTable.java
@@ -0,0 +1,277 @@
+/*
+ * This file is generated by jOOQ.
+ */
+package pro.fessional.wings.tiny.grow.database.autogen.tables;
+
+
+import org.jetbrains.annotations.NotNull;
+import org.jooq.Field;
+import org.jooq.Function19;
+import org.jooq.Name;
+import org.jooq.Records;
+import org.jooq.Row19;
+import org.jooq.Schema;
+import org.jooq.SelectField;
+import org.jooq.Table;
+import org.jooq.TableField;
+import org.jooq.TableOptions;
+import org.jooq.UniqueKey;
+import org.jooq.impl.DSL;
+import org.jooq.impl.Internal;
+import org.jooq.impl.SQLDataType;
+import org.jooq.impl.TableImpl;
+import pro.fessional.wings.faceless.database.jooq.WingsJournalTable;
+import pro.fessional.wings.faceless.service.lightid.LightIdAware;
+import pro.fessional.wings.tiny.grow.database.autogen.DefaultSchemaTinyGrow;
+import pro.fessional.wings.tiny.grow.database.autogen.tables.records.WinGrowTrackRecord;
+
+import javax.annotation.processing.Generated;
+import java.time.LocalDateTime;
+import java.util.function.Function;
+
+
+/**
+ * The table wings.win_grow_track.
+ */
+@Generated(
+    value = {
+        "https://www.jooq.org",
+        "jOOQ version:3.18.9",
+        "schema version:2020102801"
+    },
+    comments = "This class is generated by jOOQ"
+)
+@SuppressWarnings({ "all", "unchecked", "rawtypes", "this-escape" })
+public class WinGrowTrackTable extends TableImpl implements WingsJournalTable, LightIdAware {
+
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * The reference instance of win_grow_track
+     */
+    public static final WinGrowTrackTable WinGrowTrack = new WinGrowTrackTable();
+    public static final WinGrowTrackTable asK2 = WinGrowTrack.as(pro.fessional.wings.faceless.database.jooq.WingsJooqEnv.uniqueAlias());
+
+    /**
+     * The class holding records for this type
+     */
+    @Override
+    public Class getRecordType() {
+        return WinGrowTrackRecord.class;
+    }
+
+    /**
+     * The column win_grow_track.id.
+     */
+    public final TableField Id = createField(DSL.name("id"), SQLDataType.BIGINT.nullable(false), this, "");
+
+    /**
+     * The column win_grow_track.create_dt.
+     */
+    public final TableField CreateDt = createField(DSL.name("create_dt"), SQLDataType.LOCALDATETIME(3).nullable(false).defaultValue(DSL.field(DSL.raw("CURRENT_TIMESTAMP(3)"), SQLDataType.LOCALDATETIME)), this, "");
+
+    /**
+     * The column win_grow_track.track_key.
+     */
+    public final TableField TrackKey = createField(DSL.name("track_key"), SQLDataType.VARCHAR(500).nullable(false).defaultValue(DSL.inline("", SQLDataType.VARCHAR)), this, "");
+
+    /**
+     * The column win_grow_track.track_ref.
+     */
+    public final TableField TrackRef = createField(DSL.name("track_ref"), SQLDataType.VARCHAR(100).nullable(false).defaultValue(DSL.inline("", SQLDataType.VARCHAR)), this, "");
+
+    /**
+     * The column win_grow_track.track_app.
+     */
+    public final TableField TrackApp = createField(DSL.name("track_app"), SQLDataType.VARCHAR(100).nullable(false).defaultValue(DSL.inline("", SQLDataType.VARCHAR)), this, "");
+
+    /**
+     * The column win_grow_track.track_env.
+     */
+    public final TableField TrackEnv = createField(DSL.name("track_env"), SQLDataType.CLOB, this, "");
+
+    /**
+     * The column win_grow_track.track_ins.
+     */
+    public final TableField TrackIns = createField(DSL.name("track_ins"), SQLDataType.CLOB, this, "");
+
+    /**
+     * The column win_grow_track.track_out.
+     */
+    public final TableField TrackOut = createField(DSL.name("track_out"), SQLDataType.CLOB, this, "");
+
+    /**
+     * The column win_grow_track.track_err.
+     */
+    public final TableField TrackErr = createField(DSL.name("track_err"), SQLDataType.CLOB, this, "");
+
+    /**
+     * The column win_grow_track.elapse_ms.
+     */
+    public final TableField ElapseMs = createField(DSL.name("elapse_ms"), SQLDataType.BIGINT.nullable(false).defaultValue(DSL.inline("0", SQLDataType.BIGINT)), this, "");
+
+    /**
+     * The column win_grow_track.user_key.
+     */
+    public final TableField UserKey = createField(DSL.name("user_key"), SQLDataType.BIGINT.nullable(false).defaultValue(DSL.inline("0", SQLDataType.BIGINT)), this, "");
+
+    /**
+     * The column win_grow_track.user_ref.
+     */
+    public final TableField UserRef = createField(DSL.name("user_ref"), SQLDataType.BIGINT.nullable(false).defaultValue(DSL.inline("0", SQLDataType.BIGINT)), this, "");
+
+    /**
+     * The column win_grow_track.data_key.
+     */
+    public final TableField DataKey = createField(DSL.name("data_key"), SQLDataType.BIGINT.nullable(false).defaultValue(DSL.inline("0", SQLDataType.BIGINT)), this, "");
+
+    /**
+     * The column win_grow_track.data_ref.
+     */
+    public final TableField DataRef = createField(DSL.name("data_ref"), SQLDataType.BIGINT.nullable(false).defaultValue(DSL.inline("0", SQLDataType.BIGINT)), this, "");
+
+    /**
+     * The column win_grow_track.data_opt.
+     */
+    public final TableField DataOpt = createField(DSL.name("data_opt"), SQLDataType.BIGINT.nullable(false).defaultValue(DSL.inline("0", SQLDataType.BIGINT)), this, "");
+
+    /**
+     * The column win_grow_track.code_key.
+     */
+    public final TableField CodeKey = createField(DSL.name("code_key"), SQLDataType.VARCHAR(100).nullable(false).defaultValue(DSL.inline("", SQLDataType.VARCHAR)), this, "");
+
+    /**
+     * The column win_grow_track.code_ref.
+     */
+    public final TableField CodeRef = createField(DSL.name("code_ref"), SQLDataType.VARCHAR(100).nullable(false).defaultValue(DSL.inline("", SQLDataType.VARCHAR)), this, "");
+
+    /**
+     * The column win_grow_track.code_opt.
+     */
+    public final TableField CodeOpt = createField(DSL.name("code_opt"), SQLDataType.VARCHAR(100).nullable(false).defaultValue(DSL.inline("", SQLDataType.VARCHAR)), this, "");
+
+    /**
+     * The column win_grow_track.word_ref.
+     */
+    public final TableField WordRef = createField(DSL.name("word_ref"), SQLDataType.VARCHAR(800).nullable(false).defaultValue(DSL.inline("", SQLDataType.VARCHAR)), this, "");
+
+    private WinGrowTrackTable(Name alias, Table aliased) {
+        this(alias, aliased, null);
+    }
+
+    private WinGrowTrackTable(Name alias, Table aliased, Field[] parameters) {
+        super(alias, null, aliased, parameters, DSL.comment(""), TableOptions.table());
+    }
+
+    /**
+     * Create an aliased win_grow_track table reference
+     */
+    public WinGrowTrackTable(String alias) {
+        this(DSL.name(alias), WinGrowTrack);
+    }
+
+    /**
+     * Create an aliased win_grow_track table reference
+     */
+    public WinGrowTrackTable(Name alias) {
+        this(alias, WinGrowTrack);
+    }
+
+    /**
+     * Create a win_grow_track table reference
+     */
+    public WinGrowTrackTable() {
+        this(DSL.name("win_grow_track"), null);
+    }
+
+    @Override
+    public Schema getSchema() {
+        return aliased() ? null : DefaultSchemaTinyGrow.DEFAULT_SCHEMA;
+    }
+
+    @Override
+    public UniqueKey getPrimaryKey() {
+        return Internal.createUniqueKey(WinGrowTrackTable.WinGrowTrack, DSL.name("KEY_win_grow_track_PRIMARY"), new TableField[] { WinGrowTrackTable.WinGrowTrack.Id }, true);
+    }
+
+    @Override
+    public WinGrowTrackTable as(String alias) {
+        return new WinGrowTrackTable(DSL.name(alias), this);
+    }
+
+    @Override
+    public WinGrowTrackTable as(Name alias) {
+        return new WinGrowTrackTable(alias, this);
+    }
+
+    @Override
+    public WinGrowTrackTable as(Table alias) {
+        return new WinGrowTrackTable(alias.getQualifiedName(), this);
+    }
+
+    /**
+     * Rename this table
+     */
+    @Override
+    public WinGrowTrackTable rename(String name) {
+        return new WinGrowTrackTable(DSL.name(name), null);
+    }
+
+    /**
+     * Rename this table
+     */
+    @Override
+    public WinGrowTrackTable rename(Name name) {
+        return new WinGrowTrackTable(name, null);
+    }
+
+    /**
+     * Rename this table
+     */
+    @Override
+    public WinGrowTrackTable rename(Table name) {
+        return new WinGrowTrackTable(name.getQualifiedName(), null);
+    }
+
+    // -------------------------------------------------------------------------
+    // Row19 type methods
+    // -------------------------------------------------------------------------
+
+    @Override
+    public Row19 fieldsRow() {
+        return (Row19) super.fieldsRow();
+    }
+
+    /**
+     * Convenience mapping calling {@link SelectField#convertFrom(Function)}.
+     */
+    public  SelectField mapping(Function19 from) {
+        return convertFrom(Records.mapping(from));
+    }
+
+    /**
+     * Convenience mapping calling {@link SelectField#convertFrom(Class,
+     * Function)}.
+     */
+    public  SelectField mapping(Class toType, Function19 from) {
+        return convertFrom(toType, Records.mapping(from));
+    }
+
+    /**
+     * LightIdAware seqName
+     */
+    @Override
+    @NotNull
+    public String getSeqName() {
+        return "win_grow_track";
+    }
+
+    /**
+     * alias asK2
+     */
+    @Override
+    @NotNull
+    public WinGrowTrackTable getAliasTable() {
+        return asK2;
+    }
+}
diff --git a/radiant/tiny-grow/src/main/java-gen/pro/fessional/wings/tiny/grow/database/autogen/tables/daos/WinGrowTrackDao.java b/radiant/tiny-grow/src/main/java-gen/pro/fessional/wings/tiny/grow/database/autogen/tables/daos/WinGrowTrackDao.java
new file mode 100644
index 000000000..49b21bda8
--- /dev/null
+++ b/radiant/tiny-grow/src/main/java-gen/pro/fessional/wings/tiny/grow/database/autogen/tables/daos/WinGrowTrackDao.java
@@ -0,0 +1,709 @@
+/*
+ * This file is generated by jOOQ.
+ */
+package pro.fessional.wings.tiny.grow.database.autogen.tables.daos;
+
+
+import org.jooq.Configuration;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Repository;
+import pro.fessional.wings.faceless.database.jooq.WingsJooqDaoJournalImpl;
+import pro.fessional.wings.silencer.spring.boot.ConditionalWingsEnabled;
+import pro.fessional.wings.tiny.grow.database.autogen.tables.WinGrowTrackTable;
+import pro.fessional.wings.tiny.grow.database.autogen.tables.pojos.WinGrowTrack;
+import pro.fessional.wings.tiny.grow.database.autogen.tables.records.WinGrowTrackRecord;
+
+import javax.annotation.processing.Generated;
+import java.time.LocalDateTime;
+import java.util.Collection;
+import java.util.List;
+import java.util.Optional;
+
+
+/**
+ * The table wings.win_grow_track.
+ */
+@Generated(
+    value = {
+        "https://www.jooq.org",
+        "jOOQ version:3.18.9",
+        "schema version:2020102801"
+    },
+    comments = "This class is generated by jOOQ"
+)
+@SuppressWarnings({ "all", "unchecked", "rawtypes", "this-escape" })
+@Repository
+@ConditionalWingsEnabled
+public class WinGrowTrackDao extends WingsJooqDaoJournalImpl {
+
+    /**
+     * Create a new WinGrowTrackDao without any configuration
+     */
+    public WinGrowTrackDao() {
+        super(WinGrowTrackTable.WinGrowTrack, WinGrowTrack.class);
+    }
+
+    /**
+     * Create a new WinGrowTrackDao with an attached configuration
+     */
+    @Autowired
+    public WinGrowTrackDao(Configuration configuration) {
+        super(WinGrowTrackTable.WinGrowTrack, WinGrowTrack.class, configuration);
+    }
+
+    @Override
+    public Long getId(WinGrowTrack object) {
+        return object.getId();
+    }
+
+    /**
+     * Fetch records that have id BETWEEN lowerInclusive AND
+     * upperInclusive
+     */
+    public List fetchRangeOfId(Long lowerInclusive, Long upperInclusive) {
+        return fetchRange(WinGrowTrackTable.WinGrowTrack.Id, lowerInclusive, upperInclusive);
+    }
+
+
+    public List fetchRangeOfIdLive(Long lowerInclusive, Long upperInclusive) {
+        return fetchRangeLive(WinGrowTrackTable.WinGrowTrack.Id, lowerInclusive, upperInclusive);
+    }
+
+    /**
+     * Fetch records that have id IN (values)
+     */
+    public List fetchById(Long... values) {
+        return fetch(WinGrowTrackTable.WinGrowTrack.Id, values);
+    }
+
+    public List fetchById(Collection values) {
+        return fetch(WinGrowTrackTable.WinGrowTrack.Id, values);
+    }
+
+
+    public List fetchByIdLive(Long... values) {
+        return fetchLive(WinGrowTrackTable.WinGrowTrack.Id, values);
+    }
+
+    public List fetchByIdLive(Collection values) {
+        return fetchLive(WinGrowTrackTable.WinGrowTrack.Id, values);
+    }
+
+    /**
+     * Fetch a unique record that has id = value
+     */
+    public WinGrowTrack fetchOneById(Long value) {
+        return fetchOne(WinGrowTrackTable.WinGrowTrack.Id, value);
+    }
+
+
+    public WinGrowTrack fetchOneByIdLive(Long value) {
+        return fetchOneLive(WinGrowTrackTable.WinGrowTrack.Id, value);
+    }
+
+    /**
+     * Fetch a unique record that has id = value
+     */
+    public Optional fetchOptionalById(Long value) {
+        return fetchOptional(WinGrowTrackTable.WinGrowTrack.Id, value);
+    }
+
+
+    public Optional fetchOptionalByIdLive(Long value) {
+        return fetchOptionalLive(WinGrowTrackTable.WinGrowTrack.Id, value);
+    }
+
+    /**
+     * Fetch records that have create_dt BETWEEN lowerInclusive AND
+     * upperInclusive
+     */
+    public List fetchRangeOfCreateDt(LocalDateTime lowerInclusive, LocalDateTime upperInclusive) {
+        return fetchRange(WinGrowTrackTable.WinGrowTrack.CreateDt, lowerInclusive, upperInclusive);
+    }
+
+
+    public List fetchRangeOfCreateDtLive(LocalDateTime lowerInclusive, LocalDateTime upperInclusive) {
+        return fetchRangeLive(WinGrowTrackTable.WinGrowTrack.CreateDt, lowerInclusive, upperInclusive);
+    }
+
+    /**
+     * Fetch records that have create_dt IN (values)
+     */
+    public List fetchByCreateDt(LocalDateTime... values) {
+        return fetch(WinGrowTrackTable.WinGrowTrack.CreateDt, values);
+    }
+
+    public List fetchByCreateDt(Collection values) {
+        return fetch(WinGrowTrackTable.WinGrowTrack.CreateDt, values);
+    }
+
+
+    public List fetchByCreateDtLive(LocalDateTime... values) {
+        return fetchLive(WinGrowTrackTable.WinGrowTrack.CreateDt, values);
+    }
+
+    public List fetchByCreateDtLive(Collection values) {
+        return fetchLive(WinGrowTrackTable.WinGrowTrack.CreateDt, values);
+    }
+
+    /**
+     * Fetch records that have track_key BETWEEN lowerInclusive AND
+     * upperInclusive
+     */
+    public List fetchRangeOfTrackKey(String lowerInclusive, String upperInclusive) {
+        return fetchRange(WinGrowTrackTable.WinGrowTrack.TrackKey, lowerInclusive, upperInclusive);
+    }
+
+
+    public List fetchRangeOfTrackKeyLive(String lowerInclusive, String upperInclusive) {
+        return fetchRangeLive(WinGrowTrackTable.WinGrowTrack.TrackKey, lowerInclusive, upperInclusive);
+    }
+
+    /**
+     * Fetch records that have track_key IN (values)
+     */
+    public List fetchByTrackKey(String... values) {
+        return fetch(WinGrowTrackTable.WinGrowTrack.TrackKey, values);
+    }
+
+    public List fetchByTrackKey(Collection values) {
+        return fetch(WinGrowTrackTable.WinGrowTrack.TrackKey, values);
+    }
+
+
+    public List fetchByTrackKeyLive(String... values) {
+        return fetchLive(WinGrowTrackTable.WinGrowTrack.TrackKey, values);
+    }
+
+    public List fetchByTrackKeyLive(Collection values) {
+        return fetchLive(WinGrowTrackTable.WinGrowTrack.TrackKey, values);
+    }
+
+    /**
+     * Fetch records that have track_ref BETWEEN lowerInclusive AND
+     * upperInclusive
+     */
+    public List fetchRangeOfTrackRef(String lowerInclusive, String upperInclusive) {
+        return fetchRange(WinGrowTrackTable.WinGrowTrack.TrackRef, lowerInclusive, upperInclusive);
+    }
+
+
+    public List fetchRangeOfTrackRefLive(String lowerInclusive, String upperInclusive) {
+        return fetchRangeLive(WinGrowTrackTable.WinGrowTrack.TrackRef, lowerInclusive, upperInclusive);
+    }
+
+    /**
+     * Fetch records that have track_ref IN (values)
+     */
+    public List fetchByTrackRef(String... values) {
+        return fetch(WinGrowTrackTable.WinGrowTrack.TrackRef, values);
+    }
+
+    public List fetchByTrackRef(Collection values) {
+        return fetch(WinGrowTrackTable.WinGrowTrack.TrackRef, values);
+    }
+
+
+    public List fetchByTrackRefLive(String... values) {
+        return fetchLive(WinGrowTrackTable.WinGrowTrack.TrackRef, values);
+    }
+
+    public List fetchByTrackRefLive(Collection values) {
+        return fetchLive(WinGrowTrackTable.WinGrowTrack.TrackRef, values);
+    }
+
+    /**
+     * Fetch records that have track_app BETWEEN lowerInclusive AND
+     * upperInclusive
+     */
+    public List fetchRangeOfTrackApp(String lowerInclusive, String upperInclusive) {
+        return fetchRange(WinGrowTrackTable.WinGrowTrack.TrackApp, lowerInclusive, upperInclusive);
+    }
+
+
+    public List fetchRangeOfTrackAppLive(String lowerInclusive, String upperInclusive) {
+        return fetchRangeLive(WinGrowTrackTable.WinGrowTrack.TrackApp, lowerInclusive, upperInclusive);
+    }
+
+    /**
+     * Fetch records that have track_app IN (values)
+     */
+    public List fetchByTrackApp(String... values) {
+        return fetch(WinGrowTrackTable.WinGrowTrack.TrackApp, values);
+    }
+
+    public List fetchByTrackApp(Collection values) {
+        return fetch(WinGrowTrackTable.WinGrowTrack.TrackApp, values);
+    }
+
+
+    public List fetchByTrackAppLive(String... values) {
+        return fetchLive(WinGrowTrackTable.WinGrowTrack.TrackApp, values);
+    }
+
+    public List fetchByTrackAppLive(Collection values) {
+        return fetchLive(WinGrowTrackTable.WinGrowTrack.TrackApp, values);
+    }
+
+    /**
+     * Fetch records that have track_env BETWEEN lowerInclusive AND
+     * upperInclusive
+     */
+    public List fetchRangeOfTrackEnv(String lowerInclusive, String upperInclusive) {
+        return fetchRange(WinGrowTrackTable.WinGrowTrack.TrackEnv, lowerInclusive, upperInclusive);
+    }
+
+
+    public List fetchRangeOfTrackEnvLive(String lowerInclusive, String upperInclusive) {
+        return fetchRangeLive(WinGrowTrackTable.WinGrowTrack.TrackEnv, lowerInclusive, upperInclusive);
+    }
+
+    /**
+     * Fetch records that have track_env IN (values)
+     */
+    public List fetchByTrackEnv(String... values) {
+        return fetch(WinGrowTrackTable.WinGrowTrack.TrackEnv, values);
+    }
+
+    public List fetchByTrackEnv(Collection values) {
+        return fetch(WinGrowTrackTable.WinGrowTrack.TrackEnv, values);
+    }
+
+
+    public List fetchByTrackEnvLive(String... values) {
+        return fetchLive(WinGrowTrackTable.WinGrowTrack.TrackEnv, values);
+    }
+
+    public List fetchByTrackEnvLive(Collection values) {
+        return fetchLive(WinGrowTrackTable.WinGrowTrack.TrackEnv, values);
+    }
+
+    /**
+     * Fetch records that have track_ins BETWEEN lowerInclusive AND
+     * upperInclusive
+     */
+    public List fetchRangeOfTrackIns(String lowerInclusive, String upperInclusive) {
+        return fetchRange(WinGrowTrackTable.WinGrowTrack.TrackIns, lowerInclusive, upperInclusive);
+    }
+
+
+    public List fetchRangeOfTrackInsLive(String lowerInclusive, String upperInclusive) {
+        return fetchRangeLive(WinGrowTrackTable.WinGrowTrack.TrackIns, lowerInclusive, upperInclusive);
+    }
+
+    /**
+     * Fetch records that have track_ins IN (values)
+     */
+    public List fetchByTrackIns(String... values) {
+        return fetch(WinGrowTrackTable.WinGrowTrack.TrackIns, values);
+    }
+
+    public List fetchByTrackIns(Collection values) {
+        return fetch(WinGrowTrackTable.WinGrowTrack.TrackIns, values);
+    }
+
+
+    public List fetchByTrackInsLive(String... values) {
+        return fetchLive(WinGrowTrackTable.WinGrowTrack.TrackIns, values);
+    }
+
+    public List fetchByTrackInsLive(Collection values) {
+        return fetchLive(WinGrowTrackTable.WinGrowTrack.TrackIns, values);
+    }
+
+    /**
+     * Fetch records that have track_out BETWEEN lowerInclusive AND
+     * upperInclusive
+     */
+    public List fetchRangeOfTrackOut(String lowerInclusive, String upperInclusive) {
+        return fetchRange(WinGrowTrackTable.WinGrowTrack.TrackOut, lowerInclusive, upperInclusive);
+    }
+
+
+    public List fetchRangeOfTrackOutLive(String lowerInclusive, String upperInclusive) {
+        return fetchRangeLive(WinGrowTrackTable.WinGrowTrack.TrackOut, lowerInclusive, upperInclusive);
+    }
+
+    /**
+     * Fetch records that have track_out IN (values)
+     */
+    public List fetchByTrackOut(String... values) {
+        return fetch(WinGrowTrackTable.WinGrowTrack.TrackOut, values);
+    }
+
+    public List fetchByTrackOut(Collection values) {
+        return fetch(WinGrowTrackTable.WinGrowTrack.TrackOut, values);
+    }
+
+
+    public List fetchByTrackOutLive(String... values) {
+        return fetchLive(WinGrowTrackTable.WinGrowTrack.TrackOut, values);
+    }
+
+    public List fetchByTrackOutLive(Collection values) {
+        return fetchLive(WinGrowTrackTable.WinGrowTrack.TrackOut, values);
+    }
+
+    /**
+     * Fetch records that have track_err BETWEEN lowerInclusive AND
+     * upperInclusive
+     */
+    public List fetchRangeOfTrackErr(String lowerInclusive, String upperInclusive) {
+        return fetchRange(WinGrowTrackTable.WinGrowTrack.TrackErr, lowerInclusive, upperInclusive);
+    }
+
+
+    public List fetchRangeOfTrackErrLive(String lowerInclusive, String upperInclusive) {
+        return fetchRangeLive(WinGrowTrackTable.WinGrowTrack.TrackErr, lowerInclusive, upperInclusive);
+    }
+
+    /**
+     * Fetch records that have track_err IN (values)
+     */
+    public List fetchByTrackErr(String... values) {
+        return fetch(WinGrowTrackTable.WinGrowTrack.TrackErr, values);
+    }
+
+    public List fetchByTrackErr(Collection values) {
+        return fetch(WinGrowTrackTable.WinGrowTrack.TrackErr, values);
+    }
+
+
+    public List fetchByTrackErrLive(String... values) {
+        return fetchLive(WinGrowTrackTable.WinGrowTrack.TrackErr, values);
+    }
+
+    public List fetchByTrackErrLive(Collection values) {
+        return fetchLive(WinGrowTrackTable.WinGrowTrack.TrackErr, values);
+    }
+
+    /**
+     * Fetch records that have elapse_ms BETWEEN lowerInclusive AND
+     * upperInclusive
+     */
+    public List fetchRangeOfElapseMs(Long lowerInclusive, Long upperInclusive) {
+        return fetchRange(WinGrowTrackTable.WinGrowTrack.ElapseMs, lowerInclusive, upperInclusive);
+    }
+
+
+    public List fetchRangeOfElapseMsLive(Long lowerInclusive, Long upperInclusive) {
+        return fetchRangeLive(WinGrowTrackTable.WinGrowTrack.ElapseMs, lowerInclusive, upperInclusive);
+    }
+
+    /**
+     * Fetch records that have elapse_ms IN (values)
+     */
+    public List fetchByElapseMs(Long... values) {
+        return fetch(WinGrowTrackTable.WinGrowTrack.ElapseMs, values);
+    }
+
+    public List fetchByElapseMs(Collection values) {
+        return fetch(WinGrowTrackTable.WinGrowTrack.ElapseMs, values);
+    }
+
+
+    public List fetchByElapseMsLive(Long... values) {
+        return fetchLive(WinGrowTrackTable.WinGrowTrack.ElapseMs, values);
+    }
+
+    public List fetchByElapseMsLive(Collection values) {
+        return fetchLive(WinGrowTrackTable.WinGrowTrack.ElapseMs, values);
+    }
+
+    /**
+     * Fetch records that have user_key BETWEEN lowerInclusive AND
+     * upperInclusive
+     */
+    public List fetchRangeOfUserKey(Long lowerInclusive, Long upperInclusive) {
+        return fetchRange(WinGrowTrackTable.WinGrowTrack.UserKey, lowerInclusive, upperInclusive);
+    }
+
+
+    public List fetchRangeOfUserKeyLive(Long lowerInclusive, Long upperInclusive) {
+        return fetchRangeLive(WinGrowTrackTable.WinGrowTrack.UserKey, lowerInclusive, upperInclusive);
+    }
+
+    /**
+     * Fetch records that have user_key IN (values)
+     */
+    public List fetchByUserKey(Long... values) {
+        return fetch(WinGrowTrackTable.WinGrowTrack.UserKey, values);
+    }
+
+    public List fetchByUserKey(Collection values) {
+        return fetch(WinGrowTrackTable.WinGrowTrack.UserKey, values);
+    }
+
+
+    public List fetchByUserKeyLive(Long... values) {
+        return fetchLive(WinGrowTrackTable.WinGrowTrack.UserKey, values);
+    }
+
+    public List fetchByUserKeyLive(Collection values) {
+        return fetchLive(WinGrowTrackTable.WinGrowTrack.UserKey, values);
+    }
+
+    /**
+     * Fetch records that have user_ref BETWEEN lowerInclusive AND
+     * upperInclusive
+     */
+    public List fetchRangeOfUserRef(Long lowerInclusive, Long upperInclusive) {
+        return fetchRange(WinGrowTrackTable.WinGrowTrack.UserRef, lowerInclusive, upperInclusive);
+    }
+
+
+    public List fetchRangeOfUserRefLive(Long lowerInclusive, Long upperInclusive) {
+        return fetchRangeLive(WinGrowTrackTable.WinGrowTrack.UserRef, lowerInclusive, upperInclusive);
+    }
+
+    /**
+     * Fetch records that have user_ref IN (values)
+     */
+    public List fetchByUserRef(Long... values) {
+        return fetch(WinGrowTrackTable.WinGrowTrack.UserRef, values);
+    }
+
+    public List fetchByUserRef(Collection values) {
+        return fetch(WinGrowTrackTable.WinGrowTrack.UserRef, values);
+    }
+
+
+    public List fetchByUserRefLive(Long... values) {
+        return fetchLive(WinGrowTrackTable.WinGrowTrack.UserRef, values);
+    }
+
+    public List fetchByUserRefLive(Collection values) {
+        return fetchLive(WinGrowTrackTable.WinGrowTrack.UserRef, values);
+    }
+
+    /**
+     * Fetch records that have data_key BETWEEN lowerInclusive AND
+     * upperInclusive
+     */
+    public List fetchRangeOfDataKey(Long lowerInclusive, Long upperInclusive) {
+        return fetchRange(WinGrowTrackTable.WinGrowTrack.DataKey, lowerInclusive, upperInclusive);
+    }
+
+
+    public List fetchRangeOfDataKeyLive(Long lowerInclusive, Long upperInclusive) {
+        return fetchRangeLive(WinGrowTrackTable.WinGrowTrack.DataKey, lowerInclusive, upperInclusive);
+    }
+
+    /**
+     * Fetch records that have data_key IN (values)
+     */
+    public List fetchByDataKey(Long... values) {
+        return fetch(WinGrowTrackTable.WinGrowTrack.DataKey, values);
+    }
+
+    public List fetchByDataKey(Collection values) {
+        return fetch(WinGrowTrackTable.WinGrowTrack.DataKey, values);
+    }
+
+
+    public List fetchByDataKeyLive(Long... values) {
+        return fetchLive(WinGrowTrackTable.WinGrowTrack.DataKey, values);
+    }
+
+    public List fetchByDataKeyLive(Collection values) {
+        return fetchLive(WinGrowTrackTable.WinGrowTrack.DataKey, values);
+    }
+
+    /**
+     * Fetch records that have data_ref BETWEEN lowerInclusive AND
+     * upperInclusive
+     */
+    public List fetchRangeOfDataRef(Long lowerInclusive, Long upperInclusive) {
+        return fetchRange(WinGrowTrackTable.WinGrowTrack.DataRef, lowerInclusive, upperInclusive);
+    }
+
+
+    public List fetchRangeOfDataRefLive(Long lowerInclusive, Long upperInclusive) {
+        return fetchRangeLive(WinGrowTrackTable.WinGrowTrack.DataRef, lowerInclusive, upperInclusive);
+    }
+
+    /**
+     * Fetch records that have data_ref IN (values)
+     */
+    public List fetchByDataRef(Long... values) {
+        return fetch(WinGrowTrackTable.WinGrowTrack.DataRef, values);
+    }
+
+    public List fetchByDataRef(Collection values) {
+        return fetch(WinGrowTrackTable.WinGrowTrack.DataRef, values);
+    }
+
+
+    public List fetchByDataRefLive(Long... values) {
+        return fetchLive(WinGrowTrackTable.WinGrowTrack.DataRef, values);
+    }
+
+    public List fetchByDataRefLive(Collection values) {
+        return fetchLive(WinGrowTrackTable.WinGrowTrack.DataRef, values);
+    }
+
+    /**
+     * Fetch records that have data_opt BETWEEN lowerInclusive AND
+     * upperInclusive
+     */
+    public List fetchRangeOfDataOpt(Long lowerInclusive, Long upperInclusive) {
+        return fetchRange(WinGrowTrackTable.WinGrowTrack.DataOpt, lowerInclusive, upperInclusive);
+    }
+
+
+    public List fetchRangeOfDataOptLive(Long lowerInclusive, Long upperInclusive) {
+        return fetchRangeLive(WinGrowTrackTable.WinGrowTrack.DataOpt, lowerInclusive, upperInclusive);
+    }
+
+    /**
+     * Fetch records that have data_opt IN (values)
+     */
+    public List fetchByDataOpt(Long... values) {
+        return fetch(WinGrowTrackTable.WinGrowTrack.DataOpt, values);
+    }
+
+    public List fetchByDataOpt(Collection values) {
+        return fetch(WinGrowTrackTable.WinGrowTrack.DataOpt, values);
+    }
+
+
+    public List fetchByDataOptLive(Long... values) {
+        return fetchLive(WinGrowTrackTable.WinGrowTrack.DataOpt, values);
+    }
+
+    public List fetchByDataOptLive(Collection values) {
+        return fetchLive(WinGrowTrackTable.WinGrowTrack.DataOpt, values);
+    }
+
+    /**
+     * Fetch records that have code_key BETWEEN lowerInclusive AND
+     * upperInclusive
+     */
+    public List fetchRangeOfCodeKey(String lowerInclusive, String upperInclusive) {
+        return fetchRange(WinGrowTrackTable.WinGrowTrack.CodeKey, lowerInclusive, upperInclusive);
+    }
+
+
+    public List fetchRangeOfCodeKeyLive(String lowerInclusive, String upperInclusive) {
+        return fetchRangeLive(WinGrowTrackTable.WinGrowTrack.CodeKey, lowerInclusive, upperInclusive);
+    }
+
+    /**
+     * Fetch records that have code_key IN (values)
+     */
+    public List fetchByCodeKey(String... values) {
+        return fetch(WinGrowTrackTable.WinGrowTrack.CodeKey, values);
+    }
+
+    public List fetchByCodeKey(Collection values) {
+        return fetch(WinGrowTrackTable.WinGrowTrack.CodeKey, values);
+    }
+
+
+    public List fetchByCodeKeyLive(String... values) {
+        return fetchLive(WinGrowTrackTable.WinGrowTrack.CodeKey, values);
+    }
+
+    public List fetchByCodeKeyLive(Collection values) {
+        return fetchLive(WinGrowTrackTable.WinGrowTrack.CodeKey, values);
+    }
+
+    /**
+     * Fetch records that have code_ref BETWEEN lowerInclusive AND
+     * upperInclusive
+     */
+    public List fetchRangeOfCodeRef(String lowerInclusive, String upperInclusive) {
+        return fetchRange(WinGrowTrackTable.WinGrowTrack.CodeRef, lowerInclusive, upperInclusive);
+    }
+
+
+    public List fetchRangeOfCodeRefLive(String lowerInclusive, String upperInclusive) {
+        return fetchRangeLive(WinGrowTrackTable.WinGrowTrack.CodeRef, lowerInclusive, upperInclusive);
+    }
+
+    /**
+     * Fetch records that have code_ref IN (values)
+     */
+    public List fetchByCodeRef(String... values) {
+        return fetch(WinGrowTrackTable.WinGrowTrack.CodeRef, values);
+    }
+
+    public List fetchByCodeRef(Collection values) {
+        return fetch(WinGrowTrackTable.WinGrowTrack.CodeRef, values);
+    }
+
+
+    public List fetchByCodeRefLive(String... values) {
+        return fetchLive(WinGrowTrackTable.WinGrowTrack.CodeRef, values);
+    }
+
+    public List fetchByCodeRefLive(Collection values) {
+        return fetchLive(WinGrowTrackTable.WinGrowTrack.CodeRef, values);
+    }
+
+    /**
+     * Fetch records that have code_opt BETWEEN lowerInclusive AND
+     * upperInclusive
+     */
+    public List fetchRangeOfCodeOpt(String lowerInclusive, String upperInclusive) {
+        return fetchRange(WinGrowTrackTable.WinGrowTrack.CodeOpt, lowerInclusive, upperInclusive);
+    }
+
+
+    public List fetchRangeOfCodeOptLive(String lowerInclusive, String upperInclusive) {
+        return fetchRangeLive(WinGrowTrackTable.WinGrowTrack.CodeOpt, lowerInclusive, upperInclusive);
+    }
+
+    /**
+     * Fetch records that have code_opt IN (values)
+     */
+    public List fetchByCodeOpt(String... values) {
+        return fetch(WinGrowTrackTable.WinGrowTrack.CodeOpt, values);
+    }
+
+    public List fetchByCodeOpt(Collection values) {
+        return fetch(WinGrowTrackTable.WinGrowTrack.CodeOpt, values);
+    }
+
+
+    public List fetchByCodeOptLive(String... values) {
+        return fetchLive(WinGrowTrackTable.WinGrowTrack.CodeOpt, values);
+    }
+
+    public List fetchByCodeOptLive(Collection values) {
+        return fetchLive(WinGrowTrackTable.WinGrowTrack.CodeOpt, values);
+    }
+
+    /**
+     * Fetch records that have word_ref BETWEEN lowerInclusive AND
+     * upperInclusive
+     */
+    public List fetchRangeOfWordRef(String lowerInclusive, String upperInclusive) {
+        return fetchRange(WinGrowTrackTable.WinGrowTrack.WordRef, lowerInclusive, upperInclusive);
+    }
+
+
+    public List fetchRangeOfWordRefLive(String lowerInclusive, String upperInclusive) {
+        return fetchRangeLive(WinGrowTrackTable.WinGrowTrack.WordRef, lowerInclusive, upperInclusive);
+    }
+
+    /**
+     * Fetch records that have word_ref IN (values)
+     */
+    public List fetchByWordRef(String... values) {
+        return fetch(WinGrowTrackTable.WinGrowTrack.WordRef, values);
+    }
+
+    public List fetchByWordRef(Collection values) {
+        return fetch(WinGrowTrackTable.WinGrowTrack.WordRef, values);
+    }
+
+
+    public List fetchByWordRefLive(String... values) {
+        return fetchLive(WinGrowTrackTable.WinGrowTrack.WordRef, values);
+    }
+
+    public List fetchByWordRefLive(Collection values) {
+        return fetchLive(WinGrowTrackTable.WinGrowTrack.WordRef, values);
+    }
+}
diff --git a/radiant/tiny-grow/src/main/java-gen/pro/fessional/wings/tiny/grow/database/autogen/tables/interfaces/IWinGrowTrack.java b/radiant/tiny-grow/src/main/java-gen/pro/fessional/wings/tiny/grow/database/autogen/tables/interfaces/IWinGrowTrack.java
new file mode 100644
index 000000000..2b36b4788
--- /dev/null
+++ b/radiant/tiny-grow/src/main/java-gen/pro/fessional/wings/tiny/grow/database/autogen/tables/interfaces/IWinGrowTrack.java
@@ -0,0 +1,233 @@
+/*
+ * This file is generated by jOOQ.
+ */
+package pro.fessional.wings.tiny.grow.database.autogen.tables.interfaces;
+
+
+import pro.fessional.wings.faceless.service.journal.JournalAware;
+
+import javax.annotation.processing.Generated;
+import java.io.Serializable;
+import java.time.LocalDateTime;
+
+
+/**
+ * The table wings.win_grow_track.
+ */
+@Generated(
+    value = {
+        "https://www.jooq.org",
+        "jOOQ version:3.18.9",
+        "schema version:2020102801"
+    },
+    comments = "This class is generated by jOOQ"
+)
+@SuppressWarnings({ "all", "unchecked", "rawtypes", "this-escape" })
+public interface IWinGrowTrack extends JournalAware, Serializable {
+
+    /**
+     * Setter for win_grow_track.id.
+     */
+    public void setId(Long value);
+
+    /**
+     * Getter for win_grow_track.id.
+     */
+    public Long getId();
+
+    /**
+     * Setter for win_grow_track.create_dt.
+     */
+    public void setCreateDt(LocalDateTime value);
+
+    /**
+     * Getter for win_grow_track.create_dt.
+     */
+    public LocalDateTime getCreateDt();
+
+    /**
+     * Setter for win_grow_track.track_key.
+     */
+    public void setTrackKey(String value);
+
+    /**
+     * Getter for win_grow_track.track_key.
+     */
+    public String getTrackKey();
+
+    /**
+     * Setter for win_grow_track.track_ref.
+     */
+    public void setTrackRef(String value);
+
+    /**
+     * Getter for win_grow_track.track_ref.
+     */
+    public String getTrackRef();
+
+    /**
+     * Setter for win_grow_track.track_app.
+     */
+    public void setTrackApp(String value);
+
+    /**
+     * Getter for win_grow_track.track_app.
+     */
+    public String getTrackApp();
+
+    /**
+     * Setter for win_grow_track.track_env.
+     */
+    public void setTrackEnv(String value);
+
+    /**
+     * Getter for win_grow_track.track_env.
+     */
+    public String getTrackEnv();
+
+    /**
+     * Setter for win_grow_track.track_ins.
+     */
+    public void setTrackIns(String value);
+
+    /**
+     * Getter for win_grow_track.track_ins.
+     */
+    public String getTrackIns();
+
+    /**
+     * Setter for win_grow_track.track_out.
+     */
+    public void setTrackOut(String value);
+
+    /**
+     * Getter for win_grow_track.track_out.
+     */
+    public String getTrackOut();
+
+    /**
+     * Setter for win_grow_track.track_err.
+     */
+    public void setTrackErr(String value);
+
+    /**
+     * Getter for win_grow_track.track_err.
+     */
+    public String getTrackErr();
+
+    /**
+     * Setter for win_grow_track.elapse_ms.
+     */
+    public void setElapseMs(Long value);
+
+    /**
+     * Getter for win_grow_track.elapse_ms.
+     */
+    public Long getElapseMs();
+
+    /**
+     * Setter for win_grow_track.user_key.
+     */
+    public void setUserKey(Long value);
+
+    /**
+     * Getter for win_grow_track.user_key.
+     */
+    public Long getUserKey();
+
+    /**
+     * Setter for win_grow_track.user_ref.
+     */
+    public void setUserRef(Long value);
+
+    /**
+     * Getter for win_grow_track.user_ref.
+     */
+    public Long getUserRef();
+
+    /**
+     * Setter for win_grow_track.data_key.
+     */
+    public void setDataKey(Long value);
+
+    /**
+     * Getter for win_grow_track.data_key.
+     */
+    public Long getDataKey();
+
+    /**
+     * Setter for win_grow_track.data_ref.
+     */
+    public void setDataRef(Long value);
+
+    /**
+     * Getter for win_grow_track.data_ref.
+     */
+    public Long getDataRef();
+
+    /**
+     * Setter for win_grow_track.data_opt.
+     */
+    public void setDataOpt(Long value);
+
+    /**
+     * Getter for win_grow_track.data_opt.
+     */
+    public Long getDataOpt();
+
+    /**
+     * Setter for win_grow_track.code_key.
+     */
+    public void setCodeKey(String value);
+
+    /**
+     * Getter for win_grow_track.code_key.
+     */
+    public String getCodeKey();
+
+    /**
+     * Setter for win_grow_track.code_ref.
+     */
+    public void setCodeRef(String value);
+
+    /**
+     * Getter for win_grow_track.code_ref.
+     */
+    public String getCodeRef();
+
+    /**
+     * Setter for win_grow_track.code_opt.
+     */
+    public void setCodeOpt(String value);
+
+    /**
+     * Getter for win_grow_track.code_opt.
+     */
+    public String getCodeOpt();
+
+    /**
+     * Setter for win_grow_track.word_ref.
+     */
+    public void setWordRef(String value);
+
+    /**
+     * Getter for win_grow_track.word_ref.
+     */
+    public String getWordRef();
+
+    // -------------------------------------------------------------------------
+    // FROM and INTO
+    // -------------------------------------------------------------------------
+
+    /**
+     * Load data from another generated Record/POJO implementing the common
+     * interface IWinGrowTrack
+     */
+    public void from(IWinGrowTrack from);
+
+    /**
+     * Copy data into another generated Record/POJO implementing the common
+     * interface IWinGrowTrack
+     */
+    public  E into(E into);
+}
diff --git a/radiant/tiny-grow/src/main/java-gen/pro/fessional/wings/tiny/grow/database/autogen/tables/pojos/WinGrowTrack.java b/radiant/tiny-grow/src/main/java-gen/pro/fessional/wings/tiny/grow/database/autogen/tables/pojos/WinGrowTrack.java
new file mode 100644
index 000000000..b89ae914d
--- /dev/null
+++ b/radiant/tiny-grow/src/main/java-gen/pro/fessional/wings/tiny/grow/database/autogen/tables/pojos/WinGrowTrack.java
@@ -0,0 +1,1851 @@
+/*
+ * This file is generated by jOOQ.
+ */
+package pro.fessional.wings.tiny.grow.database.autogen.tables.pojos;
+
+
+import pro.fessional.wings.tiny.grow.database.autogen.tables.interfaces.IWinGrowTrack;
+
+import javax.annotation.processing.Generated;
+import java.beans.Transient;
+import java.time.LocalDateTime;
+import java.util.function.Predicate;
+import java.util.function.Supplier;
+import java.util.function.UnaryOperator;
+
+
+/**
+ * The table wings.win_grow_track.
+ */
+@Generated(
+    value = {
+        "https://www.jooq.org",
+        "jOOQ version:3.18.9",
+        "schema version:2020102801"
+    },
+    comments = "This class is generated by jOOQ"
+)
+@SuppressWarnings({ "all", "unchecked", "rawtypes", "this-escape" })
+public class WinGrowTrack implements IWinGrowTrack {
+
+    private static final long serialVersionUID = 1L;
+
+    private Long id;
+    private LocalDateTime createDt;
+    private String trackKey;
+    private String trackRef;
+    private String trackApp;
+    private String trackEnv;
+    private String trackIns;
+    private String trackOut;
+    private String trackErr;
+    private Long elapseMs;
+    private Long userKey;
+    private Long userRef;
+    private Long dataKey;
+    private Long dataRef;
+    private Long dataOpt;
+    private String codeKey;
+    private String codeRef;
+    private String codeOpt;
+    private String wordRef;
+
+    public WinGrowTrack() {}
+
+    public WinGrowTrack(IWinGrowTrack value) {
+        this.id = value.getId();
+        this.createDt = value.getCreateDt();
+        this.trackKey = value.getTrackKey();
+        this.trackRef = value.getTrackRef();
+        this.trackApp = value.getTrackApp();
+        this.trackEnv = value.getTrackEnv();
+        this.trackIns = value.getTrackIns();
+        this.trackOut = value.getTrackOut();
+        this.trackErr = value.getTrackErr();
+        this.elapseMs = value.getElapseMs();
+        this.userKey = value.getUserKey();
+        this.userRef = value.getUserRef();
+        this.dataKey = value.getDataKey();
+        this.dataRef = value.getDataRef();
+        this.dataOpt = value.getDataOpt();
+        this.codeKey = value.getCodeKey();
+        this.codeRef = value.getCodeRef();
+        this.codeOpt = value.getCodeOpt();
+        this.wordRef = value.getWordRef();
+    }
+
+    public WinGrowTrack(
+        Long id,
+        LocalDateTime createDt,
+        String trackKey,
+        String trackRef,
+        String trackApp,
+        String trackEnv,
+        String trackIns,
+        String trackOut,
+        String trackErr,
+        Long elapseMs,
+        Long userKey,
+        Long userRef,
+        Long dataKey,
+        Long dataRef,
+        Long dataOpt,
+        String codeKey,
+        String codeRef,
+        String codeOpt,
+        String wordRef
+    ) {
+        this.id = id;
+        this.createDt = createDt;
+        this.trackKey = trackKey;
+        this.trackRef = trackRef;
+        this.trackApp = trackApp;
+        this.trackEnv = trackEnv;
+        this.trackIns = trackIns;
+        this.trackOut = trackOut;
+        this.trackErr = trackErr;
+        this.elapseMs = elapseMs;
+        this.userKey = userKey;
+        this.userRef = userRef;
+        this.dataKey = dataKey;
+        this.dataRef = dataRef;
+        this.dataOpt = dataOpt;
+        this.codeKey = codeKey;
+        this.codeRef = codeRef;
+        this.codeOpt = codeOpt;
+        this.wordRef = wordRef;
+    }
+
+    /**
+     * Getter for win_grow_track.id.
+     */
+    @Override
+    public Long getId() {
+        return this.id;
+    }
+
+    /**
+     * Setter for win_grow_track.id.
+     */
+    @Override
+    public void setId(Long id) {
+        this.id = id;
+    }
+
+    @Transient
+    public void setIdIf(Long id, boolean bool) {
+        if (bool) {
+            this.id = id;
+        }
+    }
+
+    @Transient
+    public void setIdIf(Supplier id, boolean bool) {
+        if (bool) {
+            this.id = id.get();
+        }
+    }
+
+    @Transient
+    public void setIdIf(Long id, Predicate bool) {
+        if (bool.test(id)) {
+            this.id = id;
+        }
+    }
+
+    @Transient
+    public void setIdIf(Long id, Predicate bool, Supplier... ids) {
+        if (bool.test(id)) {
+            this.id = id;
+            return;
+        }
+        for (Supplier supplier : ids) {
+            id = supplier.get();
+            if (bool.test(id)) {
+                this.id = id;
+                return;
+            }
+        }
+    }
+
+    @Transient
+    public void setIdIfNot(Long id, Predicate bool) {
+        if (!bool.test(id)) {
+            this.id = id;
+        }
+    }
+
+    @Transient
+    public void setIdIfNot(Long id, Predicate bool, Supplier... ids) {
+        if (!bool.test(id)) {
+            this.id = id;
+            return;
+        }
+        for (Supplier supplier : ids) {
+            id = supplier.get();
+            if (!bool.test(id)) {
+                this.id = id;
+                return;
+            }
+        }
+    }
+
+    @Transient
+    public void setIdIf(UnaryOperator id) {
+        this.id = id.apply(this.id);
+    }
+
+
+    /**
+     * Getter for win_grow_track.create_dt.
+     */
+    @Override
+    public LocalDateTime getCreateDt() {
+        return this.createDt;
+    }
+
+    /**
+     * Setter for win_grow_track.create_dt.
+     */
+    @Override
+    public void setCreateDt(LocalDateTime createDt) {
+        this.createDt = createDt;
+    }
+
+    @Transient
+    public void setCreateDtIf(LocalDateTime createDt, boolean bool) {
+        if (bool) {
+            this.createDt = createDt;
+        }
+    }
+
+    @Transient
+    public void setCreateDtIf(Supplier createDt, boolean bool) {
+        if (bool) {
+            this.createDt = createDt.get();
+        }
+    }
+
+    @Transient
+    public void setCreateDtIf(LocalDateTime createDt, Predicate bool) {
+        if (bool.test(createDt)) {
+            this.createDt = createDt;
+        }
+    }
+
+    @Transient
+    public void setCreateDtIf(LocalDateTime createDt, Predicate bool, Supplier... createDts) {
+        if (bool.test(createDt)) {
+            this.createDt = createDt;
+            return;
+        }
+        for (Supplier supplier : createDts) {
+            createDt = supplier.get();
+            if (bool.test(createDt)) {
+                this.createDt = createDt;
+                return;
+            }
+        }
+    }
+
+    @Transient
+    public void setCreateDtIfNot(LocalDateTime createDt, Predicate bool) {
+        if (!bool.test(createDt)) {
+            this.createDt = createDt;
+        }
+    }
+
+    @Transient
+    public void setCreateDtIfNot(LocalDateTime createDt, Predicate bool, Supplier... createDts) {
+        if (!bool.test(createDt)) {
+            this.createDt = createDt;
+            return;
+        }
+        for (Supplier supplier : createDts) {
+            createDt = supplier.get();
+            if (!bool.test(createDt)) {
+                this.createDt = createDt;
+                return;
+            }
+        }
+    }
+
+    @Transient
+    public void setCreateDtIf(UnaryOperator createDt) {
+        this.createDt = createDt.apply(this.createDt);
+    }
+
+
+    /**
+     * Getter for win_grow_track.track_key.
+     */
+    @Override
+    public String getTrackKey() {
+        return this.trackKey;
+    }
+
+    /**
+     * Setter for win_grow_track.track_key.
+     */
+    @Override
+    public void setTrackKey(String trackKey) {
+        this.trackKey = trackKey;
+    }
+
+    @Transient
+    public void setTrackKeyIf(String trackKey, boolean bool) {
+        if (bool) {
+            this.trackKey = trackKey;
+        }
+    }
+
+    @Transient
+    public void setTrackKeyIf(Supplier trackKey, boolean bool) {
+        if (bool) {
+            this.trackKey = trackKey.get();
+        }
+    }
+
+    @Transient
+    public void setTrackKeyIf(String trackKey, Predicate bool) {
+        if (bool.test(trackKey)) {
+            this.trackKey = trackKey;
+        }
+    }
+
+    @Transient
+    public void setTrackKeyIf(String trackKey, Predicate bool, Supplier... trackKeys) {
+        if (bool.test(trackKey)) {
+            this.trackKey = trackKey;
+            return;
+        }
+        for (Supplier supplier : trackKeys) {
+            trackKey = supplier.get();
+            if (bool.test(trackKey)) {
+                this.trackKey = trackKey;
+                return;
+            }
+        }
+    }
+
+    @Transient
+    public void setTrackKeyIfNot(String trackKey, Predicate bool) {
+        if (!bool.test(trackKey)) {
+            this.trackKey = trackKey;
+        }
+    }
+
+    @Transient
+    public void setTrackKeyIfNot(String trackKey, Predicate bool, Supplier... trackKeys) {
+        if (!bool.test(trackKey)) {
+            this.trackKey = trackKey;
+            return;
+        }
+        for (Supplier supplier : trackKeys) {
+            trackKey = supplier.get();
+            if (!bool.test(trackKey)) {
+                this.trackKey = trackKey;
+                return;
+            }
+        }
+    }
+
+    @Transient
+    public void setTrackKeyIf(UnaryOperator trackKey) {
+        this.trackKey = trackKey.apply(this.trackKey);
+    }
+
+
+    /**
+     * Getter for win_grow_track.track_ref.
+     */
+    @Override
+    public String getTrackRef() {
+        return this.trackRef;
+    }
+
+    /**
+     * Setter for win_grow_track.track_ref.
+     */
+    @Override
+    public void setTrackRef(String trackRef) {
+        this.trackRef = trackRef;
+    }
+
+    @Transient
+    public void setTrackRefIf(String trackRef, boolean bool) {
+        if (bool) {
+            this.trackRef = trackRef;
+        }
+    }
+
+    @Transient
+    public void setTrackRefIf(Supplier trackRef, boolean bool) {
+        if (bool) {
+            this.trackRef = trackRef.get();
+        }
+    }
+
+    @Transient
+    public void setTrackRefIf(String trackRef, Predicate bool) {
+        if (bool.test(trackRef)) {
+            this.trackRef = trackRef;
+        }
+    }
+
+    @Transient
+    public void setTrackRefIf(String trackRef, Predicate bool, Supplier... trackRefs) {
+        if (bool.test(trackRef)) {
+            this.trackRef = trackRef;
+            return;
+        }
+        for (Supplier supplier : trackRefs) {
+            trackRef = supplier.get();
+            if (bool.test(trackRef)) {
+                this.trackRef = trackRef;
+                return;
+            }
+        }
+    }
+
+    @Transient
+    public void setTrackRefIfNot(String trackRef, Predicate bool) {
+        if (!bool.test(trackRef)) {
+            this.trackRef = trackRef;
+        }
+    }
+
+    @Transient
+    public void setTrackRefIfNot(String trackRef, Predicate bool, Supplier... trackRefs) {
+        if (!bool.test(trackRef)) {
+            this.trackRef = trackRef;
+            return;
+        }
+        for (Supplier supplier : trackRefs) {
+            trackRef = supplier.get();
+            if (!bool.test(trackRef)) {
+                this.trackRef = trackRef;
+                return;
+            }
+        }
+    }
+
+    @Transient
+    public void setTrackRefIf(UnaryOperator trackRef) {
+        this.trackRef = trackRef.apply(this.trackRef);
+    }
+
+
+    /**
+     * Getter for win_grow_track.track_app.
+     */
+    @Override
+    public String getTrackApp() {
+        return this.trackApp;
+    }
+
+    /**
+     * Setter for win_grow_track.track_app.
+     */
+    @Override
+    public void setTrackApp(String trackApp) {
+        this.trackApp = trackApp;
+    }
+
+    @Transient
+    public void setTrackAppIf(String trackApp, boolean bool) {
+        if (bool) {
+            this.trackApp = trackApp;
+        }
+    }
+
+    @Transient
+    public void setTrackAppIf(Supplier trackApp, boolean bool) {
+        if (bool) {
+            this.trackApp = trackApp.get();
+        }
+    }
+
+    @Transient
+    public void setTrackAppIf(String trackApp, Predicate bool) {
+        if (bool.test(trackApp)) {
+            this.trackApp = trackApp;
+        }
+    }
+
+    @Transient
+    public void setTrackAppIf(String trackApp, Predicate bool, Supplier... trackApps) {
+        if (bool.test(trackApp)) {
+            this.trackApp = trackApp;
+            return;
+        }
+        for (Supplier supplier : trackApps) {
+            trackApp = supplier.get();
+            if (bool.test(trackApp)) {
+                this.trackApp = trackApp;
+                return;
+            }
+        }
+    }
+
+    @Transient
+    public void setTrackAppIfNot(String trackApp, Predicate bool) {
+        if (!bool.test(trackApp)) {
+            this.trackApp = trackApp;
+        }
+    }
+
+    @Transient
+    public void setTrackAppIfNot(String trackApp, Predicate bool, Supplier... trackApps) {
+        if (!bool.test(trackApp)) {
+            this.trackApp = trackApp;
+            return;
+        }
+        for (Supplier supplier : trackApps) {
+            trackApp = supplier.get();
+            if (!bool.test(trackApp)) {
+                this.trackApp = trackApp;
+                return;
+            }
+        }
+    }
+
+    @Transient
+    public void setTrackAppIf(UnaryOperator trackApp) {
+        this.trackApp = trackApp.apply(this.trackApp);
+    }
+
+
+    /**
+     * Getter for win_grow_track.track_env.
+     */
+    @Override
+    public String getTrackEnv() {
+        return this.trackEnv;
+    }
+
+    /**
+     * Setter for win_grow_track.track_env.
+     */
+    @Override
+    public void setTrackEnv(String trackEnv) {
+        this.trackEnv = trackEnv;
+    }
+
+    @Transient
+    public void setTrackEnvIf(String trackEnv, boolean bool) {
+        if (bool) {
+            this.trackEnv = trackEnv;
+        }
+    }
+
+    @Transient
+    public void setTrackEnvIf(Supplier trackEnv, boolean bool) {
+        if (bool) {
+            this.trackEnv = trackEnv.get();
+        }
+    }
+
+    @Transient
+    public void setTrackEnvIf(String trackEnv, Predicate bool) {
+        if (bool.test(trackEnv)) {
+            this.trackEnv = trackEnv;
+        }
+    }
+
+    @Transient
+    public void setTrackEnvIf(String trackEnv, Predicate bool, Supplier... trackEnvs) {
+        if (bool.test(trackEnv)) {
+            this.trackEnv = trackEnv;
+            return;
+        }
+        for (Supplier supplier : trackEnvs) {
+            trackEnv = supplier.get();
+            if (bool.test(trackEnv)) {
+                this.trackEnv = trackEnv;
+                return;
+            }
+        }
+    }
+
+    @Transient
+    public void setTrackEnvIfNot(String trackEnv, Predicate bool) {
+        if (!bool.test(trackEnv)) {
+            this.trackEnv = trackEnv;
+        }
+    }
+
+    @Transient
+    public void setTrackEnvIfNot(String trackEnv, Predicate bool, Supplier... trackEnvs) {
+        if (!bool.test(trackEnv)) {
+            this.trackEnv = trackEnv;
+            return;
+        }
+        for (Supplier supplier : trackEnvs) {
+            trackEnv = supplier.get();
+            if (!bool.test(trackEnv)) {
+                this.trackEnv = trackEnv;
+                return;
+            }
+        }
+    }
+
+    @Transient
+    public void setTrackEnvIf(UnaryOperator trackEnv) {
+        this.trackEnv = trackEnv.apply(this.trackEnv);
+    }
+
+
+    /**
+     * Getter for win_grow_track.track_ins.
+     */
+    @Override
+    public String getTrackIns() {
+        return this.trackIns;
+    }
+
+    /**
+     * Setter for win_grow_track.track_ins.
+     */
+    @Override
+    public void setTrackIns(String trackIns) {
+        this.trackIns = trackIns;
+    }
+
+    @Transient
+    public void setTrackInsIf(String trackIns, boolean bool) {
+        if (bool) {
+            this.trackIns = trackIns;
+        }
+    }
+
+    @Transient
+    public void setTrackInsIf(Supplier trackIns, boolean bool) {
+        if (bool) {
+            this.trackIns = trackIns.get();
+        }
+    }
+
+    @Transient
+    public void setTrackInsIf(String trackIns, Predicate bool) {
+        if (bool.test(trackIns)) {
+            this.trackIns = trackIns;
+        }
+    }
+
+    @Transient
+    public void setTrackInsIf(String trackIns, Predicate bool, Supplier... trackInss) {
+        if (bool.test(trackIns)) {
+            this.trackIns = trackIns;
+            return;
+        }
+        for (Supplier supplier : trackInss) {
+            trackIns = supplier.get();
+            if (bool.test(trackIns)) {
+                this.trackIns = trackIns;
+                return;
+            }
+        }
+    }
+
+    @Transient
+    public void setTrackInsIfNot(String trackIns, Predicate bool) {
+        if (!bool.test(trackIns)) {
+            this.trackIns = trackIns;
+        }
+    }
+
+    @Transient
+    public void setTrackInsIfNot(String trackIns, Predicate bool, Supplier... trackInss) {
+        if (!bool.test(trackIns)) {
+            this.trackIns = trackIns;
+            return;
+        }
+        for (Supplier supplier : trackInss) {
+            trackIns = supplier.get();
+            if (!bool.test(trackIns)) {
+                this.trackIns = trackIns;
+                return;
+            }
+        }
+    }
+
+    @Transient
+    public void setTrackInsIf(UnaryOperator trackIns) {
+        this.trackIns = trackIns.apply(this.trackIns);
+    }
+
+
+    /**
+     * Getter for win_grow_track.track_out.
+     */
+    @Override
+    public String getTrackOut() {
+        return this.trackOut;
+    }
+
+    /**
+     * Setter for win_grow_track.track_out.
+     */
+    @Override
+    public void setTrackOut(String trackOut) {
+        this.trackOut = trackOut;
+    }
+
+    @Transient
+    public void setTrackOutIf(String trackOut, boolean bool) {
+        if (bool) {
+            this.trackOut = trackOut;
+        }
+    }
+
+    @Transient
+    public void setTrackOutIf(Supplier trackOut, boolean bool) {
+        if (bool) {
+            this.trackOut = trackOut.get();
+        }
+    }
+
+    @Transient
+    public void setTrackOutIf(String trackOut, Predicate bool) {
+        if (bool.test(trackOut)) {
+            this.trackOut = trackOut;
+        }
+    }
+
+    @Transient
+    public void setTrackOutIf(String trackOut, Predicate bool, Supplier... trackOuts) {
+        if (bool.test(trackOut)) {
+            this.trackOut = trackOut;
+            return;
+        }
+        for (Supplier supplier : trackOuts) {
+            trackOut = supplier.get();
+            if (bool.test(trackOut)) {
+                this.trackOut = trackOut;
+                return;
+            }
+        }
+    }
+
+    @Transient
+    public void setTrackOutIfNot(String trackOut, Predicate bool) {
+        if (!bool.test(trackOut)) {
+            this.trackOut = trackOut;
+        }
+    }
+
+    @Transient
+    public void setTrackOutIfNot(String trackOut, Predicate bool, Supplier... trackOuts) {
+        if (!bool.test(trackOut)) {
+            this.trackOut = trackOut;
+            return;
+        }
+        for (Supplier supplier : trackOuts) {
+            trackOut = supplier.get();
+            if (!bool.test(trackOut)) {
+                this.trackOut = trackOut;
+                return;
+            }
+        }
+    }
+
+    @Transient
+    public void setTrackOutIf(UnaryOperator trackOut) {
+        this.trackOut = trackOut.apply(this.trackOut);
+    }
+
+
+    /**
+     * Getter for win_grow_track.track_err.
+     */
+    @Override
+    public String getTrackErr() {
+        return this.trackErr;
+    }
+
+    /**
+     * Setter for win_grow_track.track_err.
+     */
+    @Override
+    public void setTrackErr(String trackErr) {
+        this.trackErr = trackErr;
+    }
+
+    @Transient
+    public void setTrackErrIf(String trackErr, boolean bool) {
+        if (bool) {
+            this.trackErr = trackErr;
+        }
+    }
+
+    @Transient
+    public void setTrackErrIf(Supplier trackErr, boolean bool) {
+        if (bool) {
+            this.trackErr = trackErr.get();
+        }
+    }
+
+    @Transient
+    public void setTrackErrIf(String trackErr, Predicate bool) {
+        if (bool.test(trackErr)) {
+            this.trackErr = trackErr;
+        }
+    }
+
+    @Transient
+    public void setTrackErrIf(String trackErr, Predicate bool, Supplier... trackErrs) {
+        if (bool.test(trackErr)) {
+            this.trackErr = trackErr;
+            return;
+        }
+        for (Supplier supplier : trackErrs) {
+            trackErr = supplier.get();
+            if (bool.test(trackErr)) {
+                this.trackErr = trackErr;
+                return;
+            }
+        }
+    }
+
+    @Transient
+    public void setTrackErrIfNot(String trackErr, Predicate bool) {
+        if (!bool.test(trackErr)) {
+            this.trackErr = trackErr;
+        }
+    }
+
+    @Transient
+    public void setTrackErrIfNot(String trackErr, Predicate bool, Supplier... trackErrs) {
+        if (!bool.test(trackErr)) {
+            this.trackErr = trackErr;
+            return;
+        }
+        for (Supplier supplier : trackErrs) {
+            trackErr = supplier.get();
+            if (!bool.test(trackErr)) {
+                this.trackErr = trackErr;
+                return;
+            }
+        }
+    }
+
+    @Transient
+    public void setTrackErrIf(UnaryOperator trackErr) {
+        this.trackErr = trackErr.apply(this.trackErr);
+    }
+
+
+    /**
+     * Getter for win_grow_track.elapse_ms.
+     */
+    @Override
+    public Long getElapseMs() {
+        return this.elapseMs;
+    }
+
+    /**
+     * Setter for win_grow_track.elapse_ms.
+     */
+    @Override
+    public void setElapseMs(Long elapseMs) {
+        this.elapseMs = elapseMs;
+    }
+
+    @Transient
+    public void setElapseMsIf(Long elapseMs, boolean bool) {
+        if (bool) {
+            this.elapseMs = elapseMs;
+        }
+    }
+
+    @Transient
+    public void setElapseMsIf(Supplier elapseMs, boolean bool) {
+        if (bool) {
+            this.elapseMs = elapseMs.get();
+        }
+    }
+
+    @Transient
+    public void setElapseMsIf(Long elapseMs, Predicate bool) {
+        if (bool.test(elapseMs)) {
+            this.elapseMs = elapseMs;
+        }
+    }
+
+    @Transient
+    public void setElapseMsIf(Long elapseMs, Predicate bool, Supplier... elapseMss) {
+        if (bool.test(elapseMs)) {
+            this.elapseMs = elapseMs;
+            return;
+        }
+        for (Supplier supplier : elapseMss) {
+            elapseMs = supplier.get();
+            if (bool.test(elapseMs)) {
+                this.elapseMs = elapseMs;
+                return;
+            }
+        }
+    }
+
+    @Transient
+    public void setElapseMsIfNot(Long elapseMs, Predicate bool) {
+        if (!bool.test(elapseMs)) {
+            this.elapseMs = elapseMs;
+        }
+    }
+
+    @Transient
+    public void setElapseMsIfNot(Long elapseMs, Predicate bool, Supplier... elapseMss) {
+        if (!bool.test(elapseMs)) {
+            this.elapseMs = elapseMs;
+            return;
+        }
+        for (Supplier supplier : elapseMss) {
+            elapseMs = supplier.get();
+            if (!bool.test(elapseMs)) {
+                this.elapseMs = elapseMs;
+                return;
+            }
+        }
+    }
+
+    @Transient
+    public void setElapseMsIf(UnaryOperator elapseMs) {
+        this.elapseMs = elapseMs.apply(this.elapseMs);
+    }
+
+
+    /**
+     * Getter for win_grow_track.user_key.
+     */
+    @Override
+    public Long getUserKey() {
+        return this.userKey;
+    }
+
+    /**
+     * Setter for win_grow_track.user_key.
+     */
+    @Override
+    public void setUserKey(Long userKey) {
+        this.userKey = userKey;
+    }
+
+    @Transient
+    public void setUserKeyIf(Long userKey, boolean bool) {
+        if (bool) {
+            this.userKey = userKey;
+        }
+    }
+
+    @Transient
+    public void setUserKeyIf(Supplier userKey, boolean bool) {
+        if (bool) {
+            this.userKey = userKey.get();
+        }
+    }
+
+    @Transient
+    public void setUserKeyIf(Long userKey, Predicate bool) {
+        if (bool.test(userKey)) {
+            this.userKey = userKey;
+        }
+    }
+
+    @Transient
+    public void setUserKeyIf(Long userKey, Predicate bool, Supplier... userKeys) {
+        if (bool.test(userKey)) {
+            this.userKey = userKey;
+            return;
+        }
+        for (Supplier supplier : userKeys) {
+            userKey = supplier.get();
+            if (bool.test(userKey)) {
+                this.userKey = userKey;
+                return;
+            }
+        }
+    }
+
+    @Transient
+    public void setUserKeyIfNot(Long userKey, Predicate bool) {
+        if (!bool.test(userKey)) {
+            this.userKey = userKey;
+        }
+    }
+
+    @Transient
+    public void setUserKeyIfNot(Long userKey, Predicate bool, Supplier... userKeys) {
+        if (!bool.test(userKey)) {
+            this.userKey = userKey;
+            return;
+        }
+        for (Supplier supplier : userKeys) {
+            userKey = supplier.get();
+            if (!bool.test(userKey)) {
+                this.userKey = userKey;
+                return;
+            }
+        }
+    }
+
+    @Transient
+    public void setUserKeyIf(UnaryOperator userKey) {
+        this.userKey = userKey.apply(this.userKey);
+    }
+
+
+    /**
+     * Getter for win_grow_track.user_ref.
+     */
+    @Override
+    public Long getUserRef() {
+        return this.userRef;
+    }
+
+    /**
+     * Setter for win_grow_track.user_ref.
+     */
+    @Override
+    public void setUserRef(Long userRef) {
+        this.userRef = userRef;
+    }
+
+    @Transient
+    public void setUserRefIf(Long userRef, boolean bool) {
+        if (bool) {
+            this.userRef = userRef;
+        }
+    }
+
+    @Transient
+    public void setUserRefIf(Supplier userRef, boolean bool) {
+        if (bool) {
+            this.userRef = userRef.get();
+        }
+    }
+
+    @Transient
+    public void setUserRefIf(Long userRef, Predicate bool) {
+        if (bool.test(userRef)) {
+            this.userRef = userRef;
+        }
+    }
+
+    @Transient
+    public void setUserRefIf(Long userRef, Predicate bool, Supplier... userRefs) {
+        if (bool.test(userRef)) {
+            this.userRef = userRef;
+            return;
+        }
+        for (Supplier supplier : userRefs) {
+            userRef = supplier.get();
+            if (bool.test(userRef)) {
+                this.userRef = userRef;
+                return;
+            }
+        }
+    }
+
+    @Transient
+    public void setUserRefIfNot(Long userRef, Predicate bool) {
+        if (!bool.test(userRef)) {
+            this.userRef = userRef;
+        }
+    }
+
+    @Transient
+    public void setUserRefIfNot(Long userRef, Predicate bool, Supplier... userRefs) {
+        if (!bool.test(userRef)) {
+            this.userRef = userRef;
+            return;
+        }
+        for (Supplier supplier : userRefs) {
+            userRef = supplier.get();
+            if (!bool.test(userRef)) {
+                this.userRef = userRef;
+                return;
+            }
+        }
+    }
+
+    @Transient
+    public void setUserRefIf(UnaryOperator userRef) {
+        this.userRef = userRef.apply(this.userRef);
+    }
+
+
+    /**
+     * Getter for win_grow_track.data_key.
+     */
+    @Override
+    public Long getDataKey() {
+        return this.dataKey;
+    }
+
+    /**
+     * Setter for win_grow_track.data_key.
+     */
+    @Override
+    public void setDataKey(Long dataKey) {
+        this.dataKey = dataKey;
+    }
+
+    @Transient
+    public void setDataKeyIf(Long dataKey, boolean bool) {
+        if (bool) {
+            this.dataKey = dataKey;
+        }
+    }
+
+    @Transient
+    public void setDataKeyIf(Supplier dataKey, boolean bool) {
+        if (bool) {
+            this.dataKey = dataKey.get();
+        }
+    }
+
+    @Transient
+    public void setDataKeyIf(Long dataKey, Predicate bool) {
+        if (bool.test(dataKey)) {
+            this.dataKey = dataKey;
+        }
+    }
+
+    @Transient
+    public void setDataKeyIf(Long dataKey, Predicate bool, Supplier... dataKeys) {
+        if (bool.test(dataKey)) {
+            this.dataKey = dataKey;
+            return;
+        }
+        for (Supplier supplier : dataKeys) {
+            dataKey = supplier.get();
+            if (bool.test(dataKey)) {
+                this.dataKey = dataKey;
+                return;
+            }
+        }
+    }
+
+    @Transient
+    public void setDataKeyIfNot(Long dataKey, Predicate bool) {
+        if (!bool.test(dataKey)) {
+            this.dataKey = dataKey;
+        }
+    }
+
+    @Transient
+    public void setDataKeyIfNot(Long dataKey, Predicate bool, Supplier... dataKeys) {
+        if (!bool.test(dataKey)) {
+            this.dataKey = dataKey;
+            return;
+        }
+        for (Supplier supplier : dataKeys) {
+            dataKey = supplier.get();
+            if (!bool.test(dataKey)) {
+                this.dataKey = dataKey;
+                return;
+            }
+        }
+    }
+
+    @Transient
+    public void setDataKeyIf(UnaryOperator dataKey) {
+        this.dataKey = dataKey.apply(this.dataKey);
+    }
+
+
+    /**
+     * Getter for win_grow_track.data_ref.
+     */
+    @Override
+    public Long getDataRef() {
+        return this.dataRef;
+    }
+
+    /**
+     * Setter for win_grow_track.data_ref.
+     */
+    @Override
+    public void setDataRef(Long dataRef) {
+        this.dataRef = dataRef;
+    }
+
+    @Transient
+    public void setDataRefIf(Long dataRef, boolean bool) {
+        if (bool) {
+            this.dataRef = dataRef;
+        }
+    }
+
+    @Transient
+    public void setDataRefIf(Supplier dataRef, boolean bool) {
+        if (bool) {
+            this.dataRef = dataRef.get();
+        }
+    }
+
+    @Transient
+    public void setDataRefIf(Long dataRef, Predicate bool) {
+        if (bool.test(dataRef)) {
+            this.dataRef = dataRef;
+        }
+    }
+
+    @Transient
+    public void setDataRefIf(Long dataRef, Predicate bool, Supplier... dataRefs) {
+        if (bool.test(dataRef)) {
+            this.dataRef = dataRef;
+            return;
+        }
+        for (Supplier supplier : dataRefs) {
+            dataRef = supplier.get();
+            if (bool.test(dataRef)) {
+                this.dataRef = dataRef;
+                return;
+            }
+        }
+    }
+
+    @Transient
+    public void setDataRefIfNot(Long dataRef, Predicate bool) {
+        if (!bool.test(dataRef)) {
+            this.dataRef = dataRef;
+        }
+    }
+
+    @Transient
+    public void setDataRefIfNot(Long dataRef, Predicate bool, Supplier... dataRefs) {
+        if (!bool.test(dataRef)) {
+            this.dataRef = dataRef;
+            return;
+        }
+        for (Supplier supplier : dataRefs) {
+            dataRef = supplier.get();
+            if (!bool.test(dataRef)) {
+                this.dataRef = dataRef;
+                return;
+            }
+        }
+    }
+
+    @Transient
+    public void setDataRefIf(UnaryOperator dataRef) {
+        this.dataRef = dataRef.apply(this.dataRef);
+    }
+
+
+    /**
+     * Getter for win_grow_track.data_opt.
+     */
+    @Override
+    public Long getDataOpt() {
+        return this.dataOpt;
+    }
+
+    /**
+     * Setter for win_grow_track.data_opt.
+     */
+    @Override
+    public void setDataOpt(Long dataOpt) {
+        this.dataOpt = dataOpt;
+    }
+
+    @Transient
+    public void setDataOptIf(Long dataOpt, boolean bool) {
+        if (bool) {
+            this.dataOpt = dataOpt;
+        }
+    }
+
+    @Transient
+    public void setDataOptIf(Supplier dataOpt, boolean bool) {
+        if (bool) {
+            this.dataOpt = dataOpt.get();
+        }
+    }
+
+    @Transient
+    public void setDataOptIf(Long dataOpt, Predicate bool) {
+        if (bool.test(dataOpt)) {
+            this.dataOpt = dataOpt;
+        }
+    }
+
+    @Transient
+    public void setDataOptIf(Long dataOpt, Predicate bool, Supplier... dataOpts) {
+        if (bool.test(dataOpt)) {
+            this.dataOpt = dataOpt;
+            return;
+        }
+        for (Supplier supplier : dataOpts) {
+            dataOpt = supplier.get();
+            if (bool.test(dataOpt)) {
+                this.dataOpt = dataOpt;
+                return;
+            }
+        }
+    }
+
+    @Transient
+    public void setDataOptIfNot(Long dataOpt, Predicate bool) {
+        if (!bool.test(dataOpt)) {
+            this.dataOpt = dataOpt;
+        }
+    }
+
+    @Transient
+    public void setDataOptIfNot(Long dataOpt, Predicate bool, Supplier... dataOpts) {
+        if (!bool.test(dataOpt)) {
+            this.dataOpt = dataOpt;
+            return;
+        }
+        for (Supplier supplier : dataOpts) {
+            dataOpt = supplier.get();
+            if (!bool.test(dataOpt)) {
+                this.dataOpt = dataOpt;
+                return;
+            }
+        }
+    }
+
+    @Transient
+    public void setDataOptIf(UnaryOperator dataOpt) {
+        this.dataOpt = dataOpt.apply(this.dataOpt);
+    }
+
+
+    /**
+     * Getter for win_grow_track.code_key.
+     */
+    @Override
+    public String getCodeKey() {
+        return this.codeKey;
+    }
+
+    /**
+     * Setter for win_grow_track.code_key.
+     */
+    @Override
+    public void setCodeKey(String codeKey) {
+        this.codeKey = codeKey;
+    }
+
+    @Transient
+    public void setCodeKeyIf(String codeKey, boolean bool) {
+        if (bool) {
+            this.codeKey = codeKey;
+        }
+    }
+
+    @Transient
+    public void setCodeKeyIf(Supplier codeKey, boolean bool) {
+        if (bool) {
+            this.codeKey = codeKey.get();
+        }
+    }
+
+    @Transient
+    public void setCodeKeyIf(String codeKey, Predicate bool) {
+        if (bool.test(codeKey)) {
+            this.codeKey = codeKey;
+        }
+    }
+
+    @Transient
+    public void setCodeKeyIf(String codeKey, Predicate bool, Supplier... codeKeys) {
+        if (bool.test(codeKey)) {
+            this.codeKey = codeKey;
+            return;
+        }
+        for (Supplier supplier : codeKeys) {
+            codeKey = supplier.get();
+            if (bool.test(codeKey)) {
+                this.codeKey = codeKey;
+                return;
+            }
+        }
+    }
+
+    @Transient
+    public void setCodeKeyIfNot(String codeKey, Predicate bool) {
+        if (!bool.test(codeKey)) {
+            this.codeKey = codeKey;
+        }
+    }
+
+    @Transient
+    public void setCodeKeyIfNot(String codeKey, Predicate bool, Supplier... codeKeys) {
+        if (!bool.test(codeKey)) {
+            this.codeKey = codeKey;
+            return;
+        }
+        for (Supplier supplier : codeKeys) {
+            codeKey = supplier.get();
+            if (!bool.test(codeKey)) {
+                this.codeKey = codeKey;
+                return;
+            }
+        }
+    }
+
+    @Transient
+    public void setCodeKeyIf(UnaryOperator codeKey) {
+        this.codeKey = codeKey.apply(this.codeKey);
+    }
+
+
+    /**
+     * Getter for win_grow_track.code_ref.
+     */
+    @Override
+    public String getCodeRef() {
+        return this.codeRef;
+    }
+
+    /**
+     * Setter for win_grow_track.code_ref.
+     */
+    @Override
+    public void setCodeRef(String codeRef) {
+        this.codeRef = codeRef;
+    }
+
+    @Transient
+    public void setCodeRefIf(String codeRef, boolean bool) {
+        if (bool) {
+            this.codeRef = codeRef;
+        }
+    }
+
+    @Transient
+    public void setCodeRefIf(Supplier codeRef, boolean bool) {
+        if (bool) {
+            this.codeRef = codeRef.get();
+        }
+    }
+
+    @Transient
+    public void setCodeRefIf(String codeRef, Predicate bool) {
+        if (bool.test(codeRef)) {
+            this.codeRef = codeRef;
+        }
+    }
+
+    @Transient
+    public void setCodeRefIf(String codeRef, Predicate bool, Supplier... codeRefs) {
+        if (bool.test(codeRef)) {
+            this.codeRef = codeRef;
+            return;
+        }
+        for (Supplier supplier : codeRefs) {
+            codeRef = supplier.get();
+            if (bool.test(codeRef)) {
+                this.codeRef = codeRef;
+                return;
+            }
+        }
+    }
+
+    @Transient
+    public void setCodeRefIfNot(String codeRef, Predicate bool) {
+        if (!bool.test(codeRef)) {
+            this.codeRef = codeRef;
+        }
+    }
+
+    @Transient
+    public void setCodeRefIfNot(String codeRef, Predicate bool, Supplier... codeRefs) {
+        if (!bool.test(codeRef)) {
+            this.codeRef = codeRef;
+            return;
+        }
+        for (Supplier supplier : codeRefs) {
+            codeRef = supplier.get();
+            if (!bool.test(codeRef)) {
+                this.codeRef = codeRef;
+                return;
+            }
+        }
+    }
+
+    @Transient
+    public void setCodeRefIf(UnaryOperator codeRef) {
+        this.codeRef = codeRef.apply(this.codeRef);
+    }
+
+
+    /**
+     * Getter for win_grow_track.code_opt.
+     */
+    @Override
+    public String getCodeOpt() {
+        return this.codeOpt;
+    }
+
+    /**
+     * Setter for win_grow_track.code_opt.
+     */
+    @Override
+    public void setCodeOpt(String codeOpt) {
+        this.codeOpt = codeOpt;
+    }
+
+    @Transient
+    public void setCodeOptIf(String codeOpt, boolean bool) {
+        if (bool) {
+            this.codeOpt = codeOpt;
+        }
+    }
+
+    @Transient
+    public void setCodeOptIf(Supplier codeOpt, boolean bool) {
+        if (bool) {
+            this.codeOpt = codeOpt.get();
+        }
+    }
+
+    @Transient
+    public void setCodeOptIf(String codeOpt, Predicate bool) {
+        if (bool.test(codeOpt)) {
+            this.codeOpt = codeOpt;
+        }
+    }
+
+    @Transient
+    public void setCodeOptIf(String codeOpt, Predicate bool, Supplier... codeOpts) {
+        if (bool.test(codeOpt)) {
+            this.codeOpt = codeOpt;
+            return;
+        }
+        for (Supplier supplier : codeOpts) {
+            codeOpt = supplier.get();
+            if (bool.test(codeOpt)) {
+                this.codeOpt = codeOpt;
+                return;
+            }
+        }
+    }
+
+    @Transient
+    public void setCodeOptIfNot(String codeOpt, Predicate bool) {
+        if (!bool.test(codeOpt)) {
+            this.codeOpt = codeOpt;
+        }
+    }
+
+    @Transient
+    public void setCodeOptIfNot(String codeOpt, Predicate bool, Supplier... codeOpts) {
+        if (!bool.test(codeOpt)) {
+            this.codeOpt = codeOpt;
+            return;
+        }
+        for (Supplier supplier : codeOpts) {
+            codeOpt = supplier.get();
+            if (!bool.test(codeOpt)) {
+                this.codeOpt = codeOpt;
+                return;
+            }
+        }
+    }
+
+    @Transient
+    public void setCodeOptIf(UnaryOperator codeOpt) {
+        this.codeOpt = codeOpt.apply(this.codeOpt);
+    }
+
+
+    /**
+     * Getter for win_grow_track.word_ref.
+     */
+    @Override
+    public String getWordRef() {
+        return this.wordRef;
+    }
+
+    /**
+     * Setter for win_grow_track.word_ref.
+     */
+    @Override
+    public void setWordRef(String wordRef) {
+        this.wordRef = wordRef;
+    }
+
+    @Transient
+    public void setWordRefIf(String wordRef, boolean bool) {
+        if (bool) {
+            this.wordRef = wordRef;
+        }
+    }
+
+    @Transient
+    public void setWordRefIf(Supplier wordRef, boolean bool) {
+        if (bool) {
+            this.wordRef = wordRef.get();
+        }
+    }
+
+    @Transient
+    public void setWordRefIf(String wordRef, Predicate bool) {
+        if (bool.test(wordRef)) {
+            this.wordRef = wordRef;
+        }
+    }
+
+    @Transient
+    public void setWordRefIf(String wordRef, Predicate bool, Supplier... wordRefs) {
+        if (bool.test(wordRef)) {
+            this.wordRef = wordRef;
+            return;
+        }
+        for (Supplier supplier : wordRefs) {
+            wordRef = supplier.get();
+            if (bool.test(wordRef)) {
+                this.wordRef = wordRef;
+                return;
+            }
+        }
+    }
+
+    @Transient
+    public void setWordRefIfNot(String wordRef, Predicate bool) {
+        if (!bool.test(wordRef)) {
+            this.wordRef = wordRef;
+        }
+    }
+
+    @Transient
+    public void setWordRefIfNot(String wordRef, Predicate bool, Supplier... wordRefs) {
+        if (!bool.test(wordRef)) {
+            this.wordRef = wordRef;
+            return;
+        }
+        for (Supplier supplier : wordRefs) {
+            wordRef = supplier.get();
+            if (!bool.test(wordRef)) {
+                this.wordRef = wordRef;
+                return;
+            }
+        }
+    }
+
+    @Transient
+    public void setWordRefIf(UnaryOperator wordRef) {
+        this.wordRef = wordRef.apply(this.wordRef);
+    }
+
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj)
+            return true;
+        if (obj == null)
+            return false;
+        if (getClass() != obj.getClass())
+            return false;
+        final WinGrowTrack other = (WinGrowTrack) obj;
+        if (this.id == null) {
+            if (other.id != null)
+                return false;
+        }
+        else if (!this.id.equals(other.id))
+            return false;
+        if (this.createDt == null) {
+            if (other.createDt != null)
+                return false;
+        }
+        else if (!this.createDt.equals(other.createDt))
+            return false;
+        if (this.trackKey == null) {
+            if (other.trackKey != null)
+                return false;
+        }
+        else if (!this.trackKey.equals(other.trackKey))
+            return false;
+        if (this.trackRef == null) {
+            if (other.trackRef != null)
+                return false;
+        }
+        else if (!this.trackRef.equals(other.trackRef))
+            return false;
+        if (this.trackApp == null) {
+            if (other.trackApp != null)
+                return false;
+        }
+        else if (!this.trackApp.equals(other.trackApp))
+            return false;
+        if (this.trackEnv == null) {
+            if (other.trackEnv != null)
+                return false;
+        }
+        else if (!this.trackEnv.equals(other.trackEnv))
+            return false;
+        if (this.trackIns == null) {
+            if (other.trackIns != null)
+                return false;
+        }
+        else if (!this.trackIns.equals(other.trackIns))
+            return false;
+        if (this.trackOut == null) {
+            if (other.trackOut != null)
+                return false;
+        }
+        else if (!this.trackOut.equals(other.trackOut))
+            return false;
+        if (this.trackErr == null) {
+            if (other.trackErr != null)
+                return false;
+        }
+        else if (!this.trackErr.equals(other.trackErr))
+            return false;
+        if (this.elapseMs == null) {
+            if (other.elapseMs != null)
+                return false;
+        }
+        else if (!this.elapseMs.equals(other.elapseMs))
+            return false;
+        if (this.userKey == null) {
+            if (other.userKey != null)
+                return false;
+        }
+        else if (!this.userKey.equals(other.userKey))
+            return false;
+        if (this.userRef == null) {
+            if (other.userRef != null)
+                return false;
+        }
+        else if (!this.userRef.equals(other.userRef))
+            return false;
+        if (this.dataKey == null) {
+            if (other.dataKey != null)
+                return false;
+        }
+        else if (!this.dataKey.equals(other.dataKey))
+            return false;
+        if (this.dataRef == null) {
+            if (other.dataRef != null)
+                return false;
+        }
+        else if (!this.dataRef.equals(other.dataRef))
+            return false;
+        if (this.dataOpt == null) {
+            if (other.dataOpt != null)
+                return false;
+        }
+        else if (!this.dataOpt.equals(other.dataOpt))
+            return false;
+        if (this.codeKey == null) {
+            if (other.codeKey != null)
+                return false;
+        }
+        else if (!this.codeKey.equals(other.codeKey))
+            return false;
+        if (this.codeRef == null) {
+            if (other.codeRef != null)
+                return false;
+        }
+        else if (!this.codeRef.equals(other.codeRef))
+            return false;
+        if (this.codeOpt == null) {
+            if (other.codeOpt != null)
+                return false;
+        }
+        else if (!this.codeOpt.equals(other.codeOpt))
+            return false;
+        if (this.wordRef == null) {
+            if (other.wordRef != null)
+                return false;
+        }
+        else if (!this.wordRef.equals(other.wordRef))
+            return false;
+        return true;
+    }
+
+    @Override
+    public int hashCode() {
+        final int prime = 31;
+        int result = 1;
+        result = prime * result + ((this.id == null) ? 0 : this.id.hashCode());
+        result = prime * result + ((this.createDt == null) ? 0 : this.createDt.hashCode());
+        result = prime * result + ((this.trackKey == null) ? 0 : this.trackKey.hashCode());
+        result = prime * result + ((this.trackRef == null) ? 0 : this.trackRef.hashCode());
+        result = prime * result + ((this.trackApp == null) ? 0 : this.trackApp.hashCode());
+        result = prime * result + ((this.trackEnv == null) ? 0 : this.trackEnv.hashCode());
+        result = prime * result + ((this.trackIns == null) ? 0 : this.trackIns.hashCode());
+        result = prime * result + ((this.trackOut == null) ? 0 : this.trackOut.hashCode());
+        result = prime * result + ((this.trackErr == null) ? 0 : this.trackErr.hashCode());
+        result = prime * result + ((this.elapseMs == null) ? 0 : this.elapseMs.hashCode());
+        result = prime * result + ((this.userKey == null) ? 0 : this.userKey.hashCode());
+        result = prime * result + ((this.userRef == null) ? 0 : this.userRef.hashCode());
+        result = prime * result + ((this.dataKey == null) ? 0 : this.dataKey.hashCode());
+        result = prime * result + ((this.dataRef == null) ? 0 : this.dataRef.hashCode());
+        result = prime * result + ((this.dataOpt == null) ? 0 : this.dataOpt.hashCode());
+        result = prime * result + ((this.codeKey == null) ? 0 : this.codeKey.hashCode());
+        result = prime * result + ((this.codeRef == null) ? 0 : this.codeRef.hashCode());
+        result = prime * result + ((this.codeOpt == null) ? 0 : this.codeOpt.hashCode());
+        result = prime * result + ((this.wordRef == null) ? 0 : this.wordRef.hashCode());
+        return result;
+    }
+
+    @Override
+    public String toString() {
+        StringBuilder sb = new StringBuilder("WinGrowTrack (");
+
+        sb.append(id);
+        sb.append(", ").append(createDt);
+        sb.append(", ").append(trackKey);
+        sb.append(", ").append(trackRef);
+        sb.append(", ").append(trackApp);
+        sb.append(", ").append(trackEnv);
+        sb.append(", ").append(trackIns);
+        sb.append(", ").append(trackOut);
+        sb.append(", ").append(trackErr);
+        sb.append(", ").append(elapseMs);
+        sb.append(", ").append(userKey);
+        sb.append(", ").append(userRef);
+        sb.append(", ").append(dataKey);
+        sb.append(", ").append(dataRef);
+        sb.append(", ").append(dataOpt);
+        sb.append(", ").append(codeKey);
+        sb.append(", ").append(codeRef);
+        sb.append(", ").append(codeOpt);
+        sb.append(", ").append(wordRef);
+
+        sb.append(")");
+        return sb.toString();
+    }
+
+    // -------------------------------------------------------------------------
+    // FROM and INTO
+    // -------------------------------------------------------------------------
+
+    @Override
+    public void from(IWinGrowTrack from) {
+        setId(from.getId());
+        setCreateDt(from.getCreateDt());
+        setTrackKey(from.getTrackKey());
+        setTrackRef(from.getTrackRef());
+        setTrackApp(from.getTrackApp());
+        setTrackEnv(from.getTrackEnv());
+        setTrackIns(from.getTrackIns());
+        setTrackOut(from.getTrackOut());
+        setTrackErr(from.getTrackErr());
+        setElapseMs(from.getElapseMs());
+        setUserKey(from.getUserKey());
+        setUserRef(from.getUserRef());
+        setDataKey(from.getDataKey());
+        setDataRef(from.getDataRef());
+        setDataOpt(from.getDataOpt());
+        setCodeKey(from.getCodeKey());
+        setCodeRef(from.getCodeRef());
+        setCodeOpt(from.getCodeOpt());
+        setWordRef(from.getWordRef());
+    }
+
+    @Override
+    public  E into(E into) {
+        into.from(this);
+        return into;
+    }
+}
diff --git a/radiant/tiny-grow/src/main/java-gen/pro/fessional/wings/tiny/grow/database/autogen/tables/records/WinGrowTrackRecord.java b/radiant/tiny-grow/src/main/java-gen/pro/fessional/wings/tiny/grow/database/autogen/tables/records/WinGrowTrackRecord.java
new file mode 100644
index 000000000..70ec6ac55
--- /dev/null
+++ b/radiant/tiny-grow/src/main/java-gen/pro/fessional/wings/tiny/grow/database/autogen/tables/records/WinGrowTrackRecord.java
@@ -0,0 +1,888 @@
+/*
+ * This file is generated by jOOQ.
+ */
+package pro.fessional.wings.tiny.grow.database.autogen.tables.records;
+
+
+import org.jooq.Field;
+import org.jooq.Record1;
+import org.jooq.Record19;
+import org.jooq.Row19;
+import org.jooq.impl.UpdatableRecordImpl;
+import pro.fessional.wings.tiny.grow.database.autogen.tables.WinGrowTrackTable;
+import pro.fessional.wings.tiny.grow.database.autogen.tables.interfaces.IWinGrowTrack;
+import pro.fessional.wings.tiny.grow.database.autogen.tables.pojos.WinGrowTrack;
+
+import javax.annotation.processing.Generated;
+import java.time.LocalDateTime;
+
+
+/**
+ * The table wings.win_grow_track.
+ */
+@Generated(
+    value = {
+        "https://www.jooq.org",
+        "jOOQ version:3.18.9",
+        "schema version:2020102801"
+    },
+    comments = "This class is generated by jOOQ"
+)
+@SuppressWarnings({ "all", "unchecked", "rawtypes", "this-escape" })
+public class WinGrowTrackRecord extends UpdatableRecordImpl implements Record19, IWinGrowTrack {
+
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * Setter for win_grow_track.id.
+     */
+    @Override
+    public void setId(Long value) {
+        set(0, value);
+    }
+
+    /**
+     * Getter for win_grow_track.id.
+     */
+    @Override
+    public Long getId() {
+        return (Long) get(0);
+    }
+
+    /**
+     * Setter for win_grow_track.create_dt.
+     */
+    @Override
+    public void setCreateDt(LocalDateTime value) {
+        set(1, value);
+    }
+
+    /**
+     * Getter for win_grow_track.create_dt.
+     */
+    @Override
+    public LocalDateTime getCreateDt() {
+        return (LocalDateTime) get(1);
+    }
+
+    /**
+     * Setter for win_grow_track.track_key.
+     */
+    @Override
+    public void setTrackKey(String value) {
+        set(2, value);
+    }
+
+    /**
+     * Getter for win_grow_track.track_key.
+     */
+    @Override
+    public String getTrackKey() {
+        return (String) get(2);
+    }
+
+    /**
+     * Setter for win_grow_track.track_ref.
+     */
+    @Override
+    public void setTrackRef(String value) {
+        set(3, value);
+    }
+
+    /**
+     * Getter for win_grow_track.track_ref.
+     */
+    @Override
+    public String getTrackRef() {
+        return (String) get(3);
+    }
+
+    /**
+     * Setter for win_grow_track.track_app.
+     */
+    @Override
+    public void setTrackApp(String value) {
+        set(4, value);
+    }
+
+    /**
+     * Getter for win_grow_track.track_app.
+     */
+    @Override
+    public String getTrackApp() {
+        return (String) get(4);
+    }
+
+    /**
+     * Setter for win_grow_track.track_env.
+     */
+    @Override
+    public void setTrackEnv(String value) {
+        set(5, value);
+    }
+
+    /**
+     * Getter for win_grow_track.track_env.
+     */
+    @Override
+    public String getTrackEnv() {
+        return (String) get(5);
+    }
+
+    /**
+     * Setter for win_grow_track.track_ins.
+     */
+    @Override
+    public void setTrackIns(String value) {
+        set(6, value);
+    }
+
+    /**
+     * Getter for win_grow_track.track_ins.
+     */
+    @Override
+    public String getTrackIns() {
+        return (String) get(6);
+    }
+
+    /**
+     * Setter for win_grow_track.track_out.
+     */
+    @Override
+    public void setTrackOut(String value) {
+        set(7, value);
+    }
+
+    /**
+     * Getter for win_grow_track.track_out.
+     */
+    @Override
+    public String getTrackOut() {
+        return (String) get(7);
+    }
+
+    /**
+     * Setter for win_grow_track.track_err.
+     */
+    @Override
+    public void setTrackErr(String value) {
+        set(8, value);
+    }
+
+    /**
+     * Getter for win_grow_track.track_err.
+     */
+    @Override
+    public String getTrackErr() {
+        return (String) get(8);
+    }
+
+    /**
+     * Setter for win_grow_track.elapse_ms.
+     */
+    @Override
+    public void setElapseMs(Long value) {
+        set(9, value);
+    }
+
+    /**
+     * Getter for win_grow_track.elapse_ms.
+     */
+    @Override
+    public Long getElapseMs() {
+        return (Long) get(9);
+    }
+
+    /**
+     * Setter for win_grow_track.user_key.
+     */
+    @Override
+    public void setUserKey(Long value) {
+        set(10, value);
+    }
+
+    /**
+     * Getter for win_grow_track.user_key.
+     */
+    @Override
+    public Long getUserKey() {
+        return (Long) get(10);
+    }
+
+    /**
+     * Setter for win_grow_track.user_ref.
+     */
+    @Override
+    public void setUserRef(Long value) {
+        set(11, value);
+    }
+
+    /**
+     * Getter for win_grow_track.user_ref.
+     */
+    @Override
+    public Long getUserRef() {
+        return (Long) get(11);
+    }
+
+    /**
+     * Setter for win_grow_track.data_key.
+     */
+    @Override
+    public void setDataKey(Long value) {
+        set(12, value);
+    }
+
+    /**
+     * Getter for win_grow_track.data_key.
+     */
+    @Override
+    public Long getDataKey() {
+        return (Long) get(12);
+    }
+
+    /**
+     * Setter for win_grow_track.data_ref.
+     */
+    @Override
+    public void setDataRef(Long value) {
+        set(13, value);
+    }
+
+    /**
+     * Getter for win_grow_track.data_ref.
+     */
+    @Override
+    public Long getDataRef() {
+        return (Long) get(13);
+    }
+
+    /**
+     * Setter for win_grow_track.data_opt.
+     */
+    @Override
+    public void setDataOpt(Long value) {
+        set(14, value);
+    }
+
+    /**
+     * Getter for win_grow_track.data_opt.
+     */
+    @Override
+    public Long getDataOpt() {
+        return (Long) get(14);
+    }
+
+    /**
+     * Setter for win_grow_track.code_key.
+     */
+    @Override
+    public void setCodeKey(String value) {
+        set(15, value);
+    }
+
+    /**
+     * Getter for win_grow_track.code_key.
+     */
+    @Override
+    public String getCodeKey() {
+        return (String) get(15);
+    }
+
+    /**
+     * Setter for win_grow_track.code_ref.
+     */
+    @Override
+    public void setCodeRef(String value) {
+        set(16, value);
+    }
+
+    /**
+     * Getter for win_grow_track.code_ref.
+     */
+    @Override
+    public String getCodeRef() {
+        return (String) get(16);
+    }
+
+    /**
+     * Setter for win_grow_track.code_opt.
+     */
+    @Override
+    public void setCodeOpt(String value) {
+        set(17, value);
+    }
+
+    /**
+     * Getter for win_grow_track.code_opt.
+     */
+    @Override
+    public String getCodeOpt() {
+        return (String) get(17);
+    }
+
+    /**
+     * Setter for win_grow_track.word_ref.
+     */
+    @Override
+    public void setWordRef(String value) {
+        set(18, value);
+    }
+
+    /**
+     * Getter for win_grow_track.word_ref.
+     */
+    @Override
+    public String getWordRef() {
+        return (String) get(18);
+    }
+
+    // -------------------------------------------------------------------------
+    // Primary key information
+    // -------------------------------------------------------------------------
+
+    @Override
+    public Record1 key() {
+        return (Record1) super.key();
+    }
+
+    // -------------------------------------------------------------------------
+    // Record19 type implementation
+    // -------------------------------------------------------------------------
+
+    @Override
+    public Row19 fieldsRow() {
+        return (Row19) super.fieldsRow();
+    }
+
+    @Override
+    public Row19 valuesRow() {
+        return (Row19) super.valuesRow();
+    }
+
+    @Override
+    public Field field1() {
+        return WinGrowTrackTable.WinGrowTrack.Id;
+    }
+
+    @Override
+    public Field field2() {
+        return WinGrowTrackTable.WinGrowTrack.CreateDt;
+    }
+
+    @Override
+    public Field field3() {
+        return WinGrowTrackTable.WinGrowTrack.TrackKey;
+    }
+
+    @Override
+    public Field field4() {
+        return WinGrowTrackTable.WinGrowTrack.TrackRef;
+    }
+
+    @Override
+    public Field field5() {
+        return WinGrowTrackTable.WinGrowTrack.TrackApp;
+    }
+
+    @Override
+    public Field field6() {
+        return WinGrowTrackTable.WinGrowTrack.TrackEnv;
+    }
+
+    @Override
+    public Field field7() {
+        return WinGrowTrackTable.WinGrowTrack.TrackIns;
+    }
+
+    @Override
+    public Field field8() {
+        return WinGrowTrackTable.WinGrowTrack.TrackOut;
+    }
+
+    @Override
+    public Field field9() {
+        return WinGrowTrackTable.WinGrowTrack.TrackErr;
+    }
+
+    @Override
+    public Field field10() {
+        return WinGrowTrackTable.WinGrowTrack.ElapseMs;
+    }
+
+    @Override
+    public Field field11() {
+        return WinGrowTrackTable.WinGrowTrack.UserKey;
+    }
+
+    @Override
+    public Field field12() {
+        return WinGrowTrackTable.WinGrowTrack.UserRef;
+    }
+
+    @Override
+    public Field field13() {
+        return WinGrowTrackTable.WinGrowTrack.DataKey;
+    }
+
+    @Override
+    public Field field14() {
+        return WinGrowTrackTable.WinGrowTrack.DataRef;
+    }
+
+    @Override
+    public Field field15() {
+        return WinGrowTrackTable.WinGrowTrack.DataOpt;
+    }
+
+    @Override
+    public Field field16() {
+        return WinGrowTrackTable.WinGrowTrack.CodeKey;
+    }
+
+    @Override
+    public Field field17() {
+        return WinGrowTrackTable.WinGrowTrack.CodeRef;
+    }
+
+    @Override
+    public Field field18() {
+        return WinGrowTrackTable.WinGrowTrack.CodeOpt;
+    }
+
+    @Override
+    public Field field19() {
+        return WinGrowTrackTable.WinGrowTrack.WordRef;
+    }
+
+    @Override
+    public Long component1() {
+        return getId();
+    }
+
+    @Override
+    public LocalDateTime component2() {
+        return getCreateDt();
+    }
+
+    @Override
+    public String component3() {
+        return getTrackKey();
+    }
+
+    @Override
+    public String component4() {
+        return getTrackRef();
+    }
+
+    @Override
+    public String component5() {
+        return getTrackApp();
+    }
+
+    @Override
+    public String component6() {
+        return getTrackEnv();
+    }
+
+    @Override
+    public String component7() {
+        return getTrackIns();
+    }
+
+    @Override
+    public String component8() {
+        return getTrackOut();
+    }
+
+    @Override
+    public String component9() {
+        return getTrackErr();
+    }
+
+    @Override
+    public Long component10() {
+        return getElapseMs();
+    }
+
+    @Override
+    public Long component11() {
+        return getUserKey();
+    }
+
+    @Override
+    public Long component12() {
+        return getUserRef();
+    }
+
+    @Override
+    public Long component13() {
+        return getDataKey();
+    }
+
+    @Override
+    public Long component14() {
+        return getDataRef();
+    }
+
+    @Override
+    public Long component15() {
+        return getDataOpt();
+    }
+
+    @Override
+    public String component16() {
+        return getCodeKey();
+    }
+
+    @Override
+    public String component17() {
+        return getCodeRef();
+    }
+
+    @Override
+    public String component18() {
+        return getCodeOpt();
+    }
+
+    @Override
+    public String component19() {
+        return getWordRef();
+    }
+
+    @Override
+    public Long value1() {
+        return getId();
+    }
+
+    @Override
+    public LocalDateTime value2() {
+        return getCreateDt();
+    }
+
+    @Override
+    public String value3() {
+        return getTrackKey();
+    }
+
+    @Override
+    public String value4() {
+        return getTrackRef();
+    }
+
+    @Override
+    public String value5() {
+        return getTrackApp();
+    }
+
+    @Override
+    public String value6() {
+        return getTrackEnv();
+    }
+
+    @Override
+    public String value7() {
+        return getTrackIns();
+    }
+
+    @Override
+    public String value8() {
+        return getTrackOut();
+    }
+
+    @Override
+    public String value9() {
+        return getTrackErr();
+    }
+
+    @Override
+    public Long value10() {
+        return getElapseMs();
+    }
+
+    @Override
+    public Long value11() {
+        return getUserKey();
+    }
+
+    @Override
+    public Long value12() {
+        return getUserRef();
+    }
+
+    @Override
+    public Long value13() {
+        return getDataKey();
+    }
+
+    @Override
+    public Long value14() {
+        return getDataRef();
+    }
+
+    @Override
+    public Long value15() {
+        return getDataOpt();
+    }
+
+    @Override
+    public String value16() {
+        return getCodeKey();
+    }
+
+    @Override
+    public String value17() {
+        return getCodeRef();
+    }
+
+    @Override
+    public String value18() {
+        return getCodeOpt();
+    }
+
+    @Override
+    public String value19() {
+        return getWordRef();
+    }
+
+    @Override
+    public WinGrowTrackRecord value1(Long value) {
+        setId(value);
+        return this;
+    }
+
+    @Override
+    public WinGrowTrackRecord value2(LocalDateTime value) {
+        setCreateDt(value);
+        return this;
+    }
+
+    @Override
+    public WinGrowTrackRecord value3(String value) {
+        setTrackKey(value);
+        return this;
+    }
+
+    @Override
+    public WinGrowTrackRecord value4(String value) {
+        setTrackRef(value);
+        return this;
+    }
+
+    @Override
+    public WinGrowTrackRecord value5(String value) {
+        setTrackApp(value);
+        return this;
+    }
+
+    @Override
+    public WinGrowTrackRecord value6(String value) {
+        setTrackEnv(value);
+        return this;
+    }
+
+    @Override
+    public WinGrowTrackRecord value7(String value) {
+        setTrackIns(value);
+        return this;
+    }
+
+    @Override
+    public WinGrowTrackRecord value8(String value) {
+        setTrackOut(value);
+        return this;
+    }
+
+    @Override
+    public WinGrowTrackRecord value9(String value) {
+        setTrackErr(value);
+        return this;
+    }
+
+    @Override
+    public WinGrowTrackRecord value10(Long value) {
+        setElapseMs(value);
+        return this;
+    }
+
+    @Override
+    public WinGrowTrackRecord value11(Long value) {
+        setUserKey(value);
+        return this;
+    }
+
+    @Override
+    public WinGrowTrackRecord value12(Long value) {
+        setUserRef(value);
+        return this;
+    }
+
+    @Override
+    public WinGrowTrackRecord value13(Long value) {
+        setDataKey(value);
+        return this;
+    }
+
+    @Override
+    public WinGrowTrackRecord value14(Long value) {
+        setDataRef(value);
+        return this;
+    }
+
+    @Override
+    public WinGrowTrackRecord value15(Long value) {
+        setDataOpt(value);
+        return this;
+    }
+
+    @Override
+    public WinGrowTrackRecord value16(String value) {
+        setCodeKey(value);
+        return this;
+    }
+
+    @Override
+    public WinGrowTrackRecord value17(String value) {
+        setCodeRef(value);
+        return this;
+    }
+
+    @Override
+    public WinGrowTrackRecord value18(String value) {
+        setCodeOpt(value);
+        return this;
+    }
+
+    @Override
+    public WinGrowTrackRecord value19(String value) {
+        setWordRef(value);
+        return this;
+    }
+
+    @Override
+    public WinGrowTrackRecord values(Long value1, LocalDateTime value2, String value3, String value4, String value5, String value6, String value7, String value8, String value9, Long value10, Long value11, Long value12, Long value13, Long value14, Long value15, String value16, String value17, String value18, String value19) {
+        value1(value1);
+        value2(value2);
+        value3(value3);
+        value4(value4);
+        value5(value5);
+        value6(value6);
+        value7(value7);
+        value8(value8);
+        value9(value9);
+        value10(value10);
+        value11(value11);
+        value12(value12);
+        value13(value13);
+        value14(value14);
+        value15(value15);
+        value16(value16);
+        value17(value17);
+        value18(value18);
+        value19(value19);
+        return this;
+    }
+
+    // -------------------------------------------------------------------------
+    // FROM and INTO
+    // -------------------------------------------------------------------------
+
+    @Override
+    public void from(IWinGrowTrack from) {
+        setId(from.getId());
+        setCreateDt(from.getCreateDt());
+        setTrackKey(from.getTrackKey());
+        setTrackRef(from.getTrackRef());
+        setTrackApp(from.getTrackApp());
+        setTrackEnv(from.getTrackEnv());
+        setTrackIns(from.getTrackIns());
+        setTrackOut(from.getTrackOut());
+        setTrackErr(from.getTrackErr());
+        setElapseMs(from.getElapseMs());
+        setUserKey(from.getUserKey());
+        setUserRef(from.getUserRef());
+        setDataKey(from.getDataKey());
+        setDataRef(from.getDataRef());
+        setDataOpt(from.getDataOpt());
+        setCodeKey(from.getCodeKey());
+        setCodeRef(from.getCodeRef());
+        setCodeOpt(from.getCodeOpt());
+        setWordRef(from.getWordRef());
+        resetChangedOnNotNull();
+    }
+
+    @Override
+    public  E into(E into) {
+        into.from(this);
+        return into;
+    }
+
+    // -------------------------------------------------------------------------
+    // Constructors
+    // -------------------------------------------------------------------------
+
+    /**
+     * Create a detached WinGrowTrackRecord
+     */
+    public WinGrowTrackRecord() {
+        super(WinGrowTrackTable.WinGrowTrack);
+    }
+
+    /**
+     * Create a detached, initialised WinGrowTrackRecord
+     */
+    public WinGrowTrackRecord(Long id, LocalDateTime createDt, String trackKey, String trackRef, String trackApp, String trackEnv, String trackIns, String trackOut, String trackErr, Long elapseMs, Long userKey, Long userRef, Long dataKey, Long dataRef, Long dataOpt, String codeKey, String codeRef, String codeOpt, String wordRef) {
+        super(WinGrowTrackTable.WinGrowTrack);
+
+        setId(id);
+        setCreateDt(createDt);
+        setTrackKey(trackKey);
+        setTrackRef(trackRef);
+        setTrackApp(trackApp);
+        setTrackEnv(trackEnv);
+        setTrackIns(trackIns);
+        setTrackOut(trackOut);
+        setTrackErr(trackErr);
+        setElapseMs(elapseMs);
+        setUserKey(userKey);
+        setUserRef(userRef);
+        setDataKey(dataKey);
+        setDataRef(dataRef);
+        setDataOpt(dataOpt);
+        setCodeKey(codeKey);
+        setCodeRef(codeRef);
+        setCodeOpt(codeOpt);
+        setWordRef(wordRef);
+        resetChangedOnNotNull();
+    }
+
+    /**
+     * Create a detached, initialised WinGrowTrackRecord
+     */
+    public WinGrowTrackRecord(WinGrowTrack value) {
+        super(WinGrowTrackTable.WinGrowTrack);
+
+        if (value != null) {
+            setId(value.getId());
+            setCreateDt(value.getCreateDt());
+            setTrackKey(value.getTrackKey());
+            setTrackRef(value.getTrackRef());
+            setTrackApp(value.getTrackApp());
+            setTrackEnv(value.getTrackEnv());
+            setTrackIns(value.getTrackIns());
+            setTrackOut(value.getTrackOut());
+            setTrackErr(value.getTrackErr());
+            setElapseMs(value.getElapseMs());
+            setUserKey(value.getUserKey());
+            setUserRef(value.getUserRef());
+            setDataKey(value.getDataKey());
+            setDataRef(value.getDataRef());
+            setDataOpt(value.getDataOpt());
+            setCodeKey(value.getCodeKey());
+            setCodeRef(value.getCodeRef());
+            setCodeOpt(value.getCodeOpt());
+            setWordRef(value.getWordRef());
+            resetChangedOnNotNull();
+        }
+    }
+}
diff --git a/radiant/tiny-grow/src/main/java/pro/fessional/wings/tiny/grow/spring/bean/TinyTrackConfiguration.java b/radiant/tiny-grow/src/main/java/pro/fessional/wings/tiny/grow/spring/bean/TinyTrackConfiguration.java
new file mode 100644
index 000000000..3fd007bac
--- /dev/null
+++ b/radiant/tiny-grow/src/main/java/pro/fessional/wings/tiny/grow/spring/bean/TinyTrackConfiguration.java
@@ -0,0 +1,31 @@
+package pro.fessional.wings.tiny.grow.spring.bean;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.springframework.context.annotation.ComponentScan;
+import org.springframework.context.annotation.Configuration;
+import pro.fessional.wings.silencer.spring.boot.ConditionalWingsEnabled;
+import pro.fessional.wings.tiny.grow.database.TinyGrowDatabase;
+import pro.fessional.wings.tiny.grow.track.TinyTrackService;
+
+
+/**
+ * @author trydofor
+ * @since 2024-07-27
+ */
+
+@Configuration(proxyBeanMethods = false)
+@ConditionalWingsEnabled
+public class TinyTrackConfiguration {
+
+    private static final Log log = LogFactory.getLog(TinyTrackConfiguration.class);
+
+    @Configuration(proxyBeanMethods = false)
+    @ConditionalWingsEnabled
+    @ComponentScan(basePackageClasses = { TinyGrowDatabase.class, TinyTrackService.class })
+    public static class DaoServScan {
+        public DaoServScan() {
+            log.info("TinyGrow spring-scan database, service");
+        }
+    }
+}
diff --git a/radiant/tiny-grow/src/main/java/pro/fessional/wings/tiny/grow/spring/conf/TinyGrowAutoConfiguration.java b/radiant/tiny-grow/src/main/java/pro/fessional/wings/tiny/grow/spring/conf/TinyGrowAutoConfiguration.java
new file mode 100644
index 000000000..9f0df9b47
--- /dev/null
+++ b/radiant/tiny-grow/src/main/java/pro/fessional/wings/tiny/grow/spring/conf/TinyGrowAutoConfiguration.java
@@ -0,0 +1,19 @@
+package pro.fessional.wings.tiny.grow.spring.conf;
+
+import org.springframework.boot.autoconfigure.AutoConfiguration;
+import org.springframework.boot.context.properties.ConfigurationPropertiesScan;
+import org.springframework.context.annotation.Import;
+import pro.fessional.wings.silencer.spring.boot.ConditionalWingsEnabled;
+import pro.fessional.wings.tiny.grow.spring.bean.TinyTrackConfiguration;
+import pro.fessional.wings.tiny.grow.spring.prop.TinyTrackExcludeProp;
+
+/**
+ * @author trydofor
+ * @since 2024-07-27
+ */
+@AutoConfiguration
+@ConditionalWingsEnabled
+@ConfigurationPropertiesScan(basePackageClasses = TinyTrackExcludeProp.class)
+@Import(TinyTrackConfiguration.class)
+public class TinyGrowAutoConfiguration {
+}
diff --git a/radiant/tiny-grow/src/main/java/pro/fessional/wings/tiny/grow/spring/prop/TinyTrackExcludeProp.java b/radiant/tiny-grow/src/main/java/pro/fessional/wings/tiny/grow/spring/prop/TinyTrackExcludeProp.java
new file mode 100644
index 000000000..088827086
--- /dev/null
+++ b/radiant/tiny-grow/src/main/java/pro/fessional/wings/tiny/grow/spring/prop/TinyTrackExcludeProp.java
@@ -0,0 +1,45 @@
+package pro.fessional.wings.tiny.grow.spring.prop;
+
+import lombok.Data;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+
+import java.util.Collections;
+import java.util.Map;
+import java.util.regex.Pattern;
+
+import static pro.fessional.wings.tiny.grow.spring.prop.TinyTrackExcludeProp.Key;
+
+/**
+ * @author trydofor
+ * @since 2024-07-27
+ */
+@Data
+@ConfigurationProperties(Key)
+public class TinyTrackExcludeProp {
+
+    public static final String Key = "wings.tiny.grow.track.exclude";
+
+    /**
+     * exclude the property if it is instance of
+     *
+     * @see #Key$clazz
+     */
+    private Map> clazz = Collections.emptyMap();
+    public static final String Key$clazz = Key + ".clazz";
+
+    /**
+     * exclude the property if its name equals
+     *
+     * @see #Key$equal
+     */
+    private Map equal = Collections.emptyMap();
+    public static final String Key$equal = Key + ".equal";
+
+    /**
+     * exclude the property if its name match regex
+     *
+     * @see #Key$regex
+     */
+    private Map regex = Collections.emptyMap();
+    public static final String Key$regex = Key + ".regex";
+}
diff --git a/radiant/tiny-grow/src/main/java/pro/fessional/wings/tiny/grow/track/TinyTrackHelper.java b/radiant/tiny-grow/src/main/java/pro/fessional/wings/tiny/grow/track/TinyTrackHelper.java
new file mode 100644
index 000000000..0a52110ee
--- /dev/null
+++ b/radiant/tiny-grow/src/main/java/pro/fessional/wings/tiny/grow/track/TinyTrackHelper.java
@@ -0,0 +1,30 @@
+package pro.fessional.wings.tiny.grow.track;
+
+import org.jetbrains.annotations.NotNull;
+import org.springframework.util.function.SingletonSupplier;
+import pro.fessional.wings.silencer.spring.help.ApplicationContextHelper;
+
+import java.util.function.Consumer;
+
+/**
+ * @author trydofor
+ * @since 2024-07-25
+ */
+public class TinyTrackHelper {
+
+    public static SingletonSupplier TrackService = ApplicationContextHelper.getSingletonSupplier(TinyTrackService.class);
+
+    /**
+     * never throw
+     */
+    public static void track(Consumer fulfill) {
+
+    }
+
+    /**
+     * never throw
+     */
+    public static void track(@NotNull String key, @NotNull String ref, @NotNull Consumer fulfill) {
+
+    }
+}
diff --git a/radiant/tiny-grow/src/main/java/pro/fessional/wings/tiny/grow/track/TinyTrackService.java b/radiant/tiny-grow/src/main/java/pro/fessional/wings/tiny/grow/track/TinyTrackService.java
new file mode 100644
index 000000000..932bec7ad
--- /dev/null
+++ b/radiant/tiny-grow/src/main/java/pro/fessional/wings/tiny/grow/track/TinyTrackService.java
@@ -0,0 +1,118 @@
+package pro.fessional.wings.tiny.grow.track;
+
+import lombok.Data;
+import org.jetbrains.annotations.NotNull;
+import pro.fessional.mirana.cast.EnumConvertor;
+import pro.fessional.mirana.cast.MethodConvertor;
+
+import java.lang.reflect.Method;
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+/**
+ * Data tracking in async, never throws
+ *
+ * @author trydofor
+ * @since 2024-07-24
+ */
+public interface TinyTrackService {
+
+    /**
+     * async executor
+     */
+    void async(Runnable run);
+
+    /**
+     * begin a tracking with key and ref
+     */
+    @NotNull
+    Tracking begin(@NotNull String key, @NotNull String ref);
+
+    /**
+     * post the tracking, fire and forget, never throws
+     */
+    void track(@NotNull Tracking tracking, boolean async);
+
+    /**
+     * async post the tracking, fire and forget, never throws
+     */
+    default void track(@NotNull Tracking tracking) {
+        track(tracking, true);
+    }
+
+    /**
+     * raw string key and 'string' ref
+     */
+    @NotNull
+    default Tracking begin(@NotNull String key) {
+        return begin(key, "string");
+    }
+
+    /**
+     * method signature key and 'method' ref.
+     * e.g. a.b.c.MyClass#method(String,int)
+     */
+    @NotNull
+    default Tracking begin(@NotNull Method key) {
+        String str = MethodConvertor.method2Str(key);
+        return begin(str, "method");
+    }
+
+    /**
+     * enum signature key and 'enum' ref.
+     * e.g. a.b.c.MyEnum#Name
+     */
+    @NotNull
+    default Tracking begin(@NotNull Enum key) {
+        String str = EnumConvertor.enum2Str(key);
+        return begin(str, "enum");
+    }
+
+    /**
+     * collect tracking to different impl, e.g. Dao to database
+     */
+    interface Collector {
+        void collect(Tracking tracking);
+    }
+
+    @Data
+    class Tracking {
+        private final long begin;
+        private final String key;
+        private final String ref;
+
+        private String app;
+        @NotNull
+        private Map env = new LinkedHashMap<>();
+        @NotNull
+        private Object[] ins = new Object[0];
+        private Object out;
+        private Throwable err;
+        private long elapse;
+
+        private long userKey;
+        private long userRef;
+
+        private long dataKey;
+        private long dataRef;
+        private long dataOpt;
+
+        private String codeKey;
+        private String codeRef;
+        private String codeOpt;
+
+        private String wordRef;
+
+        public void setIns(Object... ins) {
+            this.ins = ins;
+        }
+
+        public void addEnv(String key, Object value) {
+            env.put(key, value);
+        }
+
+        public void addEnv(Map envs) {
+            env.putAll(envs);
+        }
+    }
+}
diff --git a/radiant/tiny-grow/src/main/java/pro/fessional/wings/tiny/grow/track/TinyTracker.java b/radiant/tiny-grow/src/main/java/pro/fessional/wings/tiny/grow/track/TinyTracker.java
new file mode 100644
index 000000000..4fa9b70f7
--- /dev/null
+++ b/radiant/tiny-grow/src/main/java/pro/fessional/wings/tiny/grow/track/TinyTracker.java
@@ -0,0 +1,40 @@
+package pro.fessional.wings.tiny.grow.track;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * data tracking by AOP
+ *
+ * @author trydofor
+ * @since 2024-07-24
+ */
+@Target({ ElementType.METHOD })
+@Retention(RetentionPolicy.RUNTIME)
+public @interface TinyTracker {
+
+    /**
+     * track key instead of AOP auto
+     */
+    String key() default "";
+
+    /**
+     * track ref instead of AOP auto
+     */
+    String ref() default "";
+
+    /**
+     * 
+     * The name of this AOP object's method that will mix the `Tracking` after return/throw,
+     * its parameters is the `Tracking` prepended to the parameters of the AOP method.
+     *
+     * * saveOrder(long, Order) - the AOP method
+     * * saveOrder(Tracking, long, Order) - same as AOP method if mix is empty
+     * * saveOrderMix(Tracking, long, Order) - if mix is saveOrderMix
+     * 
+ * @see TinyTrackService.Tracking + */ + String mix() default ""; +} diff --git a/radiant/tiny-grow/src/main/java/pro/fessional/wings/tiny/grow/track/impl/TinyTrackAround.java b/radiant/tiny-grow/src/main/java/pro/fessional/wings/tiny/grow/track/impl/TinyTrackAround.java new file mode 100644 index 000000000..e53636015 --- /dev/null +++ b/radiant/tiny-grow/src/main/java/pro/fessional/wings/tiny/grow/track/impl/TinyTrackAround.java @@ -0,0 +1,153 @@ +package pro.fessional.wings.tiny.grow.track.impl; + +import lombok.Setter; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.aspectj.lang.JoinPoint; +import org.aspectj.lang.ProceedingJoinPoint; +import org.aspectj.lang.annotation.Around; +import org.aspectj.lang.annotation.Aspect; +import org.aspectj.lang.reflect.MethodSignature; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.annotation.Order; +import org.springframework.stereotype.Component; +import pro.fessional.mirana.cast.MethodConvertor; +import pro.fessional.mirana.data.Null; +import pro.fessional.mirana.time.ThreadNow; +import pro.fessional.wings.silencer.spring.WingsOrdered; +import pro.fessional.wings.silencer.spring.boot.ConditionalWingsEnabled; +import pro.fessional.wings.slardar.context.TerminalContext; +import pro.fessional.wings.tiny.grow.track.TinyTrackService; +import pro.fessional.wings.tiny.grow.track.TinyTrackService.Tracking; +import pro.fessional.wings.tiny.grow.track.TinyTracker; + +import java.lang.reflect.Method; +import java.util.concurrent.ConcurrentHashMap; + +/** + * @author trydofor + * @since 2024-07-24 + */ +@Aspect +@Component +@ConditionalWingsEnabled +@Order(WingsOrdered.Lv3Service) +@Slf4j +public class TinyTrackAround { + + @Setter(onMethod_ = { @Autowired }) + protected TinyTrackService tinyTrackService; + + @Around("@annotation(pro.fessional.wings.tiny.grow.track.TinyTracker)") + public Object track(ProceedingJoinPoint joinPoint) throws Throwable { + final Method method = ((MethodSignature) joinPoint.getSignature()).getMethod(); + final TinyTracker anno = method.getAnnotation(TinyTracker.class); + + final Tracking tracking = tryTrack(method, anno); + if (tracking == null) { + return joinPoint.proceed(); + } + + try { + tracking.setIns(joinPoint.getArgs()); + Object out = joinPoint.proceed(); + tracking.setOut(out); + return out; + } + catch (Throwable e) { + tracking.setErr(e); + throw e; + } + finally { + try { + mixAsync(tracking, method, anno, joinPoint); + } + catch (Throwable e) { + log.error("tiny-track fails to mixAsync, method=" + MethodConvertor.method2Str(method), e); + } + } + } + + protected void mixAsync(@NotNull Tracking tracking, @NotNull Method method, @NotNull TinyTracker anno, @NotNull JoinPoint joinPoint) { + // biz thread + tracking.setElapse(ThreadNow.millis() - tracking.getBegin()); + mixTrackEnv(tracking); + + // async thread + tinyTrackService.async(() -> { + final Method mix = findMixer(method, anno); + if (!Null.asNull(mix)) { + try { + Object[] pm = joinPoint.getArgs(); + Object[] pn = new Object[pm.length + 1]; + pn[0] = tracking; + System.arraycopy(pm, 0, pn, 1, pm.length); + mix.invoke(joinPoint.getTarget(), pn); + } + catch (Exception e) { + log.error("tiny-track fails to mix=" + MethodConvertor.method2Str(mix), e); + } + } + // track + tinyTrackService.track(tracking, false); + }); + } + + protected void mixTrackEnv(@NotNull Tracking tracking) { + final TerminalContext.Context ctx = TerminalContext.get(false); + if (!ctx.isNull()) { + tracking.addEnv("userId", ctx.getUserId()); + tracking.addEnv("locale", ctx.getLocale().toLanguageTag()); + tracking.addEnv("zoneid", ctx.getZoneId().getId()); + tracking.addEnv("authType", ctx.getAuthType().name()); + tracking.addEnv("username", ctx.getUsername()); + } + } + + @Nullable + protected Tracking tryTrack(@NotNull Method method, @NotNull TinyTracker anno) { + try { + final String key = anno.key(); + if (StringUtils.isEmpty(key)) { + return tinyTrackService.begin(method); + } + + String ref = anno.ref(); + if (StringUtils.isEmpty(ref)) { + return tinyTrackService.begin(key); + } + + return tinyTrackService.begin(key, ref); + } + catch (Exception e) { + log.error("tiny-track fails to beginTracking, method=" + MethodConvertor.method2Str(method), e); + return null; + } + } + + private final ConcurrentHashMap mixMethod = new ConcurrentHashMap<>(); + + @Nullable + protected Method findMixer(@NotNull Method method, @NotNull TinyTracker anno) { + return mixMethod.computeIfAbsent(method, k -> { + try { + String nm = anno.mix(); + if (nm == null || nm.isBlank()) { + nm = method.getName(); + } + Class[] pm = method.getParameterTypes(); + Class[] pn = new Class[pm.length + 1]; + pn[0] = Tracking.class; + System.arraycopy(pm, 0, pn, 1, pm.length); + Method md = method.getDeclaringClass().getDeclaredMethod(nm, pn); + md.setAccessible(true); + return md; + } + catch (Exception e) { + return Null.Mtd; + } + }); + } +} diff --git a/radiant/tiny-grow/src/main/java/pro/fessional/wings/tiny/grow/track/impl/TinyTrackCollectorDaoImpl.java b/radiant/tiny-grow/src/main/java/pro/fessional/wings/tiny/grow/track/impl/TinyTrackCollectorDaoImpl.java new file mode 100644 index 000000000..52bfa5c06 --- /dev/null +++ b/radiant/tiny-grow/src/main/java/pro/fessional/wings/tiny/grow/track/impl/TinyTrackCollectorDaoImpl.java @@ -0,0 +1,101 @@ +package pro.fessional.wings.tiny.grow.track.impl; + +import lombok.Setter; +import org.jetbrains.annotations.NotNull; +import org.springframework.beans.factory.InitializingBean; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import pro.fessional.mirana.pain.ThrowableUtil; +import pro.fessional.mirana.time.DateLocaling; +import pro.fessional.wings.faceless.service.lightid.LightIdService; +import pro.fessional.wings.silencer.spring.boot.ConditionalWingsEnabled; +import pro.fessional.wings.slardar.fastjson.FastJsonHelper; +import pro.fessional.wings.slardar.fastjson.filter.ExcludePropertyPreFilter; +import pro.fessional.wings.tiny.grow.database.autogen.tables.daos.WinGrowTrackDao; +import pro.fessional.wings.tiny.grow.database.autogen.tables.pojos.WinGrowTrack; +import pro.fessional.wings.tiny.grow.spring.prop.TinyTrackExcludeProp; +import pro.fessional.wings.tiny.grow.track.TinyTrackService; + +import java.util.Map; + +/** + * @author trydofor + * @since 2024-07-27 + */ +@Service +@ConditionalWingsEnabled +public class TinyTrackCollectorDaoImpl implements TinyTrackService.Collector, InitializingBean { + + @Setter(onMethod_ = { @Autowired }) + protected WinGrowTrackDao winGrowTrackDao; + + @Setter(onMethod_ = { @Autowired }) + protected LightIdService lightIdService; + + @Setter(onMethod_ = { @Autowired }) + protected TinyTrackExcludeProp tinyTrackExcludeProp; + + protected ExcludePropertyPreFilter excludePropertyPreFilter; + + @Override + @Transactional + public void collect(TinyTrackService.Tracking tracking) { + WinGrowTrack pojo = new WinGrowTrack(); + pojo.setId(lightIdService.getId(winGrowTrackDao.getTable())); + buildPojo(pojo, tracking); + winGrowTrackDao.insert(pojo); + } + + @Override + public void afterPropertiesSet() { + excludePropertyPreFilter = new ExcludePropertyPreFilter(); + excludePropertyPreFilter.addClazz(tinyTrackExcludeProp.getClazz().values()); + excludePropertyPreFilter.addEqual(tinyTrackExcludeProp.getEqual().values()); + excludePropertyPreFilter.addRegex(tinyTrackExcludeProp.getRegex().values()); + } + + protected void buildPojo(@NotNull WinGrowTrack pojo, @NotNull TinyTrackService.Tracking tracking) { + pojo.setCreateDt(DateLocaling.sysLdt(tracking.getBegin())); + + pojo.setTrackKey(tracking.getKey()); + pojo.setTrackRef(tracking.getRef()); + pojo.setTrackApp(tracking.getApp()); + + pojo.setTrackEnv(encodeEnv(tracking.getEnv())); + pojo.setTrackIns(encodeIns(tracking.getIns())); + pojo.setTrackOut(encodeOut(tracking.getOut())); + pojo.setTrackErr(encodeErr(tracking.getErr())); + + pojo.setElapseMs(tracking.getElapse()); + + pojo.setUserKey(tracking.getUserKey()); + pojo.setUserRef(tracking.getUserRef()); + + pojo.setDataKey(tracking.getDataKey()); + pojo.setDataRef(tracking.getDataRef()); + pojo.setDataOpt(tracking.getDataOpt()); + + pojo.setCodeKey(tracking.getCodeKey()); + pojo.setCodeRef(tracking.getCodeRef()); + pojo.setCodeOpt(tracking.getCodeOpt()); + + pojo.setWordRef(tracking.getWordRef()); + } + + protected String encodeEnv(Map env) { + return FastJsonHelper.string(env, excludePropertyPreFilter); + } + + protected String encodeIns(Object[] ins) { + return FastJsonHelper.string(ins, excludePropertyPreFilter); + } + + protected String encodeOut(Object out) { + return FastJsonHelper.string(out, excludePropertyPreFilter); + } + + protected String encodeErr(Throwable err) { + return ThrowableUtil.toString(err); + } +} diff --git a/radiant/tiny-grow/src/main/java/pro/fessional/wings/tiny/grow/track/impl/TinyTrackServiceImpl.java b/radiant/tiny-grow/src/main/java/pro/fessional/wings/tiny/grow/track/impl/TinyTrackServiceImpl.java new file mode 100644 index 000000000..5635f4026 --- /dev/null +++ b/radiant/tiny-grow/src/main/java/pro/fessional/wings/tiny/grow/track/impl/TinyTrackServiceImpl.java @@ -0,0 +1,84 @@ +package pro.fessional.wings.tiny.grow.track.impl; + +import com.alibaba.ttl.threadpool.TtlExecutors; +import lombok.Setter; +import lombok.extern.slf4j.Slf4j; +import org.jetbrains.annotations.NotNull; +import org.springframework.beans.factory.InitializingBean; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.stereotype.Service; +import pro.fessional.mirana.time.ThreadNow; +import pro.fessional.wings.silencer.modulate.RuntimeMode; +import pro.fessional.wings.silencer.spring.boot.ConditionalWingsEnabled; +import pro.fessional.wings.silencer.spring.help.ApplicationContextHelper; +import pro.fessional.wings.tiny.grow.track.TinyTrackService; + +import java.util.List; +import java.util.concurrent.Executor; +import java.util.concurrent.Executors; + +import static org.springframework.scheduling.annotation.AsyncAnnotationBeanPostProcessor.DEFAULT_TASK_EXECUTOR_BEAN_NAME; + +/** + * @author trydofor + * @since 2024-07-26 + */ +@Service +@ConditionalWingsEnabled +@Slf4j +public class TinyTrackServiceImpl implements TinyTrackService, InitializingBean { + + @Setter(onMethod_ = { @Autowired(required = false), @Qualifier(DEFAULT_TASK_EXECUTOR_BEAN_NAME) }) + private Executor executor; + + @Setter(onMethod_ = { @Autowired }) + protected List trackCollector; + + + @Override + public void async(Runnable run) { + executor.execute(run); + } + + @Override + @NotNull + public Tracking begin(@NotNull String key, @NotNull String ref) { + final Tracking tracking = new Tracking(ThreadNow.millis(), key, ref); + + tracking.setApp(ApplicationContextHelper.getApplicationName()); + tracking.addEnv("run", RuntimeMode.getRunMode().name()); + + return tracking; + } + + @Override + public void track(@NotNull Tracking tracking, boolean async) { + if (async) { + executor.execute(() -> track(tracking)); + } + else { + track(tracking); + } + } + + @Override + public void track(@NotNull Tracking tracking) { + for (Collector cl : trackCollector) { + try { + cl.collect(tracking); + } + catch (Exception e) { + log.error("tiny-track skip failed collector=" + cl.getClass(), e); + } + } + } + + @Override + public void afterPropertiesSet() throws Exception { + if (executor == null) { + log.warn("should reuse autowired thread pool"); + executor = TtlExecutors.getTtlExecutor(Executors.newWorkStealingPool(2)); + } + } +} diff --git a/radiant/tiny-grow/src/main/resources/META-INF/additional-spring-configuration-metadata.json b/radiant/tiny-grow/src/main/resources/META-INF/additional-spring-configuration-metadata.json new file mode 100644 index 000000000..45ff386ec --- /dev/null +++ b/radiant/tiny-grow/src/main/resources/META-INF/additional-spring-configuration-metadata.json @@ -0,0 +1,17 @@ +{ + "groups": [ + {"name": "wings.enabled.pro.fessional.wings.tiny.grow.spring.conf"}, + {"name": "wings.enabled.pro.fessional.wings.tiny.grow.spring.bean"} + ], + "properties": [ + {"name": "wings.enabled.pro.fessional.wings.tiny.grow.spring.conf.TinyGrowAutoConfiguration", "type": "java.lang.Boolean"}, + + {"name": "wings.enabled.pro.fessional.wings.tiny.grow.spring.bean.TinyTrackConfiguration", "type": "java.lang.Boolean"}, + {"name": "wings.enabled.pro.fessional.wings.tiny.grow.spring.bean.TinyTrackConfiguration$DaoServScan", "type": "java.lang.Boolean"}, + + {"name": "wings.enabled.pro.fessional.wings.tiny.grow.track.impl.TinyTrackAround", "type": "java.lang.Boolean"}, + {"name": "wings.enabled.pro.fessional.wings.tiny.grow.track.impl.TinyTrackCollectorDaoImpl", "type": "java.lang.Boolean"}, + {"name": "wings.enabled.pro.fessional.wings.tiny.grow.track.impl.TinyTrackServiceImpl", "type": "java.lang.Boolean"} + ], + "hints": [] +} \ No newline at end of file diff --git a/radiant/tiny-grow/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/radiant/tiny-grow/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports new file mode 100644 index 000000000..3f43c3cfa --- /dev/null +++ b/radiant/tiny-grow/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports @@ -0,0 +1 @@ +pro.fessional.wings.tiny.grow.spring.conf.TinyGrowAutoConfiguration diff --git a/radiant/tiny-grow/src/main/resources/wings-conf/wings-flywave-fit-79.properties b/radiant/tiny-grow/src/main/resources/wings-conf/wings-flywave-fit-79.properties new file mode 100644 index 000000000..3511220a0 --- /dev/null +++ b/radiant/tiny-grow/src/main/resources/wings-conf/wings-flywave-fit-79.properties @@ -0,0 +1,3 @@ +wings.faceless.flywave.fit.tiny-grow.path=classpath*:/wings-flywave/master/08-grow/*.sql +wings.faceless.flywave.fit.tiny-grow.revi=2020_1028_01L +wings.faceless.flywave.fit.tiny-grow.lost=EXEC diff --git a/radiant/tiny-grow/src/main/resources/wings-conf/wings-tinytrack-exclude-79.properties b/radiant/tiny-grow/src/main/resources/wings-conf/wings-tinytrack-exclude-79.properties new file mode 100644 index 000000000..7ca6537c2 --- /dev/null +++ b/radiant/tiny-grow/src/main/resources/wings-conf/wings-tinytrack-exclude-79.properties @@ -0,0 +1,11 @@ +## exclude the property if it is instance of +wings.tiny.grow.track.exclude.clazz[jakarta.ServletRequest]=jakarta.servlet.ServletRequest +wings.tiny.grow.track.exclude.clazz[jakarta.ServletResponse]=jakarta.servlet.ServletResponse +wings.tiny.grow.track.exclude.clazz[io.InputStream]=java.io.InputStream +wings.tiny.grow.track.exclude.clazz[io.OutputStream]=java.io.OutputStream + +## exclude the property if its name equals +#wings.tiny.grow.track.exclude.equal[password]=password + +## exclude the property if its name match regex +#wings.tiny.grow.track.exclude.regex[pass]=(?i)pass diff --git a/radiant/tiny-grow/src/main/resources/wings-flywave/master/08-grow/2020-10-28u01-tiny_grow.sql b/radiant/tiny-grow/src/main/resources/wings-flywave/master/08-grow/2020-10-28u01-tiny_grow.sql new file mode 100644 index 000000000..cb4cf9c12 --- /dev/null +++ b/radiant/tiny-grow/src/main/resources/wings-flywave/master/08-grow/2020-10-28u01-tiny_grow.sql @@ -0,0 +1,3 @@ +DROP TABLE IF EXISTS `win_grow_track`; -- 145/Grow Tracking; + +-- CALL FLYWAVE('2020-10-28u01-tiny_grow.sql'); \ No newline at end of file diff --git a/radiant/tiny-grow/src/main/resources/wings-flywave/master/08-grow/2020-10-28v01-tiny_grow.sql b/radiant/tiny-grow/src/main/resources/wings-flywave/master/08-grow/2020-10-28v01-tiny_grow.sql new file mode 100644 index 000000000..47a2f1aa6 --- /dev/null +++ b/radiant/tiny-grow/src/main/resources/wings-flywave/master/08-grow/2020-10-28v01-tiny_grow.sql @@ -0,0 +1,30 @@ +-- Error Code: 1071. Specified key was too long; max key length is 3072 bytes +CREATE TABLE `win_grow_track` ( + `id` BIGINT NOT NULL COMMENT 'primary key', + `create_dt` DATETIME(3) NOT NULL DEFAULT NOW(3) COMMENT 'created datetime', + `track_key` VARCHAR(500) NOT NULL DEFAULT '' COMMENT 'track key, method/enum', + `track_ref` VARCHAR(100) NOT NULL DEFAULT '' COMMENT 'method/enum/url/str', + `track_app` VARCHAR(100) NOT NULL DEFAULT '' COMMENT 'app name', + `track_env` TEXT NULL COMMENT 'env, terminal context, json', + `track_ins` TEXT NULL COMMENT 'inputs param, json array', + `track_out` TEXT NULL COMMENT 'output return, json', + `track_err` TEXT NULL COMMENT 'error exception, json', + `elapse_ms` BIGINT NOT NULL DEFAULT '0' COMMENT 'elapse mills', + `user_key` BIGINT NOT NULL DEFAULT '0' COMMENT 'key user, data owner', + `user_ref` BIGINT NOT NULL DEFAULT '0' COMMENT 'ref user, data operator', + `data_key` BIGINT NOT NULL DEFAULT '0' COMMENT 'key data, order id', + `data_ref` BIGINT NOT NULL DEFAULT '0' COMMENT 'ref data, trade id', + `data_opt` BIGINT NOT NULL DEFAULT '0' COMMENT 'optional data, payment id', + `code_key` VARCHAR(100) NOT NULL DEFAULT '' COMMENT 'key code, order num', + `code_ref` VARCHAR(100) NOT NULL DEFAULT '' COMMENT 'ref code, trade seq', + `code_opt` VARCHAR(100) NOT NULL DEFAULT '' COMMENT 'optional code, message id', + `word_ref` VARCHAR(800) NOT NULL DEFAULT '' COMMENT 'ref word, mark', + PRIMARY KEY (`id`), + INDEX ix_track_key (`track_key`), + INDEX ix_user_key (`user_key`), + INDEX ix_data_key (`data_key`), + INDEX ix_code_key (`code_key`) +) ENGINE = InnoDB + DEFAULT CHARSET = utf8mb4 COMMENT ='145/Grow Tracking'; + +-- CALL FLYWAVE('2020-10-28v01-tiny_grow.sql'); \ No newline at end of file diff --git a/radiant/tiny-grow/src/test/java/pro/fessional/wings/tiny/app/TestTinyGrowApplication.java b/radiant/tiny-grow/src/test/java/pro/fessional/wings/tiny/app/TestTinyGrowApplication.java new file mode 100644 index 000000000..7f957ac06 --- /dev/null +++ b/radiant/tiny-grow/src/test/java/pro/fessional/wings/tiny/app/TestTinyGrowApplication.java @@ -0,0 +1,19 @@ +package pro.fessional.wings.tiny.app; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import pro.fessional.wings.testing.silencer.TestingPropertyHelper; + +/** + * @author trydofor + * @since 2019-07-20 + */ +@SpringBootApplication +public class TestTinyGrowApplication { + + public static void main(String[] args) { + TestingPropertyHelper.autoSetWingsRootDir(); + SpringApplication.run(TestTinyGrowApplication.class, args); + } + +} diff --git a/radiant/tiny-grow/src/test/java/pro/fessional/wings/tiny/app/controller/TestTrackController.java b/radiant/tiny-grow/src/test/java/pro/fessional/wings/tiny/app/controller/TestTrackController.java new file mode 100644 index 000000000..071623c37 --- /dev/null +++ b/radiant/tiny-grow/src/test/java/pro/fessional/wings/tiny/app/controller/TestTrackController.java @@ -0,0 +1,27 @@ +package pro.fessional.wings.tiny.app.controller; + +import jakarta.servlet.http.HttpServletRequest; +import lombok.extern.slf4j.Slf4j; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; +import pro.fessional.wings.tiny.app.service.TestTrackData; +import pro.fessional.wings.tiny.app.service.impl.TestTrackCollectorImpl; +import pro.fessional.wings.tiny.grow.track.TinyTracker; + +/** + * @author trydofor + * @since 2024-07-27 + */ +@Slf4j +@RestController +public class TestTrackController { + + @TinyTracker + @RequestMapping("/test/track.json") + public TestTrackData track(@RequestParam("id") long id, @RequestParam("str") String str, HttpServletRequest ignore) { + TestTrackCollectorImpl.CodeKeys.putIfAbsent(str, Boolean.TRUE); + log.info("track31 code-key={}", str); + return new TestTrackData(id, str); + } +} diff --git a/radiant/tiny-grow/src/test/java/pro/fessional/wings/tiny/app/service/TestTrack1Service.java b/radiant/tiny-grow/src/test/java/pro/fessional/wings/tiny/app/service/TestTrack1Service.java new file mode 100644 index 000000000..bdd3f905c --- /dev/null +++ b/radiant/tiny-grow/src/test/java/pro/fessional/wings/tiny/app/service/TestTrack1Service.java @@ -0,0 +1,36 @@ +package pro.fessional.wings.tiny.app.service; + +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import pro.fessional.wings.tiny.app.service.impl.TestTrackCollectorImpl; +import pro.fessional.wings.tiny.grow.track.TinyTrackService; +import pro.fessional.wings.tiny.grow.track.TinyTracker; + +/** + * @author trydofor + * @since 2024-07-27 + */ +@Service +@Slf4j +public class TestTrack1Service { + @TinyTracker + public TestTrackData track(long id, String str) { + TestTrackCollectorImpl.CodeKeys.putIfAbsent(str, Boolean.TRUE); + log.info("track11 code-key={}", str); + return new TestTrackData(id, str); + } + + protected void track(TinyTrackService.Tracking trk, long id, String str) { + trk.setDataKey(id); + trk.setCodeKey(str); + } + + @Transactional + @TinyTracker + public TestTrackData trackTx(long id, String str) { + TestTrackCollectorImpl.CodeKeys.putIfAbsent(str, Boolean.TRUE); + log.info("track12 code-key={}", str); + return new TestTrackData(id, str); + } +} diff --git a/radiant/tiny-grow/src/test/java/pro/fessional/wings/tiny/app/service/TestTrack2Service.java b/radiant/tiny-grow/src/test/java/pro/fessional/wings/tiny/app/service/TestTrack2Service.java new file mode 100644 index 000000000..3649c1bf7 --- /dev/null +++ b/radiant/tiny-grow/src/test/java/pro/fessional/wings/tiny/app/service/TestTrack2Service.java @@ -0,0 +1,13 @@ +package pro.fessional.wings.tiny.app.service; + +/** + * @author trydofor + * @since 2024-07-27 + */ +public interface TestTrack2Service { + + TestTrackData track(long id, String str); + + TestTrackData trackTx(long id, String str); + +} diff --git a/radiant/tiny-grow/src/test/java/pro/fessional/wings/tiny/app/service/TestTrackData.java b/radiant/tiny-grow/src/test/java/pro/fessional/wings/tiny/app/service/TestTrackData.java new file mode 100644 index 000000000..0a7dede4a --- /dev/null +++ b/radiant/tiny-grow/src/test/java/pro/fessional/wings/tiny/app/service/TestTrackData.java @@ -0,0 +1,25 @@ +package pro.fessional.wings.tiny.app.service; + +import lombok.Data; + +import java.io.ByteArrayInputStream; +import java.io.InputStream; + +/** + * @author trydofor + * @since 2024-07-27 + */ +@Data +public class TestTrackData { + + private String password = "exclude password equal"; + private String secret = "exclude secret regex"; + private InputStream download = new ByteArrayInputStream("123".getBytes()); + private long id; + private String str; + + public TestTrackData(long id, String str) { + this.id = id; + this.str = str; + } +} diff --git a/radiant/tiny-grow/src/test/java/pro/fessional/wings/tiny/app/service/impl/TestTrack2ServiceImpl.java b/radiant/tiny-grow/src/test/java/pro/fessional/wings/tiny/app/service/impl/TestTrack2ServiceImpl.java new file mode 100644 index 000000000..cbf329806 --- /dev/null +++ b/radiant/tiny-grow/src/test/java/pro/fessional/wings/tiny/app/service/impl/TestTrack2ServiceImpl.java @@ -0,0 +1,40 @@ +package pro.fessional.wings.tiny.app.service.impl; + +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import pro.fessional.wings.tiny.app.service.TestTrack2Service; +import pro.fessional.wings.tiny.app.service.TestTrackData; +import pro.fessional.wings.tiny.grow.track.TinyTrackService; +import pro.fessional.wings.tiny.grow.track.TinyTracker; + +/** + * @author trydofor + * @since 2024-07-27 + */ +@Service +@Slf4j +public class TestTrack2ServiceImpl implements TestTrack2Service { + + @TinyTracker + @Override + public TestTrackData track(long id, String str) { + TestTrackCollectorImpl.CodeKeys.putIfAbsent(str, Boolean.TRUE); + log.info("track21 code-key={}", str); + return new TestTrackData(id, str); + } + + private void track(TinyTrackService.Tracking trk, long id, String str) { + trk.setDataKey(id); + trk.setCodeKey(str); + } + + @Override + @Transactional + @TinyTracker + public TestTrackData trackTx(long id, String str) { + TestTrackCollectorImpl.CodeKeys.putIfAbsent(str, Boolean.TRUE); + log.info("track22 code-key={}", str); + return new TestTrackData(id, str); + } +} diff --git a/radiant/tiny-grow/src/test/java/pro/fessional/wings/tiny/app/service/impl/TestTrackCollectorImpl.java b/radiant/tiny-grow/src/test/java/pro/fessional/wings/tiny/app/service/impl/TestTrackCollectorImpl.java new file mode 100644 index 000000000..72d13f965 --- /dev/null +++ b/radiant/tiny-grow/src/test/java/pro/fessional/wings/tiny/app/service/impl/TestTrackCollectorImpl.java @@ -0,0 +1,25 @@ +package pro.fessional.wings.tiny.app.service.impl; + +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; +import pro.fessional.wings.tiny.grow.track.TinyTrackService; + +import java.util.concurrent.ConcurrentHashMap; + +/** + * @author trydofor + * @since 2024-07-27 + */ +@Service +@Slf4j +public class TestTrackCollectorImpl implements TinyTrackService.Collector { + + public static final ConcurrentHashMap CodeKeys = new ConcurrentHashMap<>(); + + @Override + public void collect(TinyTrackService.Tracking tracking) { + String ck = (String) tracking.getIns()[1]; + log.info("done code-key={}, tracking={}", ck, tracking); + CodeKeys.remove(ck); + } +} diff --git a/radiant/tiny-grow/src/test/java/pro/fessional/wings/tiny/grow/track/TinyTrackServiceTest.java b/radiant/tiny-grow/src/test/java/pro/fessional/wings/tiny/grow/track/TinyTrackServiceTest.java new file mode 100644 index 000000000..0b1a6f1e4 --- /dev/null +++ b/radiant/tiny-grow/src/test/java/pro/fessional/wings/tiny/grow/track/TinyTrackServiceTest.java @@ -0,0 +1,110 @@ +package pro.fessional.wings.tiny.grow.track; + +import lombok.Setter; +import lombok.extern.slf4j.Slf4j; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.http.MediaType; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.MvcResult; +import pro.fessional.mirana.id.Ulid; +import pro.fessional.mirana.time.Sleep; +import pro.fessional.mirana.time.ThreadNow; +import pro.fessional.wings.tiny.app.service.TestTrack1Service; +import pro.fessional.wings.tiny.app.service.TestTrack2Service; +import pro.fessional.wings.tiny.app.service.impl.TestTrackCollectorImpl; +import pro.fessional.wings.tiny.grow.database.autogen.tables.daos.WinGrowTrackDao; +import pro.fessional.wings.tiny.grow.database.autogen.tables.pojos.WinGrowTrack; + +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +/** + * @author trydofor + * @since 2024-07-27 + */ +@SpringBootTest(properties = { + "wings.tiny.grow.track.exclude.equal[password]=password", + "wings.tiny.grow.track.exclude.regex[secret]=(?i).*secret", +}) +@Slf4j +@AutoConfigureMockMvc +class TinyTrackServiceTest { + + @Setter(onMethod_ = { @Autowired }) + protected TestTrack1Service testTrack1Service; + + @Setter(onMethod_ = { @Autowired }) + protected TestTrack2Service testTrack2Service; + + @Setter(onMethod_ = { @Autowired }) + protected WinGrowTrackDao winGrowTrackDao; + + @Setter(onMethod_ = { @Autowired }) + private MockMvc mvc; + + private final long now = (ThreadNow.millis() / 100) * 100; + + @Test + void service() { + String key11 = Ulid.next(); + String key12 = Ulid.next(); + testTrack1Service.track(now + 11, key11); + testTrack1Service.trackTx(now + 12, key12); + waitCodeKey(key11, key12); + + checkPojo(11, key11, false, "pro.fessional.wings.tiny.app.service.TestTrack1Service#track(long,String)", "Local", now + 11, key11); + checkPojo(12, key12, false, "pro.fessional.wings.tiny.app.service.TestTrack1Service#trackTx(long,String)", "Local", 0, ""); + + String key21 = Ulid.next(); + String key22 = Ulid.next(); + testTrack2Service.track(now + 21, key21); + testTrack2Service.trackTx(now + 22, key22); + waitCodeKey(key21, key22); + + checkPojo(21, key21, false, "pro.fessional.wings.tiny.app.service.impl.TestTrack2ServiceImpl#track(long,String)", "Local", now + 21, key21); + checkPojo(22, key22, false, "pro.fessional.wings.tiny.app.service.impl.TestTrack2ServiceImpl#trackTx(long,String)", "Local", 0, ""); + } + + @Test + void mvc() throws Exception { + String key31 = Ulid.next(); + final MvcResult mvcResult = mvc.perform(get("/test/track.json") + .contentType(MediaType.APPLICATION_JSON) + .param("id", String.valueOf(now + 31)) + .param("str", key31) + ) + .andDo(print()) + .andExpect(status().isOk()) + .andReturn(); + final String body0 = mvcResult.getResponse().getContentAsString(); + waitCodeKey(key31); + checkPojo(31, key31, true, "pro.fessional.wings.tiny.app.controller.TestTrackController#track(long,String,HttpServletRequest)", "zoneid", 0, ""); + } + + private void waitCodeKey(String... cks) { + for (String ck : cks) { + while (TestTrackCollectorImpl.CodeKeys.containsKey(ck)) { + log.info("wait key={}", ck); + Sleep.ignoreInterrupt(1_000); + } + } + } + + private void checkPojo(int id, String str, boolean web, String key, String env, long dkey, String ckey) { + long iid = now + id; + String ins = (web ? "[%s,\"%s\",{}]" : "[%s,\"%s\"]").formatted(iid, str); + String out = "{\"id\":%s,\"str\":\"%s\"}".formatted(iid, str); + WinGrowTrack pojo = winGrowTrackDao.fetchOne(t -> t.TrackIns.eq(ins)); + Assertions.assertNotNull(pojo); + Assertions.assertEquals(key, pojo.getTrackKey()); + Assertions.assertTrue(pojo.getTrackEnv().contains(env)); + Assertions.assertEquals(dkey, pojo.getDataKey()); + Assertions.assertEquals(ckey, pojo.getCodeKey()); + Assertions.assertEquals(out, pojo.getTrackOut()); + } +} \ No newline at end of file diff --git a/radiant/tiny-grow/src/test/resources/application.properties b/radiant/tiny-grow/src/test/resources/application.properties new file mode 100644 index 000000000..cc9dc3295 --- /dev/null +++ b/radiant/tiny-grow/src/test/resources/application.properties @@ -0,0 +1,6 @@ +server.port=8086 +spring.application.name=tiny-grow + +wings.enabled.faceless.flywave=true +wings.faceless.flywave.auto-init=true +wings.faceless.flywave.fit.tiny-grow.revi=2019_0512_01L, 2019_0520_01L, 2020_1028_01L diff --git a/radiant/tiny-grow/src/test/resources/wings-conf/spring-datasource-99.properties b/radiant/tiny-grow/src/test/resources/wings-conf/spring-datasource-99.properties new file mode 100644 index 000000000..5d8d9afb4 --- /dev/null +++ b/radiant/tiny-grow/src/test/resources/wings-conf/spring-datasource-99.properties @@ -0,0 +1 @@ +testing.dbname=wings_tiny diff --git a/radiant/tiny-grow/src/test/resources/wings-conf/wings-tinytask-test.properties b/radiant/tiny-grow/src/test/resources/wings-conf/wings-tinytask-test.properties new file mode 100644 index 000000000..3b19786fe --- /dev/null +++ b/radiant/tiny-grow/src/test/resources/wings-conf/wings-tinytask-test.properties @@ -0,0 +1,16 @@ +wings.tiny.task.define[pro.fessional.wings.tiny.app.service.TestServiceAuto#strVoid].timing-rate=30 + +wings.tiny.task.define[voidVoidAuto].enabled=false +wings.tiny.task.define[voidVoidAuto].timing-rate=30 + +### +wings.tiny.task.define[pro.fessional.wings.tiny.app.service.TestServiceManual#strVoid].enabled=true +wings.tiny.task.define[pro.fessional.wings.tiny.app.service.TestServiceManual#strVoid].autorun=false +wings.tiny.task.define[pro.fessional.wings.tiny.app.service.TestServiceManual#strVoid].timing-idle=30 + +wings.tiny.task.define[voidStrManual].enabled=true +wings.tiny.task.define[voidStrManual].tasker-name=voidStrManual +wings.tiny.task.define[voidStrManual].timing-rate=30 + +wings.tiny.task.define[voidVoidManual].enabled=true +wings.tiny.task.define[voidVoidManual].timing-rate=30 diff --git a/radiant/tiny-mail/src/main/java/pro/fessional/wings/tiny/mail/sender/MailNotice.java b/radiant/tiny-mail/src/main/java/pro/fessional/wings/tiny/mail/sender/MailNotice.java index 8828ce9cf..82c2cbd0f 100644 --- a/radiant/tiny-mail/src/main/java/pro/fessional/wings/tiny/mail/sender/MailNotice.java +++ b/radiant/tiny-mail/src/main/java/pro/fessional/wings/tiny/mail/sender/MailNotice.java @@ -1,5 +1,6 @@ package pro.fessional.wings.tiny.mail.sender; +import com.alibaba.ttl.threadpool.TtlExecutors; import lombok.Getter; import lombok.RequiredArgsConstructor; import lombok.Setter; @@ -91,7 +92,7 @@ public void emit(TinyMailConfig config, String subject, String content) { public void afterPropertiesSet() { if (executor == null) { log.warn("should reuse autowired thread pool"); - executor = Executors.newSingleThreadExecutor(); + executor = TtlExecutors.getTtlExecutor(Executors.newWorkStealingPool(2)); } } } diff --git a/wings/faceless-flywave/src/main/java/pro/fessional/wings/faceless/flywave/WingsRevision.java b/wings/faceless-flywave/src/main/java/pro/fessional/wings/faceless/flywave/WingsRevision.java index 12d3d558e..446d9fbde 100644 --- a/wings/faceless-flywave/src/main/java/pro/fessional/wings/faceless/flywave/WingsRevision.java +++ b/wings/faceless-flywave/src/main/java/pro/fessional/wings/faceless/flywave/WingsRevision.java @@ -20,6 +20,7 @@ public enum WingsRevision implements RevisionRegister { V05_20_1025_01_ConfRuntime(2020_1025_01L, "runtime config", "master/05-conf", "wings/warlock/src/main/resources/wings-flywave"), V06_20_1026_01_TinyTask(2020_1026_01L, "tiny task", "master/06-task", "radiant/tiny-task/src/main/resources/wings-flywave"), V07_20_1027_01_TinyMail(2020_1027_01L, "tiny mail", "master/07-mail", "radiant/tiny-mail/src/main/resources/wings-flywave"), + V08_20_1028_01_TinyGrow(2020_1028_01L, "tiny grow", "master/08-grow", "radiant/tiny-grow/src/main/resources/wings-flywave"), // upgrade V01_21_0918_01_FixAuthn(2021_0918_01L, "fix authn", "branch/somefix/01-authn-fix", "wings/warlock/src/main/resources/wings-flywave"), diff --git a/wings/slardar/src/main/java/pro/fessional/wings/slardar/fastjson/FastJsonHelper.java b/wings/slardar/src/main/java/pro/fessional/wings/slardar/fastjson/FastJsonHelper.java index d40705121..6d477bef8 100644 --- a/wings/slardar/src/main/java/pro/fessional/wings/slardar/fastjson/FastJsonHelper.java +++ b/wings/slardar/src/main/java/pro/fessional/wings/slardar/fastjson/FastJsonHelper.java @@ -5,6 +5,7 @@ import com.alibaba.fastjson2.JSONPath; import com.alibaba.fastjson2.JSONReader; import com.alibaba.fastjson2.JSONWriter; +import com.alibaba.fastjson2.filter.Filter; import org.jetbrains.annotations.Contract; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -222,6 +223,23 @@ public static byte[] bytes(Object obj) { return JSON.toJSONBytes(obj, WingsWriter); } + /** + * Serialization using the wings convention, + * output as string wherever possible to ensure data precision, + * but not affecting Java type inverse parsing + */ + @Contract("!null,_->!null") + public static String string(Object obj, Filter... filters) { + if (obj == null) return null; + return JSON.toJSONString(obj, filters, WingsWriter); + } + + @Contract("!null,_->!null") + public static byte[] bytes(Object obj, Filter... filters) { + if (obj == null) return null; + return JSON.toJSONBytes(obj, filters, WingsWriter); + } + //// path private static final ConcurrentHashMap JsonPathCache = new ConcurrentHashMap<>(); diff --git a/wings/slardar/src/main/java/pro/fessional/wings/slardar/fastjson/filter/ComposePropertyFilter.java b/wings/slardar/src/main/java/pro/fessional/wings/slardar/fastjson/filter/ComposePropertyFilter.java new file mode 100644 index 000000000..a83deeea0 --- /dev/null +++ b/wings/slardar/src/main/java/pro/fessional/wings/slardar/fastjson/filter/ComposePropertyFilter.java @@ -0,0 +1,59 @@ +package pro.fessional.wings.slardar.fastjson.filter; + +import com.alibaba.fastjson2.filter.PropertyFilter; +import org.jetbrains.annotations.NotNull; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.List; + +/** + *
+ * delta - the default return of this
+ * andOr - compose by `and` or `or`
+ * 
+ * + * @author trydofor + * @since 2024-07-27 + */ +public class ComposePropertyFilter implements PropertyFilter { + + private final boolean delta; + private final boolean andOr; + private final List filters; + + public ComposePropertyFilter(boolean andOr, PropertyFilter... filters) { + this(true, andOr, Arrays.asList(filters)); + } + + public ComposePropertyFilter(boolean delta, boolean andOr, PropertyFilter... filters) { + this(delta, andOr, Arrays.asList(filters)); + } + + public ComposePropertyFilter(boolean andOr, @NotNull Collection filters) { + this(true, andOr, filters); + } + + @SuppressWarnings("unchecked") + public ComposePropertyFilter(boolean delta, boolean andOr, @NotNull Collection filters) { + this.delta = delta; + this.andOr = andOr; + this.filters = filters instanceof List ? (List) filters : new ArrayList<>(filters); + } + + @Override + public boolean apply(Object object, String name, Object value) { + for (PropertyFilter ft : filters) { + boolean b = ft.apply(object, name, value); + if (andOr) { + if (!b) return false; // and false + } + else { + if (b) return true; // or true + } + } + + return delta; + } +} diff --git a/wings/slardar/src/main/java/pro/fessional/wings/slardar/fastjson/filter/ComposePropertyPreFilter.java b/wings/slardar/src/main/java/pro/fessional/wings/slardar/fastjson/filter/ComposePropertyPreFilter.java new file mode 100644 index 000000000..d0d1f98a9 --- /dev/null +++ b/wings/slardar/src/main/java/pro/fessional/wings/slardar/fastjson/filter/ComposePropertyPreFilter.java @@ -0,0 +1,60 @@ +package pro.fessional.wings.slardar.fastjson.filter; + +import com.alibaba.fastjson2.JSONWriter; +import com.alibaba.fastjson2.filter.PropertyPreFilter; +import org.jetbrains.annotations.NotNull; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.List; + +/** + *
+ * delta - the default return of this
+ * andOr - compose by `and` or `or`
+ * 
+ * + * @author trydofor + * @since 2024-07-27 + */ +public class ComposePropertyPreFilter implements PropertyPreFilter { + + private final boolean delta; + private final boolean andOr; + private final List filters; + + public ComposePropertyPreFilter(boolean andOr, PropertyPreFilter... filters) { + this(true, andOr, Arrays.asList(filters)); + } + + public ComposePropertyPreFilter(boolean delta, boolean andOr, PropertyPreFilter... filters) { + this(delta, andOr, Arrays.asList(filters)); + } + + public ComposePropertyPreFilter(boolean andOr, @NotNull Collection filters) { + this(true, andOr, filters); + } + + @SuppressWarnings("unchecked") + public ComposePropertyPreFilter(boolean delta, boolean andOr, @NotNull Collection filters) { + this.delta = delta; + this.andOr = andOr; + this.filters = filters instanceof List ? (List) filters : new ArrayList<>(filters); + } + + @Override + public boolean process(JSONWriter writer, Object source, String name) { + for (PropertyPreFilter ft : filters) { + boolean b = ft.process(writer, source, name); + if (andOr) { + if (!b) return false; // and false + } + else { + if (b) return true; // or true + } + } + + return delta; + } +} diff --git a/wings/slardar/src/main/java/pro/fessional/wings/slardar/fastjson/filter/ExcludePropertyPreFilter.java b/wings/slardar/src/main/java/pro/fessional/wings/slardar/fastjson/filter/ExcludePropertyPreFilter.java new file mode 100644 index 000000000..2f877afda --- /dev/null +++ b/wings/slardar/src/main/java/pro/fessional/wings/slardar/fastjson/filter/ExcludePropertyPreFilter.java @@ -0,0 +1,65 @@ +package pro.fessional.wings.slardar.fastjson.filter; + +import com.alibaba.fastjson2.JSONWriter; +import com.alibaba.fastjson2.filter.PropertyPreFilter; +import org.jetbrains.annotations.NotNull; + +import java.util.Collection; +import java.util.HashSet; +import java.util.Set; +import java.util.regex.Pattern; + +/** + *
+ * exclude the prop if
+ * * instance of class
+ * * name match regexp
+ * * name equal
+ * 
+ * + * @author trydofor + * @since 2024-07-27 + */ +public class ExcludePropertyPreFilter implements PropertyPreFilter { + + private final Set> clazz = new HashSet<>(); + private final Set equal = new HashSet<>(); + private final Set regex = new HashSet<>(); + + public void addClazz(@NotNull Class clz) { + clazz.add(clz); + } + + public void addEqual(@NotNull String str) { + equal.add(str); + } + + public void addRegex(Pattern ptn) { + regex.add(ptn); + } + + public void addClazz(@NotNull Collection> clz) { + clazz.addAll(clz); + } + + public void addEqual(@NotNull Collection str) { + equal.addAll(str); + } + + public void addRegex(Collection ptn) { + regex.addAll(ptn); + } + + @Override + public boolean process(JSONWriter writer, Object source, String name) { + for (Class clz : clazz) { + if (clz.isInstance(source)) return false; + } + + for (Pattern ptn : regex) { + if (ptn.matcher(name).find()) return false; + } + + return !equal.contains(name); + } +} diff --git a/wings/slardar/src/main/java/pro/fessional/wings/slardar/notice/DingTalkNotice.java b/wings/slardar/src/main/java/pro/fessional/wings/slardar/notice/DingTalkNotice.java index 054bdc366..601a72cd8 100644 --- a/wings/slardar/src/main/java/pro/fessional/wings/slardar/notice/DingTalkNotice.java +++ b/wings/slardar/src/main/java/pro/fessional/wings/slardar/notice/DingTalkNotice.java @@ -1,5 +1,6 @@ package pro.fessional.wings.slardar.notice; +import com.alibaba.ttl.threadpool.TtlExecutors; import lombok.Getter; import lombok.RequiredArgsConstructor; import lombok.Setter; @@ -173,7 +174,7 @@ public void emit(DingTalkConf config, String subject, String content) { public void afterPropertiesSet() { if (executor == null) { log.warn("should reuse autowired thread pool"); - executor = Executors.newSingleThreadExecutor(); + executor = TtlExecutors.getTtlExecutor(Executors.newWorkStealingPool(2)); } } diff --git a/wings/slardar/src/test/java/pro/fessional/wings/slardar/fastjson/FastJsonTest.java b/wings/slardar/src/test/java/pro/fessional/wings/slardar/fastjson/FastJsonTest.java index 4d7519401..8a9e53365 100644 --- a/wings/slardar/src/test/java/pro/fessional/wings/slardar/fastjson/FastJsonTest.java +++ b/wings/slardar/src/test/java/pro/fessional/wings/slardar/fastjson/FastJsonTest.java @@ -119,6 +119,9 @@ public void testJsonPath() { String json = FastJsonHelper.string(r); JSONObject obj = FastJsonHelper.object(json); + String json2 = FastJsonHelper.string(r,null); + Assertions.assertEquals(json, json2); + JSONPath p1 = FastJsonHelper.path("$.success"); JSONPath p2 = FastJsonHelper.path("$.success"); Assertions.assertSame(p1, p2); From 6de62ea1a710366440099addbb22a3e01bb44078 Mon Sep 17 00:00:00 2001 From: trydofor Date: Mon, 29 Jul 2024 20:07:22 +0800 Subject: [PATCH 31/51] =?UTF-8?q?=E2=9C=A8=20Anno=20omit,=20Helper,=20Docs?= =?UTF-8?q?=20#275?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- WingsBoot.t.md | 2 + observe/docs | 2 +- observe/mirana | 2 +- .../conf/TinyGrowAutoConfiguration.java | 4 +- ...xcludeProp.java => TinyTrackOmitProp.java} | 12 +- .../tiny/grow/track/TinyTrackHelper.java | 138 +++++++++++++++++- .../tiny/grow/track/TinyTrackService.java | 61 ++------ .../wings/tiny/grow/track/TinyTracker.java | 29 +++- .../wings/tiny/grow/track/TinyTracking.java | 93 ++++++++++++ .../tiny/grow/track/impl/TinyTrackAround.java | 48 +++--- .../track/impl/TinyTrackCollectorDaoImpl.java | 53 ++----- .../grow/track/impl/TinyTrackServiceImpl.java | 32 +++- .../wings-tinytrack-exclude-79.properties | 11 -- .../wings-tinytrack-omit-79.properties | 11 ++ .../app/controller/TestTrackController.java | 2 +- .../tiny/app/service/TestTrack1Service.java | 46 +++++- .../service/impl/TestTrack2ServiceImpl.java | 4 +- .../service/impl/TestTrackCollectorImpl.java | 3 +- .../tiny/grow/track/TinyTrackServiceTest.java | 17 ++- .../filter/ExcludePropertyPreFilter.java | 52 ++++--- 20 files changed, 444 insertions(+), 178 deletions(-) rename radiant/tiny-grow/src/main/java/pro/fessional/wings/tiny/grow/spring/prop/{TinyTrackExcludeProp.java => TinyTrackOmitProp.java} (73%) create mode 100644 radiant/tiny-grow/src/main/java/pro/fessional/wings/tiny/grow/track/TinyTracking.java delete mode 100644 radiant/tiny-grow/src/main/resources/wings-conf/wings-tinytrack-exclude-79.properties create mode 100644 radiant/tiny-grow/src/main/resources/wings-conf/wings-tinytrack-omit-79.properties diff --git a/WingsBoot.t.md b/WingsBoot.t.md index 5284d7b42..6c6e9f694 100644 --- a/WingsBoot.t.md +++ b/WingsBoot.t.md @@ -435,4 +435,6 @@ Use `t.md` as local [Test Management](https://www.jetbrains.com/help/idea/test-m * 15015 MailNoticeTest: title dryrun mailNotice * 15016 MailSenderManagerTest: title dryrun batch mail * 15017 TinyMailServiceDbTest: mock fail and check database +* 15018 TinyTrackServiceTest: tiny track AOP service +* 15019 TinyTrackServiceTest: tiny track Mvc controller diff --git a/observe/docs b/observe/docs index 5a0422caa..56b9094f6 160000 --- a/observe/docs +++ b/observe/docs @@ -1 +1 @@ -Subproject commit 5a0422caaff0d501ff16500c6115532a2de870b6 +Subproject commit 56b9094f604836ab7999716ac42adb698149ab91 diff --git a/observe/mirana b/observe/mirana index 91b7e6040..9587e8bf9 160000 --- a/observe/mirana +++ b/observe/mirana @@ -1 +1 @@ -Subproject commit 91b7e6040f09df04319c9e36a641e39b1e0a191c +Subproject commit 9587e8bf9c062b1426410b4779c07eeced2703f6 diff --git a/radiant/tiny-grow/src/main/java/pro/fessional/wings/tiny/grow/spring/conf/TinyGrowAutoConfiguration.java b/radiant/tiny-grow/src/main/java/pro/fessional/wings/tiny/grow/spring/conf/TinyGrowAutoConfiguration.java index 9f0df9b47..faf9a0fa1 100644 --- a/radiant/tiny-grow/src/main/java/pro/fessional/wings/tiny/grow/spring/conf/TinyGrowAutoConfiguration.java +++ b/radiant/tiny-grow/src/main/java/pro/fessional/wings/tiny/grow/spring/conf/TinyGrowAutoConfiguration.java @@ -5,7 +5,7 @@ import org.springframework.context.annotation.Import; import pro.fessional.wings.silencer.spring.boot.ConditionalWingsEnabled; import pro.fessional.wings.tiny.grow.spring.bean.TinyTrackConfiguration; -import pro.fessional.wings.tiny.grow.spring.prop.TinyTrackExcludeProp; +import pro.fessional.wings.tiny.grow.spring.prop.TinyTrackOmitProp; /** * @author trydofor @@ -13,7 +13,7 @@ */ @AutoConfiguration @ConditionalWingsEnabled -@ConfigurationPropertiesScan(basePackageClasses = TinyTrackExcludeProp.class) +@ConfigurationPropertiesScan(basePackageClasses = TinyTrackOmitProp.class) @Import(TinyTrackConfiguration.class) public class TinyGrowAutoConfiguration { } diff --git a/radiant/tiny-grow/src/main/java/pro/fessional/wings/tiny/grow/spring/prop/TinyTrackExcludeProp.java b/radiant/tiny-grow/src/main/java/pro/fessional/wings/tiny/grow/spring/prop/TinyTrackOmitProp.java similarity index 73% rename from radiant/tiny-grow/src/main/java/pro/fessional/wings/tiny/grow/spring/prop/TinyTrackExcludeProp.java rename to radiant/tiny-grow/src/main/java/pro/fessional/wings/tiny/grow/spring/prop/TinyTrackOmitProp.java index 088827086..2d3af66ac 100644 --- a/radiant/tiny-grow/src/main/java/pro/fessional/wings/tiny/grow/spring/prop/TinyTrackExcludeProp.java +++ b/radiant/tiny-grow/src/main/java/pro/fessional/wings/tiny/grow/spring/prop/TinyTrackOmitProp.java @@ -7,7 +7,7 @@ import java.util.Map; import java.util.regex.Pattern; -import static pro.fessional.wings.tiny.grow.spring.prop.TinyTrackExcludeProp.Key; +import static pro.fessional.wings.tiny.grow.spring.prop.TinyTrackOmitProp.Key; /** * @author trydofor @@ -15,12 +15,12 @@ */ @Data @ConfigurationProperties(Key) -public class TinyTrackExcludeProp { +public class TinyTrackOmitProp { - public static final String Key = "wings.tiny.grow.track.exclude"; + public static final String Key = "wings.tiny.grow.track.omit"; /** - * exclude the property if it is instance of + * omit the property if it is instance of. empty means disable * * @see #Key$clazz */ @@ -28,7 +28,7 @@ public class TinyTrackExcludeProp { public static final String Key$clazz = Key + ".clazz"; /** - * exclude the property if its name equals + * omit the property if its name equals. empty means disable * * @see #Key$equal */ @@ -36,7 +36,7 @@ public class TinyTrackExcludeProp { public static final String Key$equal = Key + ".equal"; /** - * exclude the property if its name match regex + * omit the property if its name match regex. empty means disable * * @see #Key$regex */ diff --git a/radiant/tiny-grow/src/main/java/pro/fessional/wings/tiny/grow/track/TinyTrackHelper.java b/radiant/tiny-grow/src/main/java/pro/fessional/wings/tiny/grow/track/TinyTrackHelper.java index 0a52110ee..65f867e80 100644 --- a/radiant/tiny-grow/src/main/java/pro/fessional/wings/tiny/grow/track/TinyTrackHelper.java +++ b/radiant/tiny-grow/src/main/java/pro/fessional/wings/tiny/grow/track/TinyTrackHelper.java @@ -1,30 +1,154 @@ package pro.fessional.wings.tiny.grow.track; +import lombok.Getter; +import lombok.RequiredArgsConstructor; +import lombok.experimental.Delegate; +import lombok.extern.slf4j.Slf4j; import org.jetbrains.annotations.NotNull; import org.springframework.util.function.SingletonSupplier; +import pro.fessional.mirana.func.Lam; +import pro.fessional.mirana.pain.ThrowableUtil; +import pro.fessional.mirana.time.ThreadNow; import pro.fessional.wings.silencer.spring.help.ApplicationContextHelper; +import java.lang.reflect.Method; import java.util.function.Consumer; +import java.util.function.Function; /** * @author trydofor * @since 2024-07-25 */ +@Slf4j public class TinyTrackHelper { - public static SingletonSupplier TrackService = ApplicationContextHelper.getSingletonSupplier(TinyTrackService.class); + private static final SingletonSupplier TrackService = ApplicationContextHelper.getSingletonSupplier(TinyTrackService.class); - /** - * never throw - */ - public static void track(Consumer fulfill) { + public static R track(@NotNull Lam.Ref key, @NotNull Function fun) { + return track(key.method, fun); + } + + public static R track(@NotNull Method key, @NotNull Function fun) { + TinyTrackService service = TrackService.obtain(); + TinyTracking tracking = service.begin(key); + return track(service, tracking, fun); + } + + public static R track(@NotNull Enum key, @NotNull Function fun) { + TinyTrackService service = TrackService.obtain(); + TinyTracking tracking = service.begin(key); + return track(service, tracking, fun); + } + + public static R track(@NotNull String key, @NotNull Function fun) { + TinyTrackService service = TrackService.obtain(); + TinyTracking tracking = service.begin(key); + return track(service, tracking, fun); + } + + public static R track(@NotNull String key, @NotNull String ref, @NotNull Function fun) { + TinyTrackService service = TrackService.obtain(); + TinyTracking tracking = service.begin(key, ref); + return track(service, tracking, fun); + } + + private static R track(@NotNull TinyTrackService service, @NotNull TinyTracking tracking, @NotNull Function fun) { + try { + R out = fun.apply(tracking); + if (tracking.getOut() == null) { + tracking.setOut(out); + } + return out; + } + catch (Throwable e) { + if (tracking.getErr() == null) { + tracking.setErr(e); + } + throw ThrowableUtil.runtime(e); + } + finally { + tracking.setElapse(ThreadNow.millis() - tracking.getBegin()); + service.track(tracking, true); + } + } + public static TrackWrapper track(@NotNull Lam.Ref key) { + return track(key.method); + } + + public static TrackWrapper track(@NotNull Method key) { + TinyTrackService service = TrackService.obtain(); + TinyTracking tracking = service.begin(key); + return new TrackWrapper(tracking, service); + } + + public static TrackWrapper track(@NotNull Enum key) { + TinyTrackService service = TrackService.obtain(); + TinyTracking tracking = service.begin(key); + return new TrackWrapper(tracking, service); + } + + public static TrackWrapper track(@NotNull String key) { + TinyTrackService service = TrackService.obtain(); + TinyTracking tracking = service.begin(key); + return new TrackWrapper(tracking, service); + } + + public static TrackWrapper track(@NotNull String key, @NotNull String ref) { + TinyTrackService service = TrackService.obtain(); + TinyTracking tracking = service.begin(key, ref); + return new TrackWrapper(tracking, service); } /** - * never throw + *
+     * try(tryTrack) {
+     *   // biz logic
+     * };
+     * 
*/ - public static void track(@NotNull String key, @NotNull String ref, @NotNull Consumer fulfill) { + @RequiredArgsConstructor + @Getter + public static class TrackWrapper implements AutoCloseable { + + @NotNull + @Delegate(types = TinyTracking.class) + private final TinyTracking tracking; + + @NotNull + private final TinyTrackService service; + + /** + * set properties without exception thrown + */ + public void safeSet(@NotNull Consumer fun) { + try { + fun.accept(tracking); + } + catch (Throwable e) { + log.warn("safeSet get error", e); + } + } + + /** + * set properties and out without exception thrown + */ + public R safeOut(@NotNull Function fun) { + R out = null; + try { + out = fun.apply(tracking); + tracking.setOut(out); + } + catch (Throwable e) { + log.warn("safeOut get error", e); + } + return out; + } + @Override + public void close() { + tracking.setElapse(ThreadNow.millis() - tracking.getBegin()); + service.track(tracking, true); + } } } diff --git a/radiant/tiny-grow/src/main/java/pro/fessional/wings/tiny/grow/track/TinyTrackService.java b/radiant/tiny-grow/src/main/java/pro/fessional/wings/tiny/grow/track/TinyTrackService.java index 932bec7ad..098e96b3f 100644 --- a/radiant/tiny-grow/src/main/java/pro/fessional/wings/tiny/grow/track/TinyTrackService.java +++ b/radiant/tiny-grow/src/main/java/pro/fessional/wings/tiny/grow/track/TinyTrackService.java @@ -1,13 +1,11 @@ package pro.fessional.wings.tiny.grow.track; -import lombok.Data; import org.jetbrains.annotations.NotNull; import pro.fessional.mirana.cast.EnumConvertor; import pro.fessional.mirana.cast.MethodConvertor; import java.lang.reflect.Method; -import java.util.LinkedHashMap; -import java.util.Map; +import java.util.concurrent.FutureTask; /** * Data tracking in async, never throws @@ -20,23 +18,23 @@ public interface TinyTrackService { /** * async executor */ - void async(Runnable run); + FutureTask async(Runnable run); /** * begin a tracking with key and ref */ @NotNull - Tracking begin(@NotNull String key, @NotNull String ref); + TinyTracking begin(@NotNull String key, @NotNull String ref); /** * post the tracking, fire and forget, never throws */ - void track(@NotNull Tracking tracking, boolean async); + void track(@NotNull TinyTracking tracking, boolean async); /** * async post the tracking, fire and forget, never throws */ - default void track(@NotNull Tracking tracking) { + default void track(@NotNull TinyTracking tracking) { track(tracking, true); } @@ -44,7 +42,7 @@ default void track(@NotNull Tracking tracking) { * raw string key and 'string' ref */ @NotNull - default Tracking begin(@NotNull String key) { + default TinyTracking begin(@NotNull String key) { return begin(key, "string"); } @@ -53,7 +51,7 @@ default Tracking begin(@NotNull String key) { * e.g. a.b.c.MyClass#method(String,int) */ @NotNull - default Tracking begin(@NotNull Method key) { + default TinyTracking begin(@NotNull Method key) { String str = MethodConvertor.method2Str(key); return begin(str, "method"); } @@ -63,7 +61,7 @@ default Tracking begin(@NotNull Method key) { * e.g. a.b.c.MyEnum#Name */ @NotNull - default Tracking begin(@NotNull Enum key) { + default TinyTracking begin(@NotNull Enum key) { String str = EnumConvertor.enum2Str(key); return begin(str, "enum"); } @@ -72,47 +70,6 @@ default Tracking begin(@NotNull Enum key) { * collect tracking to different impl, e.g. Dao to database */ interface Collector { - void collect(Tracking tracking); - } - - @Data - class Tracking { - private final long begin; - private final String key; - private final String ref; - - private String app; - @NotNull - private Map env = new LinkedHashMap<>(); - @NotNull - private Object[] ins = new Object[0]; - private Object out; - private Throwable err; - private long elapse; - - private long userKey; - private long userRef; - - private long dataKey; - private long dataRef; - private long dataOpt; - - private String codeKey; - private String codeRef; - private String codeOpt; - - private String wordRef; - - public void setIns(Object... ins) { - this.ins = ins; - } - - public void addEnv(String key, Object value) { - env.put(key, value); - } - - public void addEnv(Map envs) { - env.putAll(envs); - } + void collect(TinyTracking tracking); } } diff --git a/radiant/tiny-grow/src/main/java/pro/fessional/wings/tiny/grow/track/TinyTracker.java b/radiant/tiny-grow/src/main/java/pro/fessional/wings/tiny/grow/track/TinyTracker.java index 4fa9b70f7..5d93088e3 100644 --- a/radiant/tiny-grow/src/main/java/pro/fessional/wings/tiny/grow/track/TinyTracker.java +++ b/radiant/tiny-grow/src/main/java/pro/fessional/wings/tiny/grow/track/TinyTracker.java @@ -1,5 +1,7 @@ package pro.fessional.wings.tiny.grow.track; +import org.intellij.lang.annotations.Language; + import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @@ -27,14 +29,31 @@ /** *
-     * The name of this AOP object's method that will mix the `Tracking` after return/throw,
-     * its parameters is the `Tracking` prepended to the parameters of the AOP method.
+     * The name of this AOP object's method that will mix the `TinyTracking` after return/throw,
+     * its parameters is the `TinyTracking` prepended to the parameters of the AOP method.
      *
      * * saveOrder(long, Order) - the AOP method
-     * * saveOrder(Tracking, long, Order) - same as AOP method if mix is empty
-     * * saveOrderMix(Tracking, long, Order) - if mix is saveOrderMix
+     * * saveOrder(TinyTracking, long, Order) - same as AOP method if mix is empty
+     * * saveOrderMix(TinyTracking, long, Order) - if mix is saveOrderMix
      * 
- * @see TinyTrackService.Tracking + * + * @see TinyTracking */ String mix() default ""; + + /** + * omit the property if it is instance of + */ + Class[] omitClass() default {}; + + /** + * omit the property if its name equals + */ + String[] omitEqual() default {}; + + /** + * omit the property if its name match regex + */ + @Language("regexp") + String[] omitRegex() default {}; } diff --git a/radiant/tiny-grow/src/main/java/pro/fessional/wings/tiny/grow/track/TinyTracking.java b/radiant/tiny-grow/src/main/java/pro/fessional/wings/tiny/grow/track/TinyTracking.java new file mode 100644 index 000000000..0e5f0dca6 --- /dev/null +++ b/radiant/tiny-grow/src/main/java/pro/fessional/wings/tiny/grow/track/TinyTracking.java @@ -0,0 +1,93 @@ +package pro.fessional.wings.tiny.grow.track; + +import lombok.Data; +import org.jetbrains.annotations.NotNull; + +import java.util.Collection; +import java.util.HashSet; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.Set; +import java.util.regex.Pattern; + +/** + * @author trydofor + * @since 2024-07-28 + */ +@Data +public class TinyTracking { + protected final long begin; + protected final String key; + protected final String ref; + + protected String app; + @NotNull + protected Map env = new LinkedHashMap<>(); + @NotNull + protected Object[] ins = new Object[0]; + protected Object out; + protected Throwable err; + protected long elapse; + + protected long userKey; + protected long userRef; + + protected long dataKey; + protected long dataRef; + protected long dataOpt; + + protected String codeKey; + protected String codeRef; + protected String codeOpt; + + protected String wordRef; + + /** + * rule set of Class/String/Pattern + */ + @NotNull + protected final Set omitRule = new HashSet<>(); + + public void setIns(Object... ins) { + this.ins = ins; + } + + public void addEnv(String key, Object value) { + env.put(key, value); + } + + public void addEnv(Map envs) { + env.putAll(envs); + } + + /** + *
+     * support rule,
+     * * Class - object is instance of
+     * * String - name equals
+     * * Pattern - name matches regexp
+     * * Collection - any of above type
+     * * Object[] - any of above type
+     * 
+ */ + public void addOmit(Object omit) { + if (omit == null) { + return; + } + else if (omit instanceof Class clz) { + omitRule.add(clz); + } + else if (omit instanceof String str) { + if (!str.isEmpty()) omitRule.add(str); + } + else if (omit instanceof Pattern ptn) { + if (!ptn.pattern().isEmpty()) omitRule.add(ptn); + } + else if (omit instanceof Collection col) { + for (Object o : col) addOmit(o); + } + else if (omit instanceof Object[] arr) { + for (Object o : arr) addOmit(o); + } + } +} diff --git a/radiant/tiny-grow/src/main/java/pro/fessional/wings/tiny/grow/track/impl/TinyTrackAround.java b/radiant/tiny-grow/src/main/java/pro/fessional/wings/tiny/grow/track/impl/TinyTrackAround.java index e53636015..475548a8a 100644 --- a/radiant/tiny-grow/src/main/java/pro/fessional/wings/tiny/grow/track/impl/TinyTrackAround.java +++ b/radiant/tiny-grow/src/main/java/pro/fessional/wings/tiny/grow/track/impl/TinyTrackAround.java @@ -18,13 +18,15 @@ import pro.fessional.mirana.time.ThreadNow; import pro.fessional.wings.silencer.spring.WingsOrdered; import pro.fessional.wings.silencer.spring.boot.ConditionalWingsEnabled; -import pro.fessional.wings.slardar.context.TerminalContext; import pro.fessional.wings.tiny.grow.track.TinyTrackService; -import pro.fessional.wings.tiny.grow.track.TinyTrackService.Tracking; import pro.fessional.wings.tiny.grow.track.TinyTracker; +import pro.fessional.wings.tiny.grow.track.TinyTracking; import java.lang.reflect.Method; +import java.util.HashSet; +import java.util.Set; import java.util.concurrent.ConcurrentHashMap; +import java.util.regex.Pattern; /** * @author trydofor @@ -45,13 +47,15 @@ public Object track(ProceedingJoinPoint joinPoint) throws Throwable { final Method method = ((MethodSignature) joinPoint.getSignature()).getMethod(); final TinyTracker anno = method.getAnnotation(TinyTracker.class); - final Tracking tracking = tryTrack(method, anno); + final TinyTracking tracking = tryTrack(method, anno); if (tracking == null) { return joinPoint.proceed(); } + tracking.setIns(joinPoint.getArgs()); + tracking.addOmit(omitRule(method, anno)); + try { - tracking.setIns(joinPoint.getArgs()); Object out = joinPoint.proceed(); tracking.setOut(out); return out; @@ -70,10 +74,9 @@ public Object track(ProceedingJoinPoint joinPoint) throws Throwable { } } - protected void mixAsync(@NotNull Tracking tracking, @NotNull Method method, @NotNull TinyTracker anno, @NotNull JoinPoint joinPoint) { + protected void mixAsync(@NotNull TinyTracking tracking, @NotNull Method method, @NotNull TinyTracker anno, @NotNull JoinPoint joinPoint) { // biz thread tracking.setElapse(ThreadNow.millis() - tracking.getBegin()); - mixTrackEnv(tracking); // async thread tinyTrackService.async(() -> { @@ -95,19 +98,8 @@ protected void mixAsync(@NotNull Tracking tracking, @NotNull Method method, @Not }); } - protected void mixTrackEnv(@NotNull Tracking tracking) { - final TerminalContext.Context ctx = TerminalContext.get(false); - if (!ctx.isNull()) { - tracking.addEnv("userId", ctx.getUserId()); - tracking.addEnv("locale", ctx.getLocale().toLanguageTag()); - tracking.addEnv("zoneid", ctx.getZoneId().getId()); - tracking.addEnv("authType", ctx.getAuthType().name()); - tracking.addEnv("username", ctx.getUsername()); - } - } - @Nullable - protected Tracking tryTrack(@NotNull Method method, @NotNull TinyTracker anno) { + protected TinyTracking tryTrack(@NotNull Method method, @NotNull TinyTracker anno) { try { final String key = anno.key(); if (StringUtils.isEmpty(key)) { @@ -127,6 +119,24 @@ protected Tracking tryTrack(@NotNull Method method, @NotNull TinyTracker anno) { } } + private final ConcurrentHashMap> omitRules = new ConcurrentHashMap<>(); + + protected Set omitRule(@NotNull Method method, @NotNull TinyTracker anno) { + return omitRules.computeIfAbsent(method, k -> { + Set set = new HashSet<>(); + for (Class clz : anno.omitClass()) { + set.add(clz); + } + for (String str : anno.omitEqual()) { + set.add(str); + } + for (String ptn : anno.omitRegex()) { + set.add(Pattern.compile(ptn)); + } + return set; + }); + } + private final ConcurrentHashMap mixMethod = new ConcurrentHashMap<>(); @Nullable @@ -139,7 +149,7 @@ protected Method findMixer(@NotNull Method method, @NotNull TinyTracker anno) { } Class[] pm = method.getParameterTypes(); Class[] pn = new Class[pm.length + 1]; - pn[0] = Tracking.class; + pn[0] = TinyTracking.class; System.arraycopy(pm, 0, pn, 1, pm.length); Method md = method.getDeclaringClass().getDeclaredMethod(nm, pn); md.setAccessible(true); diff --git a/radiant/tiny-grow/src/main/java/pro/fessional/wings/tiny/grow/track/impl/TinyTrackCollectorDaoImpl.java b/radiant/tiny-grow/src/main/java/pro/fessional/wings/tiny/grow/track/impl/TinyTrackCollectorDaoImpl.java index 52bfa5c06..1636da195 100644 --- a/radiant/tiny-grow/src/main/java/pro/fessional/wings/tiny/grow/track/impl/TinyTrackCollectorDaoImpl.java +++ b/radiant/tiny-grow/src/main/java/pro/fessional/wings/tiny/grow/track/impl/TinyTrackCollectorDaoImpl.java @@ -2,7 +2,6 @@ import lombok.Setter; import org.jetbrains.annotations.NotNull; -import org.springframework.beans.factory.InitializingBean; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -14,10 +13,8 @@ import pro.fessional.wings.slardar.fastjson.filter.ExcludePropertyPreFilter; import pro.fessional.wings.tiny.grow.database.autogen.tables.daos.WinGrowTrackDao; import pro.fessional.wings.tiny.grow.database.autogen.tables.pojos.WinGrowTrack; -import pro.fessional.wings.tiny.grow.spring.prop.TinyTrackExcludeProp; import pro.fessional.wings.tiny.grow.track.TinyTrackService; - -import java.util.Map; +import pro.fessional.wings.tiny.grow.track.TinyTracking; /** * @author trydofor @@ -25,7 +22,7 @@ */ @Service @ConditionalWingsEnabled -public class TinyTrackCollectorDaoImpl implements TinyTrackService.Collector, InitializingBean { +public class TinyTrackCollectorDaoImpl implements TinyTrackService.Collector { @Setter(onMethod_ = { @Autowired }) protected WinGrowTrackDao winGrowTrackDao; @@ -33,40 +30,25 @@ public class TinyTrackCollectorDaoImpl implements TinyTrackService.Collector, In @Setter(onMethod_ = { @Autowired }) protected LightIdService lightIdService; - @Setter(onMethod_ = { @Autowired }) - protected TinyTrackExcludeProp tinyTrackExcludeProp; - - protected ExcludePropertyPreFilter excludePropertyPreFilter; - @Override @Transactional - public void collect(TinyTrackService.Tracking tracking) { + public void collect(TinyTracking tracking) { WinGrowTrack pojo = new WinGrowTrack(); pojo.setId(lightIdService.getId(winGrowTrackDao.getTable())); - buildPojo(pojo, tracking); - winGrowTrackDao.insert(pojo); - } - @Override - public void afterPropertiesSet() { - excludePropertyPreFilter = new ExcludePropertyPreFilter(); - excludePropertyPreFilter.addClazz(tinyTrackExcludeProp.getClazz().values()); - excludePropertyPreFilter.addEqual(tinyTrackExcludeProp.getEqual().values()); - excludePropertyPreFilter.addRegex(tinyTrackExcludeProp.getRegex().values()); + buildProp(pojo, tracking); + buildExec(pojo, tracking); + + winGrowTrackDao.insert(pojo); } - protected void buildPojo(@NotNull WinGrowTrack pojo, @NotNull TinyTrackService.Tracking tracking) { + protected void buildProp(@NotNull WinGrowTrack pojo, @NotNull TinyTracking tracking) { pojo.setCreateDt(DateLocaling.sysLdt(tracking.getBegin())); pojo.setTrackKey(tracking.getKey()); pojo.setTrackRef(tracking.getRef()); pojo.setTrackApp(tracking.getApp()); - pojo.setTrackEnv(encodeEnv(tracking.getEnv())); - pojo.setTrackIns(encodeIns(tracking.getIns())); - pojo.setTrackOut(encodeOut(tracking.getOut())); - pojo.setTrackErr(encodeErr(tracking.getErr())); - pojo.setElapseMs(tracking.getElapse()); pojo.setUserKey(tracking.getUserKey()); @@ -83,19 +65,12 @@ protected void buildPojo(@NotNull WinGrowTrack pojo, @NotNull TinyTrackService.T pojo.setWordRef(tracking.getWordRef()); } - protected String encodeEnv(Map env) { - return FastJsonHelper.string(env, excludePropertyPreFilter); - } - - protected String encodeIns(Object[] ins) { - return FastJsonHelper.string(ins, excludePropertyPreFilter); - } - - protected String encodeOut(Object out) { - return FastJsonHelper.string(out, excludePropertyPreFilter); - } + protected void buildExec(@NotNull WinGrowTrack pojo, @NotNull TinyTracking tracking) { + ExcludePropertyPreFilter filter = new ExcludePropertyPreFilter(tracking.getOmitRule()); - protected String encodeErr(Throwable err) { - return ThrowableUtil.toString(err); + pojo.setTrackEnv(FastJsonHelper.string(tracking.getEnv(), filter)); + pojo.setTrackIns(FastJsonHelper.string(tracking.getIns(), filter)); + pojo.setTrackOut(FastJsonHelper.string(tracking.getOut(), filter)); + pojo.setTrackErr(ThrowableUtil.toString(tracking.getErr())); } } diff --git a/radiant/tiny-grow/src/main/java/pro/fessional/wings/tiny/grow/track/impl/TinyTrackServiceImpl.java b/radiant/tiny-grow/src/main/java/pro/fessional/wings/tiny/grow/track/impl/TinyTrackServiceImpl.java index 5635f4026..1af4330a0 100644 --- a/radiant/tiny-grow/src/main/java/pro/fessional/wings/tiny/grow/track/impl/TinyTrackServiceImpl.java +++ b/radiant/tiny-grow/src/main/java/pro/fessional/wings/tiny/grow/track/impl/TinyTrackServiceImpl.java @@ -12,11 +12,15 @@ import pro.fessional.wings.silencer.modulate.RuntimeMode; import pro.fessional.wings.silencer.spring.boot.ConditionalWingsEnabled; import pro.fessional.wings.silencer.spring.help.ApplicationContextHelper; +import pro.fessional.wings.slardar.context.TerminalContext; +import pro.fessional.wings.tiny.grow.spring.prop.TinyTrackOmitProp; import pro.fessional.wings.tiny.grow.track.TinyTrackService; +import pro.fessional.wings.tiny.grow.track.TinyTracking; import java.util.List; import java.util.concurrent.Executor; import java.util.concurrent.Executors; +import java.util.concurrent.FutureTask; import static org.springframework.scheduling.annotation.AsyncAnnotationBeanPostProcessor.DEFAULT_TASK_EXECUTOR_BEAN_NAME; @@ -35,25 +39,41 @@ public class TinyTrackServiceImpl implements TinyTrackService, InitializingBean @Setter(onMethod_ = { @Autowired }) protected List trackCollector; + @Setter(onMethod_ = { @Autowired }) + protected TinyTrackOmitProp tinyTrackOmitProp; @Override - public void async(Runnable run) { - executor.execute(run); + public FutureTask async(Runnable run) { + FutureTask future = new FutureTask<>(run, null); + executor.execute(future); + return future; } @Override @NotNull - public Tracking begin(@NotNull String key, @NotNull String ref) { - final Tracking tracking = new Tracking(ThreadNow.millis(), key, ref); + public TinyTracking begin(@NotNull String key, @NotNull String ref) { + final TinyTracking tracking = new TinyTracking(ThreadNow.millis(), key, ref); tracking.setApp(ApplicationContextHelper.getApplicationName()); tracking.addEnv("run", RuntimeMode.getRunMode().name()); + final TerminalContext.Context ctx = TerminalContext.get(false); + if (!ctx.isNull()) { + tracking.addEnv("userId", ctx.getUserId()); + tracking.addEnv("locale", ctx.getLocale().toLanguageTag()); + tracking.addEnv("zoneid", ctx.getZoneId().getId()); + tracking.addEnv("authType", ctx.getAuthType().name()); + tracking.addEnv("username", ctx.getUsername()); + } + + tracking.addOmit(tinyTrackOmitProp.getClazz().values()); + tracking.addOmit(tinyTrackOmitProp.getEqual().values()); + tracking.addOmit(tinyTrackOmitProp.getRegex().values()); return tracking; } @Override - public void track(@NotNull Tracking tracking, boolean async) { + public void track(@NotNull TinyTracking tracking, boolean async) { if (async) { executor.execute(() -> track(tracking)); } @@ -63,7 +83,7 @@ public void track(@NotNull Tracking tracking, boolean async) { } @Override - public void track(@NotNull Tracking tracking) { + public void track(@NotNull TinyTracking tracking) { for (Collector cl : trackCollector) { try { cl.collect(tracking); diff --git a/radiant/tiny-grow/src/main/resources/wings-conf/wings-tinytrack-exclude-79.properties b/radiant/tiny-grow/src/main/resources/wings-conf/wings-tinytrack-exclude-79.properties deleted file mode 100644 index 7ca6537c2..000000000 --- a/radiant/tiny-grow/src/main/resources/wings-conf/wings-tinytrack-exclude-79.properties +++ /dev/null @@ -1,11 +0,0 @@ -## exclude the property if it is instance of -wings.tiny.grow.track.exclude.clazz[jakarta.ServletRequest]=jakarta.servlet.ServletRequest -wings.tiny.grow.track.exclude.clazz[jakarta.ServletResponse]=jakarta.servlet.ServletResponse -wings.tiny.grow.track.exclude.clazz[io.InputStream]=java.io.InputStream -wings.tiny.grow.track.exclude.clazz[io.OutputStream]=java.io.OutputStream - -## exclude the property if its name equals -#wings.tiny.grow.track.exclude.equal[password]=password - -## exclude the property if its name match regex -#wings.tiny.grow.track.exclude.regex[pass]=(?i)pass diff --git a/radiant/tiny-grow/src/main/resources/wings-conf/wings-tinytrack-omit-79.properties b/radiant/tiny-grow/src/main/resources/wings-conf/wings-tinytrack-omit-79.properties new file mode 100644 index 000000000..acd472ae2 --- /dev/null +++ b/radiant/tiny-grow/src/main/resources/wings-conf/wings-tinytrack-omit-79.properties @@ -0,0 +1,11 @@ +## omit the property if it is instance of. empty means disable +wings.tiny.grow.track.omit.clazz[jakarta.ServletRequest]=jakarta.servlet.ServletRequest +wings.tiny.grow.track.omit.clazz[jakarta.ServletResponse]=jakarta.servlet.ServletResponse +wings.tiny.grow.track.omit.clazz[io.InputStream]=java.io.InputStream +wings.tiny.grow.track.omit.clazz[io.OutputStream]=java.io.OutputStream + +## omit the property if its name equals. empty means disable +#wings.tiny.grow.track.omit.equal[password]=password + +## omit the property if its name match regex. empty means disable +#wings.tiny.grow.track.omit.regex[pass]=(?i)pass diff --git a/radiant/tiny-grow/src/test/java/pro/fessional/wings/tiny/app/controller/TestTrackController.java b/radiant/tiny-grow/src/test/java/pro/fessional/wings/tiny/app/controller/TestTrackController.java index 071623c37..1def00d5c 100644 --- a/radiant/tiny-grow/src/test/java/pro/fessional/wings/tiny/app/controller/TestTrackController.java +++ b/radiant/tiny-grow/src/test/java/pro/fessional/wings/tiny/app/controller/TestTrackController.java @@ -17,7 +17,7 @@ @RestController public class TestTrackController { - @TinyTracker + @TinyTracker(omitClass = HttpServletRequest.class) @RequestMapping("/test/track.json") public TestTrackData track(@RequestParam("id") long id, @RequestParam("str") String str, HttpServletRequest ignore) { TestTrackCollectorImpl.CodeKeys.putIfAbsent(str, Boolean.TRUE); diff --git a/radiant/tiny-grow/src/test/java/pro/fessional/wings/tiny/app/service/TestTrack1Service.java b/radiant/tiny-grow/src/test/java/pro/fessional/wings/tiny/app/service/TestTrack1Service.java index bdd3f905c..4b3558293 100644 --- a/radiant/tiny-grow/src/test/java/pro/fessional/wings/tiny/app/service/TestTrack1Service.java +++ b/radiant/tiny-grow/src/test/java/pro/fessional/wings/tiny/app/service/TestTrack1Service.java @@ -3,9 +3,11 @@ import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; +import pro.fessional.mirana.pain.ThrowableUtil; import pro.fessional.wings.tiny.app.service.impl.TestTrackCollectorImpl; -import pro.fessional.wings.tiny.grow.track.TinyTrackService; +import pro.fessional.wings.tiny.grow.track.TinyTrackHelper; import pro.fessional.wings.tiny.grow.track.TinyTracker; +import pro.fessional.wings.tiny.grow.track.TinyTracking; /** * @author trydofor @@ -21,7 +23,7 @@ public TestTrackData track(long id, String str) { return new TestTrackData(id, str); } - protected void track(TinyTrackService.Tracking trk, long id, String str) { + protected void track(TinyTracking trk, long id, String str) { trk.setDataKey(id); trk.setCodeKey(str); } @@ -33,4 +35,44 @@ public TestTrackData trackTx(long id, String str) { log.info("track12 code-key={}", str); return new TestTrackData(id, str); } + + public TestTrackData track13(long id, String str) { + final String key = "pro.fessional.wings.tiny.app.service.TestTrack1Service#track13(long,String)"; + return TinyTrackHelper.track(key, trk -> { + TestTrackCollectorImpl.CodeKeys.putIfAbsent(str, Boolean.TRUE); + log.info("track13 code-key={}", str); + + trk.setIns(id, str); + trk.setDataKey(id); + trk.setCodeKey(str); + + return new TestTrackData(id, str); + }); + } + + public TestTrackData track14(long id, String str) { + final String key = "pro.fessional.wings.tiny.app.service.TestTrack1Service#track14(long,String)"; + final var trk = TinyTrackHelper.track(key); + try { + final TestTrackData out = new TestTrackData(id, str); + + TestTrackCollectorImpl.CodeKeys.putIfAbsent(str, Boolean.TRUE); + log.info("track14 code-key={}", str); + + trk.setIns(id, str); + trk.setDataKey(id); + trk.setCodeKey(str); + + trk.setOut(out); + + return out; + } + catch (Throwable e) { + trk.setErr(e); + throw ThrowableUtil.runtime(e); + } + finally { + trk.close(); + } + } } diff --git a/radiant/tiny-grow/src/test/java/pro/fessional/wings/tiny/app/service/impl/TestTrack2ServiceImpl.java b/radiant/tiny-grow/src/test/java/pro/fessional/wings/tiny/app/service/impl/TestTrack2ServiceImpl.java index cbf329806..cdc768ca2 100644 --- a/radiant/tiny-grow/src/test/java/pro/fessional/wings/tiny/app/service/impl/TestTrack2ServiceImpl.java +++ b/radiant/tiny-grow/src/test/java/pro/fessional/wings/tiny/app/service/impl/TestTrack2ServiceImpl.java @@ -5,8 +5,8 @@ import org.springframework.transaction.annotation.Transactional; import pro.fessional.wings.tiny.app.service.TestTrack2Service; import pro.fessional.wings.tiny.app.service.TestTrackData; -import pro.fessional.wings.tiny.grow.track.TinyTrackService; import pro.fessional.wings.tiny.grow.track.TinyTracker; +import pro.fessional.wings.tiny.grow.track.TinyTracking; /** * @author trydofor @@ -24,7 +24,7 @@ public TestTrackData track(long id, String str) { return new TestTrackData(id, str); } - private void track(TinyTrackService.Tracking trk, long id, String str) { + private void track(TinyTracking trk, long id, String str) { trk.setDataKey(id); trk.setCodeKey(str); } diff --git a/radiant/tiny-grow/src/test/java/pro/fessional/wings/tiny/app/service/impl/TestTrackCollectorImpl.java b/radiant/tiny-grow/src/test/java/pro/fessional/wings/tiny/app/service/impl/TestTrackCollectorImpl.java index 72d13f965..6cebd3a23 100644 --- a/radiant/tiny-grow/src/test/java/pro/fessional/wings/tiny/app/service/impl/TestTrackCollectorImpl.java +++ b/radiant/tiny-grow/src/test/java/pro/fessional/wings/tiny/app/service/impl/TestTrackCollectorImpl.java @@ -3,6 +3,7 @@ import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; import pro.fessional.wings.tiny.grow.track.TinyTrackService; +import pro.fessional.wings.tiny.grow.track.TinyTracking; import java.util.concurrent.ConcurrentHashMap; @@ -17,7 +18,7 @@ public class TestTrackCollectorImpl implements TinyTrackService.Collector { public static final ConcurrentHashMap CodeKeys = new ConcurrentHashMap<>(); @Override - public void collect(TinyTrackService.Tracking tracking) { + public void collect(TinyTracking tracking) { String ck = (String) tracking.getIns()[1]; log.info("done code-key={}, tracking={}", ck, tracking); CodeKeys.remove(ck); diff --git a/radiant/tiny-grow/src/test/java/pro/fessional/wings/tiny/grow/track/TinyTrackServiceTest.java b/radiant/tiny-grow/src/test/java/pro/fessional/wings/tiny/grow/track/TinyTrackServiceTest.java index 0b1a6f1e4..e7d921643 100644 --- a/radiant/tiny-grow/src/test/java/pro/fessional/wings/tiny/grow/track/TinyTrackServiceTest.java +++ b/radiant/tiny-grow/src/test/java/pro/fessional/wings/tiny/grow/track/TinyTrackServiceTest.java @@ -1,5 +1,6 @@ package pro.fessional.wings.tiny.grow.track; +import io.qameta.allure.TmsLink; import lombok.Setter; import lombok.extern.slf4j.Slf4j; import org.junit.jupiter.api.Assertions; @@ -28,8 +29,9 @@ * @since 2024-07-27 */ @SpringBootTest(properties = { - "wings.tiny.grow.track.exclude.equal[password]=password", - "wings.tiny.grow.track.exclude.regex[secret]=(?i).*secret", + "wings.tiny.grow.track.omit.clazz[jakarta.ServletRequest]=", // disable, use annotation + "wings.tiny.grow.track.omit.equal[password]=password", + "wings.tiny.grow.track.omit.regex[secret]=(?i).*secret", }) @Slf4j @AutoConfigureMockMvc @@ -50,6 +52,7 @@ class TinyTrackServiceTest { private final long now = (ThreadNow.millis() / 100) * 100; @Test + @TmsLink("C15018") void service() { String key11 = Ulid.next(); String key12 = Ulid.next(); @@ -60,6 +63,15 @@ void service() { checkPojo(11, key11, false, "pro.fessional.wings.tiny.app.service.TestTrack1Service#track(long,String)", "Local", now + 11, key11); checkPojo(12, key12, false, "pro.fessional.wings.tiny.app.service.TestTrack1Service#trackTx(long,String)", "Local", 0, ""); + String key13 = Ulid.next(); + String key14 = Ulid.next(); + testTrack1Service.track13(now + 13, key13); + testTrack1Service.track14(now + 14, key14); + waitCodeKey(key13, key14); + + checkPojo(13, key13, false, "pro.fessional.wings.tiny.app.service.TestTrack1Service#track13(long,String)", "Local", now + 13, key13); + checkPojo(14, key14, false, "pro.fessional.wings.tiny.app.service.TestTrack1Service#track14(long,String)", "Local", now + 14, key14); + String key21 = Ulid.next(); String key22 = Ulid.next(); testTrack2Service.track(now + 21, key21); @@ -71,6 +83,7 @@ void service() { } @Test + @TmsLink("C15019") void mvc() throws Exception { String key31 = Ulid.next(); final MvcResult mvcResult = mvc.perform(get("/test/track.json") diff --git a/wings/slardar/src/main/java/pro/fessional/wings/slardar/fastjson/filter/ExcludePropertyPreFilter.java b/wings/slardar/src/main/java/pro/fessional/wings/slardar/fastjson/filter/ExcludePropertyPreFilter.java index 2f877afda..7a8787c56 100644 --- a/wings/slardar/src/main/java/pro/fessional/wings/slardar/fastjson/filter/ExcludePropertyPreFilter.java +++ b/wings/slardar/src/main/java/pro/fessional/wings/slardar/fastjson/filter/ExcludePropertyPreFilter.java @@ -2,7 +2,6 @@ import com.alibaba.fastjson2.JSONWriter; import com.alibaba.fastjson2.filter.PropertyPreFilter; -import org.jetbrains.annotations.NotNull; import java.util.Collection; import java.util.HashSet; @@ -26,28 +25,39 @@ public class ExcludePropertyPreFilter implements PropertyPreFilter { private final Set equal = new HashSet<>(); private final Set regex = new HashSet<>(); - public void addClazz(@NotNull Class clz) { - clazz.add(clz); + /** + *
+     * support exclude type,
+     * * Class - object is instance of
+     * * String - name equals
+     * * Pattern - name matches regexp
+     * * Collection - any of above type
+     * * Object[] - any of above type
+     * 
+ */ + public ExcludePropertyPreFilter(Object exclude) { + addExclude(exclude); } - public void addEqual(@NotNull String str) { - equal.add(str); - } - - public void addRegex(Pattern ptn) { - regex.add(ptn); - } - - public void addClazz(@NotNull Collection> clz) { - clazz.addAll(clz); - } - - public void addEqual(@NotNull Collection str) { - equal.addAll(str); - } - - public void addRegex(Collection ptn) { - regex.addAll(ptn); + protected void addExclude(Object exclude) { + if (exclude == null) { + return; + } + else if (exclude instanceof Class clz) { + clazz.add(clz); + } + else if (exclude instanceof String str) { + equal.add(str); + } + else if (exclude instanceof Pattern reg) { + regex.add(reg); + } + else if (exclude instanceof Collection col) { + for (Object o : col) addExclude(o); + } + else if (exclude instanceof Object[] arr) { + for (Object o : arr) addExclude(o); + } } @Override From 70dcdc55f631f15524e2c21aa2691ce9900fed9b Mon Sep 17 00:00:00 2001 From: trydofor Date: Tue, 30 Jul 2024 12:53:48 +0800 Subject: [PATCH 32/51] =?UTF-8?q?=E2=9C=A8=20tinymail=20solidify=20prop=20?= =?UTF-8?q?at=20insert=20#280?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pom.xml | 5 + radiant/devs-coverage/pom.xml | 3 + .../service/impl/TinyMailServiceImpl.java | 13 +- .../mail/service/TinyMailServiceDbTest.java | 2 + .../wings/faceless/convention/EmptySugar.java | 133 ++++++++++++++++++ 5 files changed, 150 insertions(+), 6 deletions(-) diff --git a/pom.xml b/pom.xml index b61a7be9d..c228dcc13 100644 --- a/pom.xml +++ b/pom.xml @@ -295,6 +295,11 @@ tiny-mail ${wings.version} + + pro.fessional.wings + tiny-grow + ${wings.version} + org.jetbrains.kotlin diff --git a/radiant/devs-coverage/pom.xml b/radiant/devs-coverage/pom.xml index f5bdf284f..e3ab0043c 100644 --- a/radiant/devs-coverage/pom.xml +++ b/radiant/devs-coverage/pom.xml @@ -144,6 +144,9 @@ ${wings.rootdir}/radiant/tiny-task/src/main/java ${wings.rootdir}/radiant/tiny-task/src/main/java-gen ${wings.rootdir}/radiant/tiny-task/target/generated-sources/annotations + ${wings.rootdir}/radiant/tiny-grow/src/main/java + ${wings.rootdir}/radiant/tiny-grow/src/main/java-gen + ${wings.rootdir}/radiant/tiny-grow/target/generated-sources/annotations diff --git a/radiant/tiny-mail/src/main/java/pro/fessional/wings/tiny/mail/service/impl/TinyMailServiceImpl.java b/radiant/tiny-mail/src/main/java/pro/fessional/wings/tiny/mail/service/impl/TinyMailServiceImpl.java index 089268a7b..e76daeed4 100644 --- a/radiant/tiny-mail/src/main/java/pro/fessional/wings/tiny/mail/service/impl/TinyMailServiceImpl.java +++ b/radiant/tiny-mail/src/main/java/pro/fessional/wings/tiny/mail/service/impl/TinyMailServiceImpl.java @@ -257,16 +257,17 @@ public long save(@NotNull TinyMailPlain msg, boolean check) { po.setMailReply(toString(msg.getReply(), config.getReply())); po.setMailSubj(msg.getSubject()); po.setMailText(msg.getContent()); - po.setMailHtml(BoxedCastUtil.orElse(msg.getHtml(), config.getHtml())); + po.setMailHtml(EmptySugar.emptyOrElse(msg.getHtml(), config::getHtml)); po.setMailFile(toString(msg.getAttachment())); po.setMailMark(msg.getMark()); + po.setMailDate(md); po.setLazyBean(msg.getLazyBean()); po.setLazyPara(msg.getLazyPara()); // PropertyMapper - IfSetter.nonnull(po::setMaxFail, msg.getMaxFail()); - IfSetter.nonnull(po::setMaxDone, msg.getMaxDone()); + po.setMaxFail(EmptySugar.emptyOrElse(msg.getMaxFail(), tinyMailServiceProp::getMaxFail)); + po.setMaxDone(EmptySugar.emptyOrElse(msg.getMaxDone(), tinyMailServiceProp::getMaxDone)); IfSetter.nonnull(po::setRefType, msg.getRefType()); IfSetter.nonnull(po::setRefKey1, msg.getRefKey1()); @@ -427,7 +428,7 @@ protected WinMailSender saveMailSender(@NotNull TinyMailConfig config, @NotNull po.setMailReply(toString(msg.getReply(), config.getReply())); po.setMailSubj(msg.getSubject()); po.setMailText(msg.getContent()); - po.setMailHtml(BoxedCastUtil.orElse(msg.getHtml(), config.getHtml())); + po.setMailHtml(EmptySugar.emptyOrElse(msg.getHtml(), config::getHtml)); po.setMailFile(stringResource(msg.getAttachment())); po.setMailMark(msg.getMark()); @@ -436,8 +437,8 @@ protected WinMailSender saveMailSender(@NotNull TinyMailConfig config, @NotNull po.setLazyBean(msg.getLazyBean()); po.setLazyPara(msg.getLazyPara()); - po.setMaxFail(BoxedCastUtil.orElse(msg.getMaxFail(), tinyMailServiceProp.getMaxFail())); - po.setMaxDone(BoxedCastUtil.orElse(msg.getMaxDone(), tinyMailServiceProp.getMaxDone())); + po.setMaxFail(EmptySugar.emptyOrElse(msg.getMaxFail(), tinyMailServiceProp::getMaxFail)); + po.setMaxDone(EmptySugar.emptyOrElse(msg.getMaxDone(), tinyMailServiceProp::getMaxDone)); IfSetter.nonnull(po::setRefType, msg.getRefType()); IfSetter.nonnull(po::setRefKey1, msg.getRefKey1()); diff --git a/radiant/tiny-mail/src/test/java/pro/fessional/wings/tiny/mail/service/TinyMailServiceDbTest.java b/radiant/tiny-mail/src/test/java/pro/fessional/wings/tiny/mail/service/TinyMailServiceDbTest.java index a7d4a07a6..aebf259c7 100644 --- a/radiant/tiny-mail/src/test/java/pro/fessional/wings/tiny/mail/service/TinyMailServiceDbTest.java +++ b/radiant/tiny-mail/src/test/java/pro/fessional/wings/tiny/mail/service/TinyMailServiceDbTest.java @@ -249,6 +249,8 @@ else if (txtNg.contains(id)) { Assertions.assertEquals(TinyMailService.Success, rc); } + // [DRYRUN]TinyMailService sendError lazy RuntimeException 1 + // force to send, exceed max fail/done List pvz = winMailSenderDao.fetchById(lzyNg); for (WinMailSender po : pvz) { Assertions.assertEquals(4, po.getSumSend()); diff --git a/wings/faceless/src/main/java/pro/fessional/wings/faceless/convention/EmptySugar.java b/wings/faceless/src/main/java/pro/fessional/wings/faceless/convention/EmptySugar.java index 6c6f121eb..8a9a5772c 100644 --- a/wings/faceless/src/main/java/pro/fessional/wings/faceless/convention/EmptySugar.java +++ b/wings/faceless/src/main/java/pro/fessional/wings/faceless/convention/EmptySugar.java @@ -1,5 +1,7 @@ package pro.fessional.wings.faceless.convention; +import org.jetbrains.annotations.Contract; + import java.math.BigDecimal; import java.math.BigInteger; import java.time.LocalDate; @@ -7,6 +9,7 @@ import java.time.LocalTime; import java.time.OffsetDateTime; import java.time.ZonedDateTime; +import java.util.function.Supplier; /** * `isXxx/notXxx` for exact comparison, `asXxx/nonXxx` for range comparison @@ -433,4 +436,134 @@ public static OffsetDateTime emptyToNull(OffsetDateTime v) { public static Boolean emptyToNull(Boolean v) { return nullToTrue(v) ? null : v; } + + @Contract("_,!null->!null") + public static String emptyOrElse(String v, String elz) { + return asEmptyValue(v) ? elz : v; + } + + @Contract("_,!null->!null") + public static Integer emptyOrElse(Integer v, Integer elz) { + return asEmptyValue(v) ? elz : v; + } + + @Contract("_,!null->!null") + public static Long emptyOrElse(Long v, Long elz) { + return asEmptyValue(v) ? elz : v; + } + + @Contract("_,!null->!null") + public static Double emptyOrElse(Double v, Double elz) { + return asEmptyValue(v) ? elz : v; + } + + @Contract("_,!null->!null") + public static Float emptyOrElse(Float v, Float elz) { + return asEmptyValue(v) ? elz : v; + } + + @Contract("_,!null->!null") + public static BigDecimal emptyOrElse(BigDecimal v, BigDecimal elz) { + return asEmptyValue(v) ? elz : v; + } + + @Contract("_,!null->!null") + public static BigInteger emptyOrElse(BigInteger v, BigInteger elz) { + return asEmptyValue(v) ? elz : v; + } + + @Contract("_,!null->!null") + public static LocalDate emptyOrElse(LocalDate v, LocalDate elz) { + return asEmptyValue(v) ? elz : v; + } + + @Contract("_,!null->!null") + public static LocalTime emptyOrElse(LocalTime v, LocalTime elz) { + return asEmptyValue(v) ? elz : v; + } + + @Contract("_,!null->!null") + public static LocalDateTime emptyOrElse(LocalDateTime v, LocalDateTime elz) { + return asEmptyValue(v) ? elz : v; + } + + @Contract("_,!null->!null") + public static ZonedDateTime emptyOrElse(ZonedDateTime v, ZonedDateTime elz) { + return asEmptyValue(v) ? elz : v; + } + + @Contract("_,!null->!null") + public static OffsetDateTime emptyOrElse(OffsetDateTime v, OffsetDateTime elz) { + return asEmptyValue(v) ? elz : v; + } + + @Contract("_,!null->!null") + public static Boolean emptyOrElse(Boolean v, Boolean elz) { + return nullToTrue(v) ? elz : v; + } + + @Contract("_,!null->!null") + public static String emptyOrElse(String v, Supplier elz) { + return asEmptyValue(v) ? elz.get() : v; + } + + @Contract("_,!null->!null") + public static Integer emptyOrElse(Integer v, Supplier elz) { + return asEmptyValue(v) ? elz.get() : v; + } + + @Contract("_,!null->!null") + public static Long emptyOrElse(Long v, Supplier elz) { + return asEmptyValue(v) ? elz.get() : v; + } + + @Contract("_,!null->!null") + public static Double emptyOrElse(Double v, Supplier elz) { + return asEmptyValue(v) ? elz.get() : v; + } + + @Contract("_,!null->!null") + public static Float emptyOrElse(Float v, Supplier elz) { + return asEmptyValue(v) ? elz.get() : v; + } + + @Contract("_,!null->!null") + public static BigDecimal emptyOrElse(BigDecimal v, Supplier elz) { + return asEmptyValue(v) ? elz.get() : v; + } + + @Contract("_,!null->!null") + public static BigInteger emptyOrElse(BigInteger v, Supplier elz) { + return asEmptyValue(v) ? elz.get() : v; + } + + @Contract("_,!null->!null") + public static LocalDate emptyOrElse(LocalDate v, Supplier elz) { + return asEmptyValue(v) ? elz.get() : v; + } + + @Contract("_,!null->!null") + public static LocalTime emptyOrElse(LocalTime v, Supplier elz) { + return asEmptyValue(v) ? elz.get() : v; + } + + @Contract("_,!null->!null") + public static LocalDateTime emptyOrElse(LocalDateTime v, Supplier elz) { + return asEmptyValue(v) ? elz.get() : v; + } + + @Contract("_,!null->!null") + public static ZonedDateTime emptyOrElse(ZonedDateTime v, Supplier elz) { + return asEmptyValue(v) ? elz.get() : v; + } + + @Contract("_,!null->!null") + public static OffsetDateTime emptyOrElse(OffsetDateTime v, Supplier elz) { + return asEmptyValue(v) ? elz.get() : v; + } + + @Contract("_,!null->!null") + public static Boolean emptyOrElse(Boolean v, Supplier elz) { + return nullToTrue(v) ? elz.get() : v; + } } From 90ce6530a244318cde9f0bf09883260aa452b0b8 Mon Sep 17 00:00:00 2001 From: trydofor Date: Wed, 31 Jul 2024 09:04:35 +0800 Subject: [PATCH 33/51] =?UTF-8?q?=F0=9F=9A=A8=201681=20Integer=20display?= =?UTF-8?q?=20width=20is=20deprecated=20#278?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../master/00-init/2022-0222v01-demo-init.sql | 8 +-- observe/docs | 2 +- .../autogen/tables/WinMailSenderTable.java | 12 ++--- .../07-mail/2020-10-27v01-tiny_mail.sql | 24 ++++----- .../03-task-tune/2021-10-26v02-task-tune.sql | 6 +-- .../06-task/2020-10-26v01-tiny_task.sql | 54 +++++++++---------- .../00-init/2019-05-12v01-version-journal.sql | 6 +-- .../autogen/tables/SysConstantEnumTable.java | 7 ++- .../autogen/tables/SysStandardI18nTable.java | 7 ++- .../autogen/tables/TstNormalTableTable.java | 8 ++- .../autogen/tables/TstShardingTable.java | 8 ++- .../autogen/tables/TstNormalTableTable.java | 8 ++- .../autogen/tables/TstShardingTable.java | 8 ++- .../01-enum-i18n/2019-05-21v01-enum-i18n.sql | 2 +- .../2021-10-26v05-journal-elapse.sql | 4 +- .../01-light/2019-05-20v01-light-commit.sql | 12 ++--- .../master/2022-0601v01-test.sql | 24 ++++----- .../04-conf-size/2021-10-26v03-conf-size.sql | 2 +- .../04-auth/2020-10-24v01-user_login.sql | 26 ++++----- .../04-auth/2020-10-24v02-role_permit.sql | 24 ++++----- .../05-conf/2020-10-25v01-conf_runtime.sql | 2 +- 21 files changed, 122 insertions(+), 132 deletions(-) diff --git a/example/winx-common/src/main/resources/wings-flywave/master/00-init/2022-0222v01-demo-init.sql b/example/winx-common/src/main/resources/wings-flywave/master/00-init/2022-0222v01-demo-init.sql index 02eca9430..0e681e095 100644 --- a/example/winx-common/src/main/resources/wings-flywave/master/00-init/2022-0222v01-demo-init.sql +++ b/example/winx-common/src/main/resources/wings-flywave/master/00-init/2022-0222v01-demo-init.sql @@ -2,13 +2,13 @@ -- CREATE DATABASE `wings_example` /*!40100 DEFAULT CHARACTER SET utf8mb4 */; CREATE TABLE `winx_user_detail` ( - `id` BIGINT(20) NOT NULL COMMENT 'primary key', + `id` BIGINT NOT NULL COMMENT 'primary key', `create_dt` DATETIME(3) NOT NULL DEFAULT NOW(3) COMMENT 'created datetime(sys)', `modify_dt` DATETIME(3) NOT NULL DEFAULT '1000-01-01' ON UPDATE NOW(3) COMMENT 'modified datetime(sys)', `delete_dt` DATETIME(3) NOT NULL DEFAULT '1000-01-01' COMMENT 'logic deleted datetime', - `commit_id` BIGINT(20) NOT NULL COMMENT 'commit id', - `user_id` BIGINT(20) NOT NULL COMMENT 'win_user_basis.id', - `user_type` INT(11) NOT NULL DEFAULT '0' COMMENT 'user type/21001##:customer|operator|helpdesk', + `commit_id` BIGINT NOT NULL COMMENT 'commit id', + `user_id` BIGINT NOT NULL COMMENT 'win_user_basis.id', + `user_type` INT NOT NULL DEFAULT '0' COMMENT 'user type/21001##:customer|operator|helpdesk', `email` VARCHAR(100) NOT NULL DEFAULT '' COMMENT 'user email', PRIMARY KEY (`id`), UNIQUE INDEX uq_user_id (`user_id`), diff --git a/observe/docs b/observe/docs index 56b9094f6..7b5106657 160000 --- a/observe/docs +++ b/observe/docs @@ -1 +1 @@ -Subproject commit 56b9094f604836ab7999716ac42adb698149ab91 +Subproject commit 7b510665769a70add77fa23c3b1117b783ad08df diff --git a/radiant/tiny-mail/src/main/java-gen/pro/fessional/wings/tiny/mail/database/autogen/tables/WinMailSenderTable.java b/radiant/tiny-mail/src/main/java-gen/pro/fessional/wings/tiny/mail/database/autogen/tables/WinMailSenderTable.java index 91e95f9f8..ce9ab73d0 100644 --- a/radiant/tiny-mail/src/main/java-gen/pro/fessional/wings/tiny/mail/database/autogen/tables/WinMailSenderTable.java +++ b/radiant/tiny-mail/src/main/java-gen/pro/fessional/wings/tiny/mail/database/autogen/tables/WinMailSenderTable.java @@ -37,7 +37,7 @@ value = { "https://www.jooq.org", "jOOQ version:3.18.9", - "schema version:2020102701" + "schema version:2020102801" }, comments = "This class is generated by jOOQ" ) @@ -108,17 +108,17 @@ public Class getRecordType() { /** * The column win_mail_sender.mail_to. */ - public final TableField MailTo = createField(DSL.name("mail_to"), SQLDataType.VARCHAR(500).nullable(false).defaultValue(DSL.inline("", SQLDataType.VARCHAR)), this, ""); + public final TableField MailTo = createField(DSL.name("mail_to"), SQLDataType.VARCHAR(900).nullable(false).defaultValue(DSL.inline("", SQLDataType.VARCHAR)), this, ""); /** * The column win_mail_sender.mail_cc. */ - public final TableField MailCc = createField(DSL.name("mail_cc"), SQLDataType.VARCHAR(500).nullable(false).defaultValue(DSL.inline("", SQLDataType.VARCHAR)), this, ""); + public final TableField MailCc = createField(DSL.name("mail_cc"), SQLDataType.VARCHAR(900).nullable(false).defaultValue(DSL.inline("", SQLDataType.VARCHAR)), this, ""); /** * The column win_mail_sender.mail_bcc. */ - public final TableField MailBcc = createField(DSL.name("mail_bcc"), SQLDataType.VARCHAR(500).nullable(false).defaultValue(DSL.inline("", SQLDataType.VARCHAR)), this, ""); + public final TableField MailBcc = createField(DSL.name("mail_bcc"), SQLDataType.VARCHAR(900).nullable(false).defaultValue(DSL.inline("", SQLDataType.VARCHAR)), this, ""); /** * The column win_mail_sender.mail_reply. @@ -143,12 +143,12 @@ public Class getRecordType() { /** * The column win_mail_sender.mail_file. */ - public final TableField MailFile = createField(DSL.name("mail_file"), SQLDataType.VARCHAR(9000).nullable(false).defaultValue(DSL.inline("", SQLDataType.VARCHAR)), this, ""); + public final TableField MailFile = createField(DSL.name("mail_file"), SQLDataType.CLOB, this, ""); /** * The column win_mail_sender.mail_mark. */ - public final TableField MailMark = createField(DSL.name("mail_mark"), SQLDataType.VARCHAR(200).nullable(false).defaultValue(DSL.inline("", SQLDataType.VARCHAR)), this, ""); + public final TableField MailMark = createField(DSL.name("mail_mark"), SQLDataType.VARCHAR(900).nullable(false).defaultValue(DSL.inline("", SQLDataType.VARCHAR)), this, ""); /** * The column win_mail_sender.mail_date. diff --git a/radiant/tiny-mail/src/main/resources/wings-flywave/master/07-mail/2020-10-27v01-tiny_mail.sql b/radiant/tiny-mail/src/main/resources/wings-flywave/master/07-mail/2020-10-27v01-tiny_mail.sql index 61d8920ae..89754fe81 100644 --- a/radiant/tiny-mail/src/main/resources/wings-flywave/master/07-mail/2020-10-27v01-tiny_mail.sql +++ b/radiant/tiny-mail/src/main/resources/wings-flywave/master/07-mail/2020-10-27v01-tiny_mail.sql @@ -1,9 +1,9 @@ CREATE TABLE `win_mail_sender` ( - `id` BIGINT(20) NOT NULL COMMENT 'primary key/mail_id', + `id` BIGINT NOT NULL COMMENT 'primary key/mail_id', `create_dt` DATETIME(3) NOT NULL DEFAULT NOW(3) COMMENT 'created datetime(sys)', `modify_dt` DATETIME(3) NOT NULL DEFAULT '1000-01-01' ON UPDATE NOW(3) COMMENT 'modified datetime(sys)', `delete_dt` DATETIME(3) NOT NULL DEFAULT '1000-01-01' COMMENT 'logic deleted datetime', - `commit_id` BIGINT(20) NOT NULL COMMENT 'commit id', + `commit_id` BIGINT NOT NULL COMMENT 'commit id', `mail_apps` VARCHAR(500) NOT NULL DEFAULT '' COMMENT 'belong to applications, comma-separated, default spring.application.name', `mail_runs` VARCHAR(100) NOT NULL DEFAULT '' COMMENT 'RunMode(product|test|develop|local), comma-separated case-insensitive, default all', `mail_conf` VARCHAR(100) NOT NULL DEFAULT '' COMMENT 'config name, default', @@ -14,7 +14,7 @@ CREATE TABLE `win_mail_sender` ( `mail_reply` VARCHAR(200) NOT NULL DEFAULT '' COMMENT 'mail reply', `mail_subj` VARCHAR(400) NOT NULL DEFAULT '' COMMENT 'mail subject', `mail_text` TEXT NULL COMMENT 'mail content', - `mail_html` TINYINT(1) NOT NULL DEFAULT '1' COMMENT 'whether HTML email', + `mail_html` BOOLEAN NOT NULL DEFAULT '1' COMMENT 'whether HTML email', `mail_file` TEXT NULL COMMENT 'attachment name and path map, json format', `mail_mark` VARCHAR(900) NOT NULL DEFAULT '' COMMENT 'business key to lookup', `mail_date` DATETIME(3) NOT NULL DEFAULT '1000-01-01' COMMENT 'scheduled mail send (sys)', @@ -23,16 +23,16 @@ CREATE TABLE `win_mail_sender` ( `last_send` DATETIME(3) NOT NULL DEFAULT '1000-01-01' COMMENT 'previous send (sys)', `last_fail` TEXT NULL COMMENT 'previous fail info', `last_done` DATETIME(3) NOT NULL DEFAULT '1000-01-01' COMMENT 'previous success (sys)', - `last_cost` INT(11) NOT NULL DEFAULT '0' COMMENT 'mills of previous send cost', + `last_cost` INT NOT NULL DEFAULT '0' COMMENT 'mills of previous send cost', `next_send` DATETIME(3) NOT NULL DEFAULT '1000-01-01' COMMENT 'next send datetime (sys)', - `next_lock` INT(11) NOT NULL DEFAULT '0' COMMENT 'optimistic lock of sending', - `sum_send` INT(11) NOT NULL DEFAULT '0' COMMENT 'total count of send', - `sum_fail` INT(11) NOT NULL DEFAULT '0' COMMENT 'total count of fail', - `sum_done` INT(11) NOT NULL DEFAULT '0' COMMENT 'total count of success', - `max_fail` INT(11) NOT NULL DEFAULT '0' COMMENT 'max count of fail, 0 means use the config', - `max_done` INT(11) NOT NULL DEFAULT '0' COMMENT 'max count of success, 0 means use the config', - `ref_type` INT(11) NOT NULL DEFAULT '0' COMMENT 'ref type indicate key1, key2 usage', - `ref_key1` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'ref key1, generally the primary key', + `next_lock` INT NOT NULL DEFAULT '0' COMMENT 'optimistic lock of sending', + `sum_send` INT NOT NULL DEFAULT '0' COMMENT 'total count of send', + `sum_fail` INT NOT NULL DEFAULT '0' COMMENT 'total count of fail', + `sum_done` INT NOT NULL DEFAULT '0' COMMENT 'total count of success', + `max_fail` INT NOT NULL DEFAULT '0' COMMENT 'max count of fail, 0 means use the config', + `max_done` INT NOT NULL DEFAULT '0' COMMENT 'max count of success, 0 means use the config', + `ref_type` INT NOT NULL DEFAULT '0' COMMENT 'ref type indicate key1, key2 usage', + `ref_key1` BIGINT NOT NULL DEFAULT '0' COMMENT 'ref key1, generally the primary key', `ref_key2` VARCHAR(500) NOT NULL DEFAULT '' COMMENT 'ref key2, generally the composite data', PRIMARY KEY (`id`), INDEX ix_next_send (`next_send`), diff --git a/radiant/tiny-task/src/main/resources/wings-flywave/branch/somefix/03-task-tune/2021-10-26v02-task-tune.sql b/radiant/tiny-task/src/main/resources/wings-flywave/branch/somefix/03-task-tune/2021-10-26v02-task-tune.sql index 88e5da9ce..a5d3386fb 100644 --- a/radiant/tiny-task/src/main/resources/wings-flywave/branch/somefix/03-task-tune/2021-10-26v02-task-tune.sql +++ b/radiant/tiny-task/src/main/resources/wings-flywave/branch/somefix/03-task-tune/2021-10-26v02-task-tune.sql @@ -1,6 +1,6 @@ -- win_task_define ALTER TABLE `win_task_define` - ADD COLUMN `timing_tune` INT(11) NOT NULL DEFAULT '0' COMMENT 'execute before or after tune (seconds)' AFTER `timing_rate`, + ADD COLUMN `timing_tune` INT NOT NULL DEFAULT '0' COMMENT 'execute before or after tune (seconds)' AFTER `timing_rate`, CHANGE COLUMN `last_done` `last_exit` DATETIME(3) NOT NULL DEFAULT '1000-01-01' COMMENT 'previous done/fail (sys)'; UPDATE `win_task_define` @@ -10,7 +10,7 @@ WHERE last_fail > '2000-01-01'; ALTER TABLE `win_task_define` DROP COLUMN `last_fail`, - ADD COLUMN `last_fail` TINYINT(1) NOT NULL DEFAULT '0' COMMENT 'whether previous fail' AFTER last_exit; + ADD COLUMN `last_fail` BOOLEAN NOT NULL DEFAULT '0' COMMENT 'whether previous fail' AFTER last_exit; UPDATE `win_task_define` SET last_fail = timing_tune, @@ -21,7 +21,7 @@ WHERE timing_tune = 1; ALTER TABLE `win_task_result` ADD COLUMN `task_key` VARCHAR(200) NOT NULL DEFAULT '' COMMENT 'conf file key, auto-generated' AFTER `task_id`, CHANGE COLUMN `task_msg` `exit_data` TEXT NULL DEFAULT NULL COMMENT 'return (json) or exception (stacktrace)', - ADD COLUMN `exit_fail` TINYINT(1) NOT NULL DEFAULT '0' COMMENT 'whether fail' AFTER `exit_data`, + ADD COLUMN `exit_fail` BOOLEAN NOT NULL DEFAULT '0' COMMENT 'whether fail' AFTER `exit_data`, CHANGE COLUMN `time_done` `time_exit` DATETIME(3) NOT NULL DEFAULT '1000-01-01' COMMENT 'datetime of done/fail (sys)'; UPDATE `win_task_result` diff --git a/radiant/tiny-task/src/main/resources/wings-flywave/master/06-task/2020-10-26v01-tiny_task.sql b/radiant/tiny-task/src/main/resources/wings-flywave/master/06-task/2020-10-26v01-tiny_task.sql index 63834535a..5dbcd1884 100644 --- a/radiant/tiny-task/src/main/resources/wings-flywave/master/06-task/2020-10-26v01-tiny_task.sql +++ b/radiant/tiny-task/src/main/resources/wings-flywave/master/06-task/2020-10-26v01-tiny_task.sql @@ -1,17 +1,17 @@ CREATE TABLE `win_task_define` ( - `id` BIGINT(20) NOT NULL COMMENT 'primary key/task_id', + `id` BIGINT NOT NULL COMMENT 'primary key/task_id', `create_dt` DATETIME(3) NOT NULL DEFAULT NOW(3) COMMENT 'created datetime(sys)', `modify_dt` DATETIME(3) NOT NULL DEFAULT '1000-01-01' ON UPDATE NOW(3) COMMENT 'modified datetime(sys)', `delete_dt` DATETIME(3) NOT NULL DEFAULT '1000-01-01' COMMENT 'logic deleted datetime', - `commit_id` BIGINT(20) NOT NULL COMMENT 'commit id', + `commit_id` BIGINT NOT NULL COMMENT 'commit id', `propkey` VARCHAR(200) NOT NULL DEFAULT '' COMMENT 'conf file key, auto-generated', - `enabled` TINYINT(1) NOT NULL DEFAULT '1' COMMENT 'whether to register and execute', - `autorun` TINYINT(1) NOT NULL DEFAULT '1' COMMENT 'whether to auto register and start', - `version` INT(11) NOT NULL DEFAULT '0' COMMENT 'version number, higher overrides lower one', + `enabled` BOOLEAN NOT NULL DEFAULT '1' COMMENT 'whether to register and execute', + `autorun` BOOLEAN NOT NULL DEFAULT '1' COMMENT 'whether to auto register and start', + `version` INT NOT NULL DEFAULT '0' COMMENT 'version number, higher overrides lower one', `tasker_bean` VARCHAR(300) NOT NULL DEFAULT '' COMMENT 'beans annotated by TinyTasker, formatted as Class#method', `tasker_para` TEXT NULL COMMENT 'parameters of the task, object array in json format', `tasker_name` VARCHAR(200) NOT NULL DEFAULT '' COMMENT 'task name, used for notice and log, shortClassName#method', - `tasker_fast` TINYINT(1) NOT NULL DEFAULT '1' COMMENT 'whether light task, fast execution, completed in seconds', + `tasker_fast` BOOLEAN NOT NULL DEFAULT '1' COMMENT 'whether light task, fast execution, completed in seconds', `tasker_apps` VARCHAR(500) NOT NULL DEFAULT '' COMMENT 'belong to applications, comma-separated, default spring.application.name', `tasker_runs` VARCHAR(100) NOT NULL DEFAULT '' COMMENT 'RunMode(product|test|develop|local), comma-separated case-insensitive', `notice_bean` VARCHAR(200) NOT NULL DEFAULT '' COMMENT 'notice bean, SmallNotice type, fullpath of Class', @@ -20,43 +20,43 @@ CREATE TABLE `win_task_define` ( `timing_zone` VARCHAR(100) NOT NULL DEFAULT '' COMMENT 'timezone of scheduling , default system timezone', `timing_type` VARCHAR(100) NOT NULL DEFAULT 'cron' COMMENT 'scheduling expression type', `timing_cron` VARCHAR(100) NOT NULL DEFAULT '' COMMENT 'scheduling expression content', - `timing_idle` INT(11) NOT NULL DEFAULT '0' COMMENT 'fixed idle interval (seconds)', - `timing_rate` INT(11) NOT NULL DEFAULT '0' COMMENT 'fixed frequency interval (seconds)', - `timing_tune` INT(11) NOT NULL DEFAULT '0' COMMENT 'execute before or after tune (seconds)', - `timing_miss` INT(11) NOT NULL DEFAULT '0' COMMENT 'within how many seconds of a misfire', - `timing_beat` INT(11) NOT NULL DEFAULT '0' COMMENT 'interval seconds of heartbeat', + `timing_idle` INT NOT NULL DEFAULT '0' COMMENT 'fixed idle interval (seconds)', + `timing_rate` INT NOT NULL DEFAULT '0' COMMENT 'fixed frequency interval (seconds)', + `timing_tune` INT NOT NULL DEFAULT '0' COMMENT 'execute before or after tune (seconds)', + `timing_miss` INT NOT NULL DEFAULT '0' COMMENT 'within how many seconds of a misfire', + `timing_beat` INT NOT NULL DEFAULT '0' COMMENT 'interval seconds of heartbeat, default auto calc', `during_from` VARCHAR(20) NOT NULL DEFAULT '' COMMENT 'schedule start datetime at timingZone, yyyy-MM-dd HH:mm:ss', `during_stop` VARCHAR(20) NOT NULL DEFAULT '' COMMENT 'schedule stop datetime at timingZone, yyyy-MM-dd HH:mm:ss', - `during_exec` INT(11) NOT NULL DEFAULT '0' COMMENT 'stop schedule after how many total executions', - `during_fail` INT(11) NOT NULL DEFAULT '0' COMMENT 'stop schedule after how many consecutive failures', - `during_done` INT(11) NOT NULL DEFAULT '0' COMMENT 'stop schedule after how many successful executions', - `during_boot` INT(11) NOT NULL DEFAULT '0' COMMENT 'recount each time the app is started, and stop schedule after how many successful executions', - `result_keep` INT(11) NOT NULL DEFAULT '60' COMMENT 'how many days to save the execution results', + `during_exec` INT NOT NULL DEFAULT '0' COMMENT 'stop schedule after how many total executions', + `during_fail` INT NOT NULL DEFAULT '0' COMMENT 'stop schedule after how many consecutive failures', + `during_done` INT NOT NULL DEFAULT '0' COMMENT 'stop schedule after how many successful executions', + `during_boot` INT NOT NULL DEFAULT '0' COMMENT 'recount each time the app is started, and stop schedule after how many successful executions', + `result_keep` INT NOT NULL DEFAULT '60' COMMENT 'how many days to save the execution results', `last_exec` DATETIME(3) NOT NULL DEFAULT '1000-01-01' COMMENT 'previous exec (sys)', `last_exit` DATETIME(3) NOT NULL DEFAULT '1000-01-01' COMMENT 'previous done/fail (sys)', - `last_fail` TINYINT(1) NOT NULL DEFAULT '0' COMMENT 'whether previous fail', + `last_fail` BOOLEAN NOT NULL DEFAULT '0' COMMENT 'whether previous fail', `next_exec` DATETIME(3) NOT NULL DEFAULT '1000-01-01' COMMENT 'next exec (sys), default stop', - `next_lock` INT(11) NOT NULL DEFAULT '0' COMMENT 'optimistic lock of exec', - `dur_fail` INT(11) NOT NULL DEFAULT '0' COMMENT 'total count of consecutive fail', - `sum_exec` INT(11) NOT NULL DEFAULT '0' COMMENT 'total count of exec', - `sum_fail` INT(11) NOT NULL DEFAULT '0' COMMENT 'total count of fail', - `sum_done` INT(11) NOT NULL DEFAULT '0' COMMENT 'total count of done', + `next_lock` INT NOT NULL DEFAULT '0' COMMENT 'optimistic lock of exec', + `dur_fail` INT NOT NULL DEFAULT '0' COMMENT 'total count of consecutive fail', + `sum_exec` INT NOT NULL DEFAULT '0' COMMENT 'total count of exec', + `sum_fail` INT NOT NULL DEFAULT '0' COMMENT 'total count of fail', + `sum_done` INT NOT NULL DEFAULT '0' COMMENT 'total count of done', PRIMARY KEY (`id`), UNIQUE INDEX uq_tasker_bean (`tasker_bean`) ) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COMMENT ='141/Task Define'; CREATE TABLE `win_task_result` ( - `id` BIGINT(20) NOT NULL COMMENT 'primary key', - `task_id` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'task id, win_task_define.id', + `id` BIGINT NOT NULL COMMENT 'primary key', + `task_id` BIGINT NOT NULL DEFAULT '0' COMMENT 'task id, win_task_define.id', `task_key` VARCHAR(200) NOT NULL DEFAULT '' COMMENT 'conf file key, auto-generated', `task_app` VARCHAR(300) NOT NULL DEFAULT '' COMMENT 'belong to applications, comma-separated', - `task_pid` INT(11) NOT NULL DEFAULT '0' COMMENT 'belong to jvm pid', + `task_pid` INT NOT NULL DEFAULT '0' COMMENT 'belong to jvm pid', `exit_data` TEXT NULL COMMENT 'return (json) or exception (stacktrace)', - `exit_fail` TINYINT(1) NOT NULL DEFAULT '0' COMMENT 'whether fail', + `exit_fail` BOOLEAN NOT NULL DEFAULT '0' COMMENT 'whether fail', `time_exec` DATETIME(3) NOT NULL DEFAULT '1000-01-01' COMMENT 'datetime of exec (sys)', `time_exit` DATETIME(3) NOT NULL DEFAULT '1000-01-01' COMMENT 'datetime of done/fail (sys)', - `time_cost` INT(11) NOT NULL DEFAULT '0' COMMENT 'mills cost of task', + `time_cost` INT NOT NULL DEFAULT '0' COMMENT 'mills cost of task', PRIMARY KEY (`id`), INDEX ix_task_id (`task_id`) ) ENGINE = InnoDB diff --git a/wings/faceless-flywave/src/main/resources/wings-flywave/master/00-init/2019-05-12v01-version-journal.sql b/wings/faceless-flywave/src/main/resources/wings-flywave/master/00-init/2019-05-12v01-version-journal.sql index 9b259391d..595d2400d 100644 --- a/wings/faceless-flywave/src/main/resources/wings-flywave/master/00-init/2019-05-12v01-version-journal.sql +++ b/wings/faceless-flywave/src/main/resources/wings-flywave/master/00-init/2019-05-12v01-version-journal.sql @@ -2,10 +2,10 @@ -- CREATE DATABASE `wings` /*!40100 DEFAULT CHARACTER SET utf8mb4 */; CREATE TABLE `sys_schema_version` ( - `revision` BIGINT(20) NOT NULL COMMENT 'version + build', + `revision` BIGINT NOT NULL COMMENT 'version + build', `create_dt` DATETIME(3) NOT NULL DEFAULT NOW(3) COMMENT 'created datetime', `modify_dt` DATETIME(3) NOT NULL DEFAULT '1000-01-01' ON UPDATE NOW(3) COMMENT 'modified datetime', - `commit_id` BIGINT(20) NOT NULL COMMENT 'commit id', + `commit_id` BIGINT NOT NULL COMMENT 'commit id', `apply_dt` DATETIME(3) NOT NULL DEFAULT '1000-01-01' COMMENT 'applied datetime', `comments` VARCHAR(500) NOT NULL DEFAULT '' COMMENT 'sql path', `upto_sql` TEXT NOT NULL COMMENT 'upgrade script', @@ -18,7 +18,7 @@ CREATE TABLE `sys_schema_journal` ( `table_name` VARCHAR(100) NOT NULL COMMENT 'plain table name', `create_dt` DATETIME(3) NOT NULL DEFAULT NOW(3) COMMENT 'created datetime', `modify_dt` DATETIME(3) NOT NULL DEFAULT '1000-01-01' ON UPDATE NOW(3) COMMENT 'modified datetime', - `commit_id` BIGINT(20) NOT NULL COMMENT 'commit id', + `commit_id` BIGINT NOT NULL COMMENT 'commit id', `ddl_instbl` TEXT NOT NULL COMMENT 'trace DDL of insert', `ddl_instrg` TEXT NOT NULL COMMENT 'trigger DDL of insert', `ddl_updtbl` TEXT NOT NULL COMMENT 'trace DDL of update', diff --git a/wings/faceless-jooq/src/test/java/pro/fessional/wings/faceless/app/database/autogen/tables/SysConstantEnumTable.java b/wings/faceless-jooq/src/test/java/pro/fessional/wings/faceless/app/database/autogen/tables/SysConstantEnumTable.java index c23156e6f..27e149f45 100644 --- a/wings/faceless-jooq/src/test/java/pro/fessional/wings/faceless/app/database/autogen/tables/SysConstantEnumTable.java +++ b/wings/faceless-jooq/src/test/java/pro/fessional/wings/faceless/app/database/autogen/tables/SysConstantEnumTable.java @@ -29,13 +29,13 @@ /** - * The table wings.sys_constant_enum. + * The table wings_faceless.sys_constant_enum. */ @Generated( value = { "https://www.jooq.org", - "jOOQ version:3.18.7", - "schema version:2020102701" + "jOOQ version:3.18.9", + "schema version:2022060102" }, comments = "This class is generated by jOOQ" ) @@ -184,7 +184,6 @@ public SelectField mapping(Function5 SelectField mapping(Class toType, Function5 from) { return convertFrom(toType, Records.mapping(from)); } - /** * alias asK5 diff --git a/wings/faceless-jooq/src/test/java/pro/fessional/wings/faceless/app/database/autogen/tables/SysStandardI18nTable.java b/wings/faceless-jooq/src/test/java/pro/fessional/wings/faceless/app/database/autogen/tables/SysStandardI18nTable.java index d84142e49..f3139f14e 100644 --- a/wings/faceless-jooq/src/test/java/pro/fessional/wings/faceless/app/database/autogen/tables/SysStandardI18nTable.java +++ b/wings/faceless-jooq/src/test/java/pro/fessional/wings/faceless/app/database/autogen/tables/SysStandardI18nTable.java @@ -29,13 +29,13 @@ /** - * The table wings.sys_standard_i18n. + * The table wings_faceless.sys_standard_i18n. */ @Generated( value = { "https://www.jooq.org", - "jOOQ version:3.18.7", - "schema version:2020102701" + "jOOQ version:3.18.9", + "schema version:2022060102" }, comments = "This class is generated by jOOQ" ) @@ -184,7 +184,6 @@ public SelectField mapping(Function5 SelectField mapping(Class toType, Function5 from) { return convertFrom(toType, Records.mapping(from)); } - /** * alias asM5 diff --git a/wings/faceless-jooq/src/test/java/pro/fessional/wings/faceless/app/database/autogen/tables/TstNormalTableTable.java b/wings/faceless-jooq/src/test/java/pro/fessional/wings/faceless/app/database/autogen/tables/TstNormalTableTable.java index da0746116..2d95e8656 100644 --- a/wings/faceless-jooq/src/test/java/pro/fessional/wings/faceless/app/database/autogen/tables/TstNormalTableTable.java +++ b/wings/faceless-jooq/src/test/java/pro/fessional/wings/faceless/app/database/autogen/tables/TstNormalTableTable.java @@ -41,13 +41,13 @@ /** - * The table wings.tst_normal_table. + * The table wings_faceless.tst_normal_table. */ @Generated( value = { "https://www.jooq.org", - "jOOQ version:3.18.7", - "schema version:2020102701" + "jOOQ version:3.18.9", + "schema version:2022060102" }, comments = "This class is generated by jOOQ" ) @@ -245,7 +245,6 @@ public SelectField mapping(Class toType, Function13delete_dt condition diff --git a/wings/faceless-jooq/src/test/java/pro/fessional/wings/faceless/app/database/autogen/tables/TstShardingTable.java b/wings/faceless-jooq/src/test/java/pro/fessional/wings/faceless/app/database/autogen/tables/TstShardingTable.java index 8b8895659..df9521c6f 100644 --- a/wings/faceless-jooq/src/test/java/pro/fessional/wings/faceless/app/database/autogen/tables/TstShardingTable.java +++ b/wings/faceless-jooq/src/test/java/pro/fessional/wings/faceless/app/database/autogen/tables/TstShardingTable.java @@ -38,13 +38,13 @@ /** - * The table wings.tst_sharding. + * The table wings_faceless.tst_sharding. */ @Generated( value = { "https://www.jooq.org", - "jOOQ version:3.18.7", - "schema version:2020102701" + "jOOQ version:3.18.9", + "schema version:2022060102" }, comments = "This class is generated by jOOQ" ) @@ -217,7 +217,6 @@ public SelectField mapping(Class toType, Function8delete_dt condition diff --git a/wings/faceless-shard/src/test/java/pro/fessional/wings/faceless/app/database/autogen/tables/TstNormalTableTable.java b/wings/faceless-shard/src/test/java/pro/fessional/wings/faceless/app/database/autogen/tables/TstNormalTableTable.java index 328a324fe..b13be9699 100644 --- a/wings/faceless-shard/src/test/java/pro/fessional/wings/faceless/app/database/autogen/tables/TstNormalTableTable.java +++ b/wings/faceless-shard/src/test/java/pro/fessional/wings/faceless/app/database/autogen/tables/TstNormalTableTable.java @@ -39,13 +39,13 @@ /** - * The table wings.tst_normal_table. + * The table wings_faceless.tst_normal_table. */ @Generated( value = { "https://www.jooq.org", - "jOOQ version:3.18.7", - "schema version:2020102701" + "jOOQ version:3.18.9", + "schema version:2022060102" }, comments = "This class is generated by jOOQ" ) @@ -243,7 +243,6 @@ public SelectField mapping(Class toType, Function13delete_dt condition diff --git a/wings/faceless-shard/src/test/java/pro/fessional/wings/faceless/app/database/autogen/tables/TstShardingTable.java b/wings/faceless-shard/src/test/java/pro/fessional/wings/faceless/app/database/autogen/tables/TstShardingTable.java index 481d472d2..f4ade0c27 100644 --- a/wings/faceless-shard/src/test/java/pro/fessional/wings/faceless/app/database/autogen/tables/TstShardingTable.java +++ b/wings/faceless-shard/src/test/java/pro/fessional/wings/faceless/app/database/autogen/tables/TstShardingTable.java @@ -36,13 +36,13 @@ /** - * The table wings.tst_sharding. + * The table wings_faceless.tst_sharding. */ @Generated( value = { "https://www.jooq.org", - "jOOQ version:3.18.7", - "schema version:2020102701" + "jOOQ version:3.18.9", + "schema version:2022060102" }, comments = "This class is generated by jOOQ" ) @@ -215,7 +215,6 @@ public SelectField mapping(Class toType, Function8delete_dt condition diff --git a/wings/faceless/src/main/resources/wings-flywave/branch/feature/01-enum-i18n/2019-05-21v01-enum-i18n.sql b/wings/faceless/src/main/resources/wings-flywave/branch/feature/01-enum-i18n/2019-05-21v01-enum-i18n.sql index 41c868073..4dc6de256 100644 --- a/wings/faceless/src/main/resources/wings-flywave/branch/feature/01-enum-i18n/2019-05-21v01-enum-i18n.sql +++ b/wings/faceless/src/main/resources/wings-flywave/branch/feature/01-enum-i18n/2019-05-21v01-enum-i18n.sql @@ -1,5 +1,5 @@ CREATE TABLE `sys_constant_enum` ( - `id` INT(11) NOT NULL COMMENT 'id: 9+ digits for dynamic, 8 digits for static, 3-2-2 (table-column-value) segments, SUPER end with 00', + `id` INT NOT NULL COMMENT 'id: 9+ digits for dynamic, 8 digits for static, 3-2-2 (table-column-value) segments, SUPER end with 00', `type` VARCHAR(100) NOT NULL COMMENT 'enum group: same type for same enum, auto Pascal naming', `code` VARCHAR(100) NOT NULL COMMENT 'enum name: Fixed [code|id] for SUPER, external key, coding friendly', `hint` VARCHAR(100) NOT NULL COMMENT 'display message', diff --git a/wings/faceless/src/main/resources/wings-flywave/branch/somefix/05-journal-elapse/2021-10-26v05-journal-elapse.sql b/wings/faceless/src/main/resources/wings-flywave/branch/somefix/05-journal-elapse/2021-10-26v05-journal-elapse.sql index f54232df2..df8cd4d0a 100644 --- a/wings/faceless/src/main/resources/wings-flywave/branch/somefix/05-journal-elapse/2021-10-26v05-journal-elapse.sql +++ b/wings/faceless/src/main/resources/wings-flywave/branch/somefix/05-journal-elapse/2021-10-26v05-journal-elapse.sql @@ -1,5 +1,5 @@ ALTER TABLE `sys_commit_journal` - ADD COLUMN `parent_id` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'parent id if renew' AFTER `create_dt`, - ADD COLUMN `elapse_ms` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'elapse mills' AFTER `parent_id`; + ADD COLUMN `parent_id` BIGINT NOT NULL DEFAULT '0' COMMENT 'parent id if renew' AFTER `create_dt`, + ADD COLUMN `elapse_ms` BIGINT NOT NULL DEFAULT '0' COMMENT 'elapse mills' AFTER `parent_id`; -- CALL FLYWAVE('2021-10-26v05-journal-elapse.sql'); \ No newline at end of file diff --git a/wings/faceless/src/main/resources/wings-flywave/master/01-light/2019-05-20v01-light-commit.sql b/wings/faceless/src/main/resources/wings-flywave/master/01-light/2019-05-20v01-light-commit.sql index 39ec78d7a..58adecd21 100644 --- a/wings/faceless/src/main/resources/wings-flywave/master/01-light/2019-05-20v01-light-commit.sql +++ b/wings/faceless/src/main/resources/wings-flywave/master/01-light/2019-05-20v01-light-commit.sql @@ -1,18 +1,18 @@ CREATE TABLE `sys_light_sequence` ( `seq_name` VARCHAR(100) NOT NULL COMMENT 'sequence name', - `block_id` INT(11) NOT NULL DEFAULT 0 COMMENT 'block', - `next_val` BIGINT(20) NOT NULL DEFAULT '1' COMMENT 'next value', - `step_val` INT(11) NOT NULL DEFAULT '100' COMMENT 'step of increment', + `block_id` INT NOT NULL DEFAULT 0 COMMENT 'block', + `next_val` BIGINT NOT NULL DEFAULT '1' COMMENT 'next value', + `step_val` INT NOT NULL DEFAULT '100' COMMENT 'step of increment', `comments` VARCHAR(200) NOT NULL COMMENT 'comments', PRIMARY KEY (`seq_name`, `block_id`) ) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COMMENT ='103/Sequence Generation'; CREATE TABLE `sys_commit_journal` ( - `id` BIGINT(20) NOT NULL COMMENT 'primary key', + `id` BIGINT NOT NULL COMMENT 'primary key', `create_dt` DATETIME(3) NOT NULL DEFAULT NOW(3) COMMENT 'created datetime', - `parent_id` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'parent id if renew', - `elapse_ms` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'elapse mills', + `parent_id` BIGINT NOT NULL DEFAULT '0' COMMENT 'parent id if renew', + `elapse_ms` BIGINT NOT NULL DEFAULT '0' COMMENT 'elapse mills', `event_name` VARCHAR(200) NOT NULL COMMENT 'event name', `target_key` VARCHAR(200) NOT NULL DEFAULT '' COMMENT 'target data', `login_info` TEXT NULL COMMENT 'login info: agent, terminal', diff --git a/wings/testing-faceless/src/main/resources/wings-flywave/master/2022-0601v01-test.sql b/wings/testing-faceless/src/main/resources/wings-flywave/master/2022-0601v01-test.sql index 380587f46..f8a877e2e 100644 --- a/wings/testing-faceless/src/main/resources/wings-flywave/master/2022-0601v01-test.sql +++ b/wings/testing-faceless/src/main/resources/wings-flywave/master/2022-0601v01-test.sql @@ -1,44 +1,44 @@ -- apply@tst_.* error@stop CREATE TABLE `tst_sharding` ( - `id` BIGINT(20) NOT NULL COMMENT 'primary key', + `id` BIGINT NOT NULL COMMENT 'primary key', `create_dt` DATETIME(3) NOT NULL DEFAULT NOW(3) COMMENT 'created datetime', `modify_dt` DATETIME(3) NOT NULL DEFAULT '1000-01-01' ON UPDATE NOW(3) COMMENT 'modified datetime', `delete_dt` DATETIME(3) NOT NULL DEFAULT '1000-01-01' COMMENT 'logic deleted datetime', - `commit_id` BIGINT(20) NOT NULL COMMENT 'commit id', + `commit_id` BIGINT NOT NULL COMMENT 'commit id', `login_info` TEXT NULL COMMENT 'login info: agent, terminal', `other_info` TEXT NULL COMMENT 'other info: biz index data', - `language` INT(11) NOT NULL DEFAULT 1020111 COMMENT 'StandardLanguage', + `language` INT NOT NULL DEFAULT 1020111 COMMENT 'StandardLanguage', PRIMARY KEY (`id`) ) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COMMENT ='201/Sharding Test'; CREATE TABLE `tst_sharding_postfix` ( - `id` BIGINT(20) NOT NULL COMMENT 'primary key', + `id` BIGINT NOT NULL COMMENT 'primary key', `create_dt` DATETIME(3) NOT NULL DEFAULT NOW(3) COMMENT 'created datetime', `modify_dt` DATETIME(3) NOT NULL DEFAULT '1000-01-01' ON UPDATE NOW(3) COMMENT 'modified datetime', `delete_dt` DATETIME(3) NOT NULL DEFAULT '1000-01-01' COMMENT 'logic deleted datetime', - `commit_id` BIGINT(20) NOT NULL COMMENT 'commit id', + `commit_id` BIGINT NOT NULL COMMENT 'commit id', `login_info` TEXT NULL COMMENT 'login info: agent, terminal', `other_info` TEXT NULL COMMENT 'other info: biz index data', - `language` INT(11) NOT NULL DEFAULT 1020111 COMMENT 'StandardLanguage', + `language` INT NOT NULL DEFAULT 1020111 COMMENT 'StandardLanguage', PRIMARY KEY (`id`) ) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COMMENT ='201/Sharding Test'; CREATE TABLE `tst_normal_table` ( - `id` BIGINT(20) NOT NULL COMMENT 'primary key', + `id` BIGINT NOT NULL COMMENT 'primary key', `create_dt` DATETIME(3) NOT NULL DEFAULT NOW(3) COMMENT 'created datetime', `modify_dt` DATETIME(3) NOT NULL DEFAULT '1000-01-01' ON UPDATE NOW(3) COMMENT 'modified datetime', `delete_dt` DATETIME(3) NOT NULL DEFAULT '1000-01-01' COMMENT 'logic deleted datetime', - `commit_id` BIGINT(20) NOT NULL COMMENT 'commit id', + `commit_id` BIGINT NOT NULL COMMENT 'commit id', `value_varchar` VARCHAR(256) NOT NULL DEFAULT '0' COMMENT 'String', `value_decimal` DECIMAL(10, 2) NOT NULL DEFAULT '0' COMMENT 'BigDecimal', - `value_boolean` TINYINT(1) NOT NULL DEFAULT '0' COMMENT 'Boolean', - `value_int` INT(11) NOT NULL DEFAULT '0' COMMENT 'Integer', - `value_long` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Long', + `value_boolean` BOOLEAN NOT NULL DEFAULT '0' COMMENT 'Boolean', + `value_int` INT NOT NULL DEFAULT '0' COMMENT 'Integer', + `value_long` BIGINT NOT NULL DEFAULT '0' COMMENT 'Long', `value_date` DATE NOT NULL DEFAULT '1000-01-01' COMMENT 'LocalDate', `value_time` TIME NOT NULL DEFAULT '00:00:00' COMMENT 'LocalTime', - `value_lang` INT(11) NOT NULL DEFAULT '1020111' COMMENT 'StandardLanguage', + `value_lang` INT NOT NULL DEFAULT '1020111' COMMENT 'StandardLanguage', PRIMARY KEY (`id`) ) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COMMENT ='202/Normal Test'; diff --git a/wings/warlock/src/main/resources/wings-flywave/branch/somefix/04-conf-size/2021-10-26v03-conf-size.sql b/wings/warlock/src/main/resources/wings-flywave/branch/somefix/04-conf-size/2021-10-26v03-conf-size.sql index 0178a29db..19d1403c1 100644 --- a/wings/warlock/src/main/resources/wings-flywave/branch/somefix/04-conf-size/2021-10-26v03-conf-size.sql +++ b/wings/warlock/src/main/resources/wings-flywave/branch/somefix/04-conf-size/2021-10-26v03-conf-size.sql @@ -1,5 +1,5 @@ ALTER TABLE `win_conf_runtime` - ADD COLUMN `enabled` TINYINT(1) NOT NULL DEFAULT '1' COMMENT 'enabled' AFTER `key`, + ADD COLUMN `enabled` BOOLEAN NOT NULL DEFAULT '1' COMMENT 'enabled' AFTER `key`, ADD COLUMN `outline` VARCHAR(5000) NOT NULL DEFAULT '' COMMENT 'value ResolvableType' AFTER `initial`, CHANGE COLUMN `current` `current` TEXT NOT NULL COMMENT 'current value', CHANGE COLUMN `previous` `previous` TEXT NOT NULL COMMENT 'previous value', diff --git a/wings/warlock/src/main/resources/wings-flywave/master/04-auth/2020-10-24v01-user_login.sql b/wings/warlock/src/main/resources/wings-flywave/master/04-auth/2020-10-24v01-user_login.sql index cea67b84e..ba6cae86b 100644 --- a/wings/warlock/src/main/resources/wings-flywave/master/04-auth/2020-10-24v01-user_login.sql +++ b/wings/warlock/src/main/resources/wings-flywave/master/04-auth/2020-10-24v01-user_login.sql @@ -1,36 +1,36 @@ CREATE TABLE `win_user_basis` ( - `id` BIGINT(20) NOT NULL COMMENT 'primary key/user_id/uid', + `id` BIGINT NOT NULL COMMENT 'primary key/user_id/uid', `create_dt` DATETIME(3) NOT NULL DEFAULT NOW(3) COMMENT 'created datetime(sys)', `modify_dt` DATETIME(3) NOT NULL DEFAULT '1000-01-01' ON UPDATE NOW(3) COMMENT 'modified datetime(sys)', `delete_dt` DATETIME(3) NOT NULL DEFAULT '1000-01-01' COMMENT 'logic deleted datetime', - `commit_id` BIGINT(20) NOT NULL COMMENT 'commit id', + `commit_id` BIGINT NOT NULL COMMENT 'commit id', `nickname` VARCHAR(50) NOT NULL DEFAULT '' COMMENT 'nickname', `passsalt` VARCHAR(100) NOT NULL DEFAULT '' COMMENT 'password salt/random, read-only, no external use', - `gender` INT(11) NOT NULL DEFAULT '0' COMMENT 'gender/12001##:unknown|mail|female', + `gender` INT NOT NULL DEFAULT '0' COMMENT 'gender/12001##:unknown|mail|female', `avatar` VARCHAR(1000) NOT NULL DEFAULT '' COMMENT 'avatar url', `locale` CHAR(5) NOT NULL DEFAULT 'zh_CN' COMMENT 'language/Locale:StandardLanguageEnum', - `zoneid` INT(11) NOT NULL DEFAULT '1010201' COMMENT 'timezone/ZoneId:StandardTimezoneEnum', + `zoneid` INT NOT NULL DEFAULT '1010201' COMMENT 'timezone/ZoneId:StandardTimezoneEnum', `remark` VARCHAR(500) NOT NULL DEFAULT '' COMMENT 'comment', - `status` INT(11) NOT NULL DEFAULT '0' COMMENT 'user status/12002##:', + `status` INT NOT NULL DEFAULT '0' COMMENT 'user status/12002##:', PRIMARY KEY (`id`) ) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COMMENT ='120/User Basis'; CREATE TABLE `win_user_authn` ( - `id` BIGINT(20) NOT NULL COMMENT 'primary key', + `id` BIGINT NOT NULL COMMENT 'primary key', `create_dt` DATETIME(3) NOT NULL DEFAULT NOW(3) COMMENT 'created datetime(sys)', `modify_dt` DATETIME(3) NOT NULL DEFAULT '1000-01-01' ON UPDATE NOW(3) COMMENT 'modified datetime(sys)', `delete_dt` DATETIME(3) NOT NULL DEFAULT '1000-01-01' COMMENT 'logic deleted datetime', - `commit_id` BIGINT(20) NOT NULL COMMENT 'commit id', - `user_id` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'basic user/win_user_basis.id', + `commit_id` BIGINT NOT NULL COMMENT 'commit id', + `user_id` BIGINT NOT NULL DEFAULT '0' COMMENT 'basic user/win_user_basis.id', `auth_type` VARCHAR(10) NOT NULL COMMENT 'auth type/wings.warlock.security.auth-type.*', `username` VARCHAR(200) NOT NULL COMMENT 'account/id:email|mobile|union_id|api_key', `password` VARCHAR(200) NOT NULL DEFAULT '' COMMENT 'password/spring style|api_secret', `extra_para` VARCHAR(3000) NOT NULL DEFAULT '' COMMENT 'para for 3rd auth', `extra_user` VARCHAR(9000) NOT NULL DEFAULT '' COMMENT 'user info of 3rd', `expired_dt` DATETIME(3) NOT NULL DEFAULT '1000-01-01' COMMENT 'expiration, not for token, empty is disabled', - `failed_cnt` INT(11) NOT NULL DEFAULT '0' COMMENT 'continuous error count: clear on success', - `failed_max` INT(11) NOT NULL DEFAULT '5' COMMENT 'max continuous error', + `failed_cnt` INT NOT NULL DEFAULT '0' COMMENT 'continuous error count: clear on success', + `failed_max` INT NOT NULL DEFAULT '5' COMMENT 'max continuous error', PRIMARY KEY (`id`), UNIQUE INDEX uq_uid_type (`user_id`, `auth_type`), UNIQUE INDEX uq_type_name (`auth_type`, `username`) @@ -38,14 +38,14 @@ CREATE TABLE `win_user_authn` ( DEFAULT CHARSET = utf8mb4 COMMENT ='121/User Authn'; CREATE TABLE `win_user_login` ( - `id` BIGINT(20) NOT NULL COMMENT 'primary key', - `user_id` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'basic user/win_user_basis.id', + `id` BIGINT NOT NULL COMMENT 'primary key', + `user_id` BIGINT NOT NULL DEFAULT '0' COMMENT 'basic user/win_user_basis.id', `auth_type` VARCHAR(20) NOT NULL COMMENT 'auth type/wings.warlock.security.auth-type.*', `login_ip` VARCHAR(50) NOT NULL DEFAULT '' COMMENT 'login IP', `login_dt` DATETIME(3) NOT NULL DEFAULT NOW(3) COMMENT 'created datetime(sys)', `terminal` VARCHAR(1000) NOT NULL DEFAULT '' COMMENT 'login terminal', `details` VARCHAR(9000) NOT NULL DEFAULT '' COMMENT 'auth details', - `failed` TINYINT(1) NOT NULL DEFAULT '0' COMMENT 'fail or not', + `failed` BOOLEAN NOT NULL DEFAULT '0' COMMENT 'fail or not', PRIMARY KEY (`id`), INDEX ix_user_id (`user_id`) ) ENGINE = InnoDB diff --git a/wings/warlock/src/main/resources/wings-flywave/master/04-auth/2020-10-24v02-role_permit.sql b/wings/warlock/src/main/resources/wings-flywave/master/04-auth/2020-10-24v02-role_permit.sql index 6471ae137..c297ab810 100644 --- a/wings/warlock/src/main/resources/wings-flywave/master/04-auth/2020-10-24v02-role_permit.sql +++ b/wings/warlock/src/main/resources/wings-flywave/master/04-auth/2020-10-24v02-role_permit.sql @@ -1,9 +1,9 @@ CREATE TABLE `win_perm_entry` ( - `id` BIGINT(20) NOT NULL COMMENT 'primary key', + `id` BIGINT NOT NULL COMMENT 'primary key', `create_dt` DATETIME(3) NOT NULL DEFAULT NOW(3) COMMENT 'created datetime(sys)', `modify_dt` DATETIME(3) NOT NULL DEFAULT '1000-01-01' ON UPDATE NOW(3) COMMENT 'modified datetime(sys)', `delete_dt` DATETIME(3) NOT NULL DEFAULT '1000-01-01' COMMENT 'logic deleted datetime', - `commit_id` BIGINT(20) NOT NULL COMMENT 'commit id', + `commit_id` BIGINT NOT NULL COMMENT 'commit id', `scopes` VARCHAR(200) NOT NULL COMMENT 'all lowercase, period-separated', `action` VARCHAR(50) NOT NULL COMMENT 'all lowercase', `remark` VARCHAR(500) NOT NULL DEFAULT '' COMMENT 'comment', @@ -13,11 +13,11 @@ CREATE TABLE `win_perm_entry` ( DEFAULT CHARSET = utf8mb4 COMMENT ='130/Perm Entry'; CREATE TABLE `win_role_entry` ( - `id` BIGINT(20) NOT NULL COMMENT 'primary key', + `id` BIGINT NOT NULL COMMENT 'primary key', `create_dt` DATETIME(3) NOT NULL DEFAULT NOW(3) COMMENT 'created datetime(sys)', `modify_dt` DATETIME(3) NOT NULL DEFAULT '1000-01-01' ON UPDATE NOW(3) COMMENT 'modified datetime(sys)', `delete_dt` DATETIME(3) NOT NULL DEFAULT '1000-01-01' COMMENT 'logic deleted datetime', - `commit_id` BIGINT(20) NOT NULL COMMENT 'commit id', + `commit_id` BIGINT NOT NULL COMMENT 'commit id', `name` VARCHAR(50) NOT NULL COMMENT 'all uppercase, no separated, no ROLE_ prefix', `remark` VARCHAR(500) NOT NULL DEFAULT '' COMMENT 'comment', PRIMARY KEY (`id`), @@ -26,21 +26,21 @@ CREATE TABLE `win_role_entry` ( DEFAULT CHARSET = utf8mb4 COMMENT ='131/Role Entry'; CREATE TABLE `win_role_grant` ( - `refer_role` BIGINT(20) NOT NULL COMMENT 'current role/win_role_entry.id', - `grant_type` INT(11) NOT NULL COMMENT 'grant type/13301##:Role,Perm', - `grant_entry` BIGINT(20) NOT NULL COMMENT 'entry to grant: id/win_role_entry.id, win_perm_entry.id', + `refer_role` BIGINT NOT NULL COMMENT 'current role/win_role_entry.id', + `grant_type` INT NOT NULL COMMENT 'grant type/13301##:Role,Perm', + `grant_entry` BIGINT NOT NULL COMMENT 'entry to grant: id/win_role_entry.id, win_perm_entry.id', `create_dt` DATETIME(3) NOT NULL DEFAULT NOW(3) COMMENT 'created datetime(sys)', - `commit_id` BIGINT(20) NOT NULL COMMENT 'commit id', + `commit_id` BIGINT NOT NULL COMMENT 'commit id', PRIMARY KEY (`refer_role`, `grant_type`, `grant_entry`) ) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COMMENT ='134/Role Grant'; CREATE TABLE `win_user_grant` ( - `refer_user` BIGINT(20) NOT NULL COMMENT 'current user/win_user_basis.id', - `grant_type` INT(11) NOT NULL COMMENT 'grant type/13301##:Role,Perm', - `grant_entry` BIGINT(20) NOT NULL COMMENT 'entry to grant: id/win_role_entry.id, win_perm_entry.id', + `refer_user` BIGINT NOT NULL COMMENT 'current user/win_user_basis.id', + `grant_type` INT NOT NULL COMMENT 'grant type/13301##:Role,Perm', + `grant_entry` BIGINT NOT NULL COMMENT 'entry to grant: id/win_role_entry.id, win_perm_entry.id', `create_dt` DATETIME(3) NOT NULL DEFAULT NOW(3) COMMENT 'created datetime(sys)', - `commit_id` BIGINT(20) NOT NULL COMMENT 'commit id', + `commit_id` BIGINT NOT NULL COMMENT 'commit id', PRIMARY KEY (`refer_user`, `grant_type`, `grant_entry`) ) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COMMENT ='135/User Grant'; diff --git a/wings/warlock/src/main/resources/wings-flywave/master/05-conf/2020-10-25v01-conf_runtime.sql b/wings/warlock/src/main/resources/wings-flywave/master/05-conf/2020-10-25v01-conf_runtime.sql index 7b79280b8..2c61c5193 100644 --- a/wings/warlock/src/main/resources/wings-flywave/master/05-conf/2020-10-25v01-conf_runtime.sql +++ b/wings/warlock/src/main/resources/wings-flywave/master/05-conf/2020-10-25v01-conf_runtime.sql @@ -1,6 +1,6 @@ CREATE TABLE `win_conf_runtime` ( `key` VARCHAR(200) NOT NULL COMMENT 'conf key:Enum|Class|String', - `enabled` TINYINT(1) NOT NULL DEFAULT '1' COMMENT 'enabled', + `enabled` BOOLEAN NOT NULL DEFAULT '1' COMMENT 'enabled', `current` TEXT NOT NULL COMMENT 'current value', `previous` TEXT NOT NULL COMMENT 'previous value', `initial` TEXT NOT NULL COMMENT 'initial value', From fd0e1753d104df109b5d8907103157f607512bd0 Mon Sep 17 00:00:00 2001 From: trydofor Date: Thu, 1 Aug 2024 09:00:23 +0800 Subject: [PATCH 34/51] =?UTF-8?q?=E2=9C=A8=20auto=20gen=20metadata.json=20?= =?UTF-8?q?#281?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- observe/docs | 2 +- radiant/devs-coverage/pom.xml | 4 + .../info/AdditionalMetadataGenerator.java | 22 ++ ...itional-spring-configuration-metadata.json | 22 +- ...itional-spring-configuration-metadata.json | 29 +- .../spring/bean/FlywaveConfiguration.java | 24 +- ...itional-spring-configuration-metadata.json | 13 +- ...itional-spring-configuration-metadata.json | 10 +- ...itional-spring-configuration-metadata.json | 10 +- ...itional-spring-configuration-metadata.json | 10 +- ...itional-spring-configuration-metadata.json | 14 +- .../bean/SilencerRunnerConfiguration.java | 5 +- .../wings/silencer/support/MetaJsonMaker.java | 258 ++++++++++++++++++ ...itional-spring-configuration-metadata.json | 11 +- ...itional-spring-configuration-metadata.json | 17 +- ...itional-spring-configuration-metadata.json | 11 +- ...itional-spring-configuration-metadata.json | 19 +- ...itional-spring-configuration-metadata.json | 41 +-- .../bean/SlardarMonitorConfiguration.java | 5 +- ...itional-spring-configuration-metadata.json | 59 ++-- ...itional-spring-configuration-metadata.json | 10 +- .../warlock/controller/api}/WebLogViewer.java | 4 +- ...itional-spring-configuration-metadata.json | 50 ++-- .../conf/WarlockAwesomeAutoConfiguration.java | 17 -- ...itional-spring-configuration-metadata.json | 25 +- 25 files changed, 489 insertions(+), 203 deletions(-) create mode 100644 radiant/devs-coverage/src/main/java/pro/fessional/wings/devs/info/AdditionalMetadataGenerator.java create mode 100644 wings/silencer/src/main/java/pro/fessional/wings/silencer/support/MetaJsonMaker.java rename wings/{slardar-webmvc/src/main/java/pro/fessional/wings/slardar/monitor/viewer => warlock-shadow/src/main/java/pro/fessional/wings/warlock/controller/api}/WebLogViewer.java (88%) delete mode 100644 wings/warlock/src/main/java/pro/fessional/wings/warlock/spring/conf/WarlockAwesomeAutoConfiguration.java diff --git a/observe/docs b/observe/docs index 7b5106657..01b278add 160000 --- a/observe/docs +++ b/observe/docs @@ -1 +1 @@ -Subproject commit 7b510665769a70add77fa23c3b1117b783ad08df +Subproject commit 01b278addb932d3a99aff3c3f1bb987273a7bd6b diff --git a/radiant/devs-coverage/pom.xml b/radiant/devs-coverage/pom.xml index e3ab0043c..778d09bc9 100644 --- a/radiant/devs-coverage/pom.xml +++ b/radiant/devs-coverage/pom.xml @@ -89,6 +89,10 @@ pro.fessional.wings tiny-task + + pro.fessional.wings + tiny-grow + diff --git a/radiant/devs-coverage/src/main/java/pro/fessional/wings/devs/info/AdditionalMetadataGenerator.java b/radiant/devs-coverage/src/main/java/pro/fessional/wings/devs/info/AdditionalMetadataGenerator.java new file mode 100644 index 000000000..ad13b1f04 --- /dev/null +++ b/radiant/devs-coverage/src/main/java/pro/fessional/wings/devs/info/AdditionalMetadataGenerator.java @@ -0,0 +1,22 @@ +package pro.fessional.wings.devs.info; + +import pro.fessional.wings.silencer.support.MetaJsonMaker; + +import java.util.List; + +/** + * META-INF/additional-spring-configuration-metadata.json + * + * @author trydofor + * @since 2024-07-30 + */ +public class AdditionalMetadataGenerator { + + public static void main(String[] args) throws Exception { + MetaJsonMaker maker = new MetaJsonMaker(); + List metas = maker.scanMeta(); + List projs = maker.projMeta(metas); + maker.printMeta(projs); + maker.writeMeta(projs); + } +} diff --git a/radiant/tiny-mail/src/main/resources/META-INF/additional-spring-configuration-metadata.json b/radiant/tiny-mail/src/main/resources/META-INF/additional-spring-configuration-metadata.json index d307a8a41..b6913714e 100644 --- a/radiant/tiny-mail/src/main/resources/META-INF/additional-spring-configuration-metadata.json +++ b/radiant/tiny-mail/src/main/resources/META-INF/additional-spring-configuration-metadata.json @@ -1,10 +1,19 @@ { "groups": [ - {"name": "wings.enabled.pro.fessional.wings.tiny.mail.spring.conf"}, - {"name": "wings.enabled.pro.fessional.wings.tiny.mail.spring.bean"} + {"name": "wings.enabled.pro.fessional.wings.tiny.mail.controller"}, + {"name": "wings.enabled.pro.fessional.wings.tiny.mail.database.autogen.tables.daos"}, + {"name": "wings.enabled.pro.fessional.wings.tiny.mail.service.impl"}, + {"name": "wings.enabled.pro.fessional.wings.tiny.mail.spring.bean"}, + {"name": "wings.enabled.pro.fessional.wings.tiny.mail.spring.conf"} ], "properties": [ - {"name": "wings.enabled.pro.fessional.wings.tiny.mail.spring.conf.TinyMailAutoConfiguration", "type": "java.lang.Boolean"}, + {"name": "wings.enabled.pro.fessional.wings.tiny.mail.controller.MailListController", "type": "java.lang.Boolean", "description": "wings.enabled.tiny.mail.mvc-list for short."}, + {"name": "wings.enabled.pro.fessional.wings.tiny.mail.controller.MailSendController", "type": "java.lang.Boolean", "description": "wings.enabled.tiny.mail.mvc-send for short."}, + + {"name": "wings.enabled.pro.fessional.wings.tiny.mail.database.autogen.tables.daos.WinMailSenderDao", "type": "java.lang.Boolean"}, + + {"name": "wings.enabled.pro.fessional.wings.tiny.mail.service.impl.TinyMailListServiceImpl", "type": "java.lang.Boolean"}, + {"name": "wings.enabled.pro.fessional.wings.tiny.mail.service.impl.TinyMailServiceImpl", "type": "java.lang.Boolean"}, {"name": "wings.enabled.pro.fessional.wings.tiny.mail.spring.bean.TinyMailConfiguration", "type": "java.lang.Boolean"}, {"name": "wings.enabled.pro.fessional.wings.tiny.mail.spring.bean.TinyMailConfiguration$DaoServScan", "type": "java.lang.Boolean"}, @@ -13,12 +22,9 @@ {"name": "wings.enabled.pro.fessional.wings.tiny.mail.spring.bean.TinyMailConfiguration.mailNotice", "type": "java.lang.Boolean"}, {"name": "wings.enabled.pro.fessional.wings.tiny.mail.spring.bean.TinyMailConfiguration.mailSenderManager", "type": "java.lang.Boolean"}, {"name": "wings.enabled.pro.fessional.wings.tiny.mail.spring.bean.TinyMailConfiguration.mailSenderProvider", "type": "java.lang.Boolean"}, + {"name": "wings.enabled.pro.fessional.wings.tiny.mail.spring.bean.TinyMailConfiguration.tinyMailLazyRunner", "type": "java.lang.Boolean"}, - {"name": "wings.enabled.pro.fessional.wings.tiny.mail.controller.MailListController", "type": "java.lang.Boolean", "description": "wings.enabled.tiny.mail.mvc-list for short."}, - {"name": "wings.enabled.pro.fessional.wings.tiny.mail.controller.MailSendController", "type": "java.lang.Boolean", "description": "wings.enabled.tiny.mail.mvc-send for short."}, - - {"name": "wings.enabled.pro.fessional.wings.tiny.mail.service.impl.TinyMailListServiceImpl", "type": "java.lang.Boolean"}, - {"name": "wings.enabled.pro.fessional.wings.tiny.mail.service.impl.TinyMailServiceImpl", "type": "java.lang.Boolean"} + {"name": "wings.enabled.pro.fessional.wings.tiny.mail.spring.conf.TinyMailAutoConfiguration", "type": "java.lang.Boolean"} ], "hints": [] } \ No newline at end of file diff --git a/radiant/tiny-task/src/main/resources/META-INF/additional-spring-configuration-metadata.json b/radiant/tiny-task/src/main/resources/META-INF/additional-spring-configuration-metadata.json index e5a15204b..86dacad9e 100644 --- a/radiant/tiny-task/src/main/resources/META-INF/additional-spring-configuration-metadata.json +++ b/radiant/tiny-task/src/main/resources/META-INF/additional-spring-configuration-metadata.json @@ -1,29 +1,30 @@ { "groups": [ - {"name": "wings.enabled.pro.fessional.wings.tiny.task.spring.conf"}, - {"name": "wings.enabled.pro.fessional.wings.tiny.task.spring.bean"} + {"name": "wings.enabled.pro.fessional.wings.tiny.task.controller"}, + {"name": "wings.enabled.pro.fessional.wings.tiny.task.database.autogen.tables.daos"}, + {"name": "wings.enabled.pro.fessional.wings.tiny.task.service.impl"}, + {"name": "wings.enabled.pro.fessional.wings.tiny.task.spring.bean"}, + {"name": "wings.enabled.pro.fessional.wings.tiny.task.spring.conf"} ], "properties": [ - {"name": "wings.enabled.pro.fessional.wings.tiny.task.spring.conf.TinyTaskAutoConfiguration", "type": "java.lang.Boolean"}, - - {"name": "wings.enabled.pro.fessional.wings.tiny.task.spring.bean.TinyTaskConfiguration", "type": "java.lang.Boolean"}, - {"name": "wings.enabled.pro.fessional.wings.tiny.task.spring.bean.TinyTaskConfiguration$DaoServScan", "type": "java.lang.Boolean"}, - {"name": "wings.enabled.pro.fessional.wings.tiny.task.spring.bean.TinyTaskConfiguration$MvcRestScan", "type": "java.lang.Boolean"}, - {"name": "wings.enabled.pro.fessional.wings.tiny.task.spring.bean.TinyTaskConfiguration.tinyTaskerAutoRunner", "type": "java.lang.Boolean", "description": "wings.enabled.tiny.task.autorun for short."}, - - {"name": "wings.enabled.pro.fessional.wings.tiny.task.spring.bean.TinyTaskConfiguration.mailNotice", "type": "java.lang.Boolean"}, - {"name": "wings.enabled.pro.fessional.wings.tiny.task.spring.bean.TinyTaskConfiguration.mailSenderManager", "type": "java.lang.Boolean"}, - {"name": "wings.enabled.pro.fessional.wings.tiny.task.spring.bean.TinyTaskConfiguration.mailSenderProvider", "type": "java.lang.Boolean"}, - {"name": "wings.enabled.pro.fessional.wings.tiny.task.controller.TaskConfController", "type": "java.lang.Boolean", "description": "wings.enabled.tiny.task.mvc-conf for short."}, {"name": "wings.enabled.pro.fessional.wings.tiny.task.controller.TaskExecController", "type": "java.lang.Boolean", "description": "wings.enabled.tiny.task.mvc-exec for short."}, {"name": "wings.enabled.pro.fessional.wings.tiny.task.controller.TaskListController", "type": "java.lang.Boolean", "description": "wings.enabled.tiny.task.mvc-list for short."}, + {"name": "wings.enabled.pro.fessional.wings.tiny.task.database.autogen.tables.daos.WinTaskDefineDao", "type": "java.lang.Boolean"}, + {"name": "wings.enabled.pro.fessional.wings.tiny.task.database.autogen.tables.daos.WinTaskResultDao", "type": "java.lang.Boolean"}, + {"name": "wings.enabled.pro.fessional.wings.tiny.task.service.impl.TinyTaskBeatServiceImpl", "type": "java.lang.Boolean"}, {"name": "wings.enabled.pro.fessional.wings.tiny.task.service.impl.TinyTaskConfServiceImpl", "type": "java.lang.Boolean"}, {"name": "wings.enabled.pro.fessional.wings.tiny.task.service.impl.TinyTaskExecServiceImpl", "type": "java.lang.Boolean"}, {"name": "wings.enabled.pro.fessional.wings.tiny.task.service.impl.TinyTaskListServiceImpl", "type": "java.lang.Boolean"}, - {"name": "wings.enabled.pro.fessional.wings.tiny.task.service.impl.TinyTaskServiceImpl", "type": "java.lang.Boolean"} + {"name": "wings.enabled.pro.fessional.wings.tiny.task.service.impl.TinyTaskServiceImpl", "type": "java.lang.Boolean"}, + + {"name": "wings.enabled.pro.fessional.wings.tiny.task.spring.bean.TinyTaskConfiguration", "type": "java.lang.Boolean"}, + {"name": "wings.enabled.pro.fessional.wings.tiny.task.spring.bean.TinyTaskConfiguration$DaoServScan", "type": "java.lang.Boolean"}, + {"name": "wings.enabled.pro.fessional.wings.tiny.task.spring.bean.TinyTaskConfiguration.tinyTaskerAutoRunner", "type": "java.lang.Boolean", "description": "wings.enabled.tiny.task.autorun for short."}, + + {"name": "wings.enabled.pro.fessional.wings.tiny.task.spring.conf.TinyTaskAutoConfiguration", "type": "java.lang.Boolean"} ], "hints": [] } \ No newline at end of file diff --git a/wings/faceless-flywave/src/main/java/pro/fessional/wings/faceless/spring/bean/FlywaveConfiguration.java b/wings/faceless-flywave/src/main/java/pro/fessional/wings/faceless/spring/bean/FlywaveConfiguration.java index cf425b18a..3871a8f9f 100644 --- a/wings/faceless-flywave/src/main/java/pro/fessional/wings/faceless/spring/bean/FlywaveConfiguration.java +++ b/wings/faceless-flywave/src/main/java/pro/fessional/wings/faceless/spring/bean/FlywaveConfiguration.java @@ -104,6 +104,18 @@ public SchemaFulldumpManager schemaFulldumpManager( return new SchemaFulldumpManager(statementParser, schemaDefinitionLoader); } + @Bean + @ConditionalWingsEnabled + public MysqlDefinitionLoader schemaDefinitionLoader(FlywaveSqlProp conf) { + if ("mysql".equalsIgnoreCase(conf.getDialect())) { + log.info("FacelessFlywave spring-bean schemaDefinitionLoader"); + return new MysqlDefinitionLoader(); + } + else { + throw new IllegalArgumentException("only support mysql"); + } + } + @Bean @ConditionalWingsEnabled public MySqlStatementParser sqlStatementParser(FlywaveSqlProp conf) { @@ -141,18 +153,6 @@ public SqlSegmentProcessor sqlSegmentProcessor(FlywaveSqlProp conf) { } } - @Bean - @ConditionalWingsEnabled - public MysqlDefinitionLoader schemaDefinitionLoader(FlywaveSqlProp conf) { - if ("mysql".equalsIgnoreCase(conf.getDialect())) { - log.info("FacelessFlywave spring-bean schemaDefinitionLoader"); - return new MysqlDefinitionLoader(); - } - else { - throw new IllegalArgumentException("only support mysql"); - } - } - @Bean @ConditionalWingsEnabled(abs = FlywaveFitProp.Key$checker) public ApplicationRunnerOrdered revisionCheckerRunner(DefaultRevisionManager manager, FlywaveFitProp prop) { diff --git a/wings/faceless-flywave/src/main/resources/META-INF/additional-spring-configuration-metadata.json b/wings/faceless-flywave/src/main/resources/META-INF/additional-spring-configuration-metadata.json index de91c5cb6..26a8b6b7c 100644 --- a/wings/faceless-flywave/src/main/resources/META-INF/additional-spring-configuration-metadata.json +++ b/wings/faceless-flywave/src/main/resources/META-INF/additional-spring-configuration-metadata.json @@ -1,13 +1,9 @@ { "groups": [ - {"name": "wings.enabled.pro.fessional.wings.faceless.spring.conf"}, - {"name": "wings.enabled.pro.fessional.wings.faceless.spring.bean"} + {"name": "wings.enabled.pro.fessional.wings.faceless.spring.bean"}, + {"name": "wings.enabled.pro.fessional.wings.faceless.spring.conf"} ], "properties": [ - {"name": "java.awt.headless", "type": "java.lang.Boolean"}, - - {"name": "wings.enabled.pro.fessional.wings.faceless.spring.conf.FlywaveAutoConfiguration", "type": "java.lang.Boolean"}, - {"name": "wings.enabled.pro.fessional.wings.faceless.spring.bean.FlywaveConfiguration", "type": "java.lang.Boolean"}, {"name": "wings.enabled.pro.fessional.wings.faceless.spring.bean.FlywaveConfiguration.revisionCheckerRunner", "type": "java.lang.Boolean", "description": "wings.faceless.flywave.checker for short."}, {"name": "wings.enabled.pro.fessional.wings.faceless.spring.bean.FlywaveConfiguration.schemaDefinitionLoader", "type": "java.lang.Boolean"}, @@ -15,7 +11,10 @@ {"name": "wings.enabled.pro.fessional.wings.faceless.spring.bean.FlywaveConfiguration.schemaJournalManager", "type": "java.lang.Boolean"}, {"name": "wings.enabled.pro.fessional.wings.faceless.spring.bean.FlywaveConfiguration.schemaShardingManager", "type": "java.lang.Boolean"}, {"name": "wings.enabled.pro.fessional.wings.faceless.spring.bean.FlywaveConfiguration.schemaVersionManger", "type": "java.lang.Boolean"}, - {"name": "wings.enabled.pro.fessional.wings.faceless.spring.bean.FlywaveConfiguration.sqlSegmentProcessor", "type": "java.lang.Boolean"} + {"name": "wings.enabled.pro.fessional.wings.faceless.spring.bean.FlywaveConfiguration.sqlSegmentProcessor", "type": "java.lang.Boolean"}, + {"name": "wings.enabled.pro.fessional.wings.faceless.spring.bean.FlywaveConfiguration.sqlStatementParser", "type": "java.lang.Boolean"}, + + {"name": "wings.enabled.pro.fessional.wings.faceless.spring.conf.FlywaveAutoConfiguration", "defaultValue": false, "type": "java.lang.Boolean", "description": "wings.enabled.faceless.flywave for short."} ], "hints": [] } \ No newline at end of file diff --git a/wings/faceless-jooq/src/main/resources/META-INF/additional-spring-configuration-metadata.json b/wings/faceless-jooq/src/main/resources/META-INF/additional-spring-configuration-metadata.json index 2b122b95d..20ce2781a 100644 --- a/wings/faceless-jooq/src/main/resources/META-INF/additional-spring-configuration-metadata.json +++ b/wings/faceless-jooq/src/main/resources/META-INF/additional-spring-configuration-metadata.json @@ -1,11 +1,9 @@ { "groups": [ - {"name": "wings.enabled.pro.fessional.wings.faceless.spring.conf"}, - {"name": "wings.enabled.pro.fessional.wings.faceless.spring.bean"} + {"name": "wings.enabled.pro.fessional.wings.faceless.spring.bean"}, + {"name": "wings.enabled.pro.fessional.wings.faceless.spring.conf"} ], "properties": [ - {"name": "wings.enabled.pro.fessional.wings.faceless.spring.conf.FacelessJooqAutoConfiguration", "type": "java.lang.Boolean"}, - {"name": "wings.enabled.pro.fessional.wings.faceless.spring.bean.FacelessJooqConfiguration", "type": "java.lang.Boolean"}, {"name": "wings.enabled.pro.fessional.wings.faceless.spring.bean.FacelessJooqConfiguration.jooqAutoQualifyFieldListener", "type": "java.lang.Boolean", "description": "wings.faceless.jooq.conf.auto-qualify for short."}, {"name": "wings.enabled.pro.fessional.wings.faceless.spring.bean.FacelessJooqConfiguration.jooqWingsConfigCustomizer", "type": "java.lang.Boolean"}, @@ -13,7 +11,9 @@ {"name": "wings.enabled.pro.fessional.wings.faceless.spring.bean.FacelessJooqCudConfiguration", "type": "java.lang.Boolean"}, {"name": "wings.enabled.pro.fessional.wings.faceless.spring.bean.FacelessJooqCudConfiguration$CudListenerBean", "type": "java.lang.Boolean", "description": "wings.faceless.jooq.conf.listen-cud for short."}, {"name": "wings.enabled.pro.fessional.wings.faceless.spring.bean.FacelessJooqCudConfiguration$JournalDiffWired", "type": "java.lang.Boolean"}, - {"name": "wings.enabled.pro.fessional.wings.faceless.spring.bean.FacelessJooqCudConfiguration.jooqJournalDeleteListener", "type": "java.lang.Boolean", "description": "wings.faceless.jooq.conf.journal-delete for short."} + {"name": "wings.enabled.pro.fessional.wings.faceless.spring.bean.FacelessJooqCudConfiguration.jooqJournalDeleteListener", "defaultValue": false, "type": "java.lang.Boolean", "description": "wings.faceless.jooq.conf.journal-delete for short."}, + + {"name": "wings.enabled.pro.fessional.wings.faceless.spring.conf.FacelessJooqAutoConfiguration", "type": "java.lang.Boolean"} ], "hints": [] } \ No newline at end of file diff --git a/wings/faceless-shard/src/main/resources/META-INF/additional-spring-configuration-metadata.json b/wings/faceless-shard/src/main/resources/META-INF/additional-spring-configuration-metadata.json index 60d3a2328..2fcc0ca72 100644 --- a/wings/faceless-shard/src/main/resources/META-INF/additional-spring-configuration-metadata.json +++ b/wings/faceless-shard/src/main/resources/META-INF/additional-spring-configuration-metadata.json @@ -1,14 +1,14 @@ { "groups": [ - {"name": "wings.enabled.pro.fessional.wings.faceless.spring.conf"}, - {"name": "wings.enabled.pro.fessional.wings.faceless.spring.bean"} + {"name": "wings.enabled.pro.fessional.wings.faceless.spring.bean"}, + {"name": "wings.enabled.pro.fessional.wings.faceless.spring.conf"} ], "properties": [ - {"name": "wings.enabled.pro.fessional.wings.faceless.spring.conf.FacelessShardAutoConfiguration", "type": "java.lang.Boolean"}, - {"name": "wings.enabled.pro.fessional.wings.faceless.spring.bean.FacelessShardingSphereConfiguration", "type": "java.lang.Boolean"}, {"name": "wings.enabled.pro.fessional.wings.faceless.spring.bean.FacelessShardingSphereConfiguration.shardingDataSourceContext", "type": "java.lang.Boolean"}, - {"name": "wings.enabled.pro.fessional.wings.faceless.spring.bean.FacelessShardingSphereConfiguration.writeRouteOnlyAround", "type": "java.lang.Boolean"} + {"name": "wings.enabled.pro.fessional.wings.faceless.spring.bean.FacelessShardingSphereConfiguration.writeRouteOnlyAround", "type": "java.lang.Boolean"}, + + {"name": "wings.enabled.pro.fessional.wings.faceless.spring.conf.FacelessShardAutoConfiguration", "type": "java.lang.Boolean"} ], "hints": [] } \ No newline at end of file diff --git a/wings/faceless/src/main/resources/META-INF/additional-spring-configuration-metadata.json b/wings/faceless/src/main/resources/META-INF/additional-spring-configuration-metadata.json index 9e52c6d2b..63e6a78cf 100644 --- a/wings/faceless/src/main/resources/META-INF/additional-spring-configuration-metadata.json +++ b/wings/faceless/src/main/resources/META-INF/additional-spring-configuration-metadata.json @@ -1,11 +1,9 @@ { "groups": [ - {"name": "wings.enabled.pro.fessional.wings.faceless.spring.conf"}, - {"name": "wings.enabled.pro.fessional.wings.faceless.spring.bean"} + {"name": "wings.enabled.pro.fessional.wings.faceless.spring.bean"}, + {"name": "wings.enabled.pro.fessional.wings.faceless.spring.conf"} ], "properties": [ - {"name": "wings.enabled.pro.fessional.wings.faceless.spring.conf.FacelessAutoConfiguration", "type": "java.lang.Boolean"}, - {"name": "wings.enabled.pro.fessional.wings.faceless.spring.bean.FacelessConfiguration", "type": "java.lang.Boolean"}, {"name": "wings.enabled.pro.fessional.wings.faceless.spring.bean.FacelessConfiguration.commitJournalModify", "type": "java.lang.Boolean"}, {"name": "wings.enabled.pro.fessional.wings.faceless.spring.bean.FacelessConfiguration.dataSourceContext", "type": "java.lang.Boolean"}, @@ -21,7 +19,9 @@ {"name": "wings.enabled.pro.fessional.wings.faceless.spring.bean.FacelessLightIdConfiguration.lightIdLoader", "type": "java.lang.Boolean"}, {"name": "wings.enabled.pro.fessional.wings.faceless.spring.bean.FacelessLightIdConfiguration.lightIdService", "type": "java.lang.Boolean"}, {"name": "wings.enabled.pro.fessional.wings.faceless.spring.bean.FacelessLightIdConfiguration.lightSequenceModify", "type": "java.lang.Boolean"}, - {"name": "wings.enabled.pro.fessional.wings.faceless.spring.bean.FacelessLightIdConfiguration.lightSequenceSelect", "type": "java.lang.Boolean"} + {"name": "wings.enabled.pro.fessional.wings.faceless.spring.bean.FacelessLightIdConfiguration.lightSequenceSelect", "type": "java.lang.Boolean"}, + + {"name": "wings.enabled.pro.fessional.wings.faceless.spring.conf.FacelessAutoConfiguration", "type": "java.lang.Boolean"} ], "hints": [] } \ No newline at end of file diff --git a/wings/silencer-curse/src/main/resources/META-INF/additional-spring-configuration-metadata.json b/wings/silencer-curse/src/main/resources/META-INF/additional-spring-configuration-metadata.json index 9f7823986..82146fc77 100644 --- a/wings/silencer-curse/src/main/resources/META-INF/additional-spring-configuration-metadata.json +++ b/wings/silencer-curse/src/main/resources/META-INF/additional-spring-configuration-metadata.json @@ -1,15 +1,15 @@ { "groups": [ - {"name": "wings.enabled.pro.fessional.wings.silencer.spring.conf"}, - {"name": "wings.enabled.pro.fessional.wings.silencer.spring.bean"} + {"name": "wings.enabled.pro.fessional.wings.silencer.spring.bean"}, + {"name": "wings.enabled.pro.fessional.wings.silencer.spring.conf"} ], "properties": [ - {"name": "wings.enabled.pro.fessional.wings.silencer.spring.conf.SilencerCurseAutoConfiguration", "type": "java.lang.Boolean"}, - {"name": "wings.enabled.pro.fessional.wings.silencer.spring.bean.SilencerCurseConfiguration", "type": "java.lang.Boolean"}, - {"name": "wings.enabled.pro.fessional.wings.silencer.spring.bean.SilencerCurseConfiguration.auditPropRunner", "type": "java.lang.Boolean", "description": "wings.enabled.silencer.audit-prop for short."}, + {"name": "wings.enabled.pro.fessional.wings.silencer.spring.bean.SilencerCurseConfiguration.auditPropRunner", "defaultValue": false, "type": "java.lang.Boolean", "description": "wings.enabled.silencer.audit-prop for short."}, + {"name": "wings.enabled.pro.fessional.wings.silencer.spring.bean.SilencerCurseConfiguration.infoGitJvmRunner", "type": "java.lang.Boolean"}, {"name": "wings.enabled.pro.fessional.wings.silencer.spring.bean.SilencerCurseConfiguration.muteConsoleRunner", "type": "java.lang.Boolean", "description": "wings.enabled.silencer.mute-console for short."}, {"name": "wings.enabled.pro.fessional.wings.silencer.spring.bean.SilencerCurseConfiguration.runtimeMode", "type": "java.lang.Boolean"}, + {"name": "wings.enabled.pro.fessional.wings.silencer.spring.bean.SilencerCurseConfiguration.thisLazyAwarePostProcessor", "type": "java.lang.Boolean"}, {"name": "wings.enabled.pro.fessional.wings.silencer.spring.bean.SilencerEncryptConfiguration", "type": "java.lang.Boolean"}, {"name": "wings.enabled.pro.fessional.wings.silencer.spring.bean.SilencerEncryptConfiguration.aes256", "type": "java.lang.Boolean"}, @@ -20,7 +20,9 @@ {"name": "wings.enabled.pro.fessional.wings.silencer.spring.bean.SilencerTweakConfiguration", "type": "java.lang.Boolean"}, {"name": "wings.enabled.pro.fessional.wings.silencer.spring.bean.SilencerTweakConfiguration$ClockWired", "type": "java.lang.Boolean", "description": "wings.enabled.silencer.tweak-clock for short."}, {"name": "wings.enabled.pro.fessional.wings.silencer.spring.bean.SilencerTweakConfiguration$LogbackWired", "type": "java.lang.Boolean", "description": "wings.enabled.silencer.tweak-logback for short."}, - {"name": "wings.enabled.pro.fessional.wings.silencer.spring.bean.SilencerTweakConfiguration$StackWired", "type": "java.lang.Boolean", "description": "wings.enabled.silencer.tweak-stack for short."} + {"name": "wings.enabled.pro.fessional.wings.silencer.spring.bean.SilencerTweakConfiguration$StackWired", "type": "java.lang.Boolean", "description": "wings.enabled.silencer.tweak-stack for short."}, + + {"name": "wings.enabled.pro.fessional.wings.silencer.spring.conf.SilencerCurseAutoConfiguration", "type": "java.lang.Boolean"} ], "hints": [] } \ No newline at end of file diff --git a/wings/silencer/src/main/java/pro/fessional/wings/silencer/spring/bean/SilencerRunnerConfiguration.java b/wings/silencer/src/main/java/pro/fessional/wings/silencer/spring/bean/SilencerRunnerConfiguration.java index e5acf5a5f..68bed16d1 100644 --- a/wings/silencer/src/main/java/pro/fessional/wings/silencer/spring/bean/SilencerRunnerConfiguration.java +++ b/wings/silencer/src/main/java/pro/fessional/wings/silencer/spring/bean/SilencerRunnerConfiguration.java @@ -8,6 +8,7 @@ import org.springframework.context.ConfigurableApplicationContext; import org.springframework.context.annotation.Configuration; import org.springframework.context.event.EventListener; +import org.springframework.stereotype.Component; import pro.fessional.wings.silencer.runner.ApplicationReadyEventRunner; import pro.fessional.wings.silencer.runner.ApplicationStartedEventRunner; import pro.fessional.wings.silencer.spring.boot.ConditionalWingsEnabled; @@ -27,7 +28,7 @@ public class SilencerRunnerConfiguration { private static final Log log = LogFactory.getLog(SilencerRunnerConfiguration.class); - @Configuration(proxyBeanMethods = false) + @Component @ConditionalWingsEnabled public static class ReadyEvent { @EventListener @@ -54,7 +55,7 @@ public void on(ApplicationReadyEvent event) { } } - @Configuration(proxyBeanMethods = false) + @Component @ConditionalWingsEnabled public static class StartedEvent { @EventListener diff --git a/wings/silencer/src/main/java/pro/fessional/wings/silencer/support/MetaJsonMaker.java b/wings/silencer/src/main/java/pro/fessional/wings/silencer/support/MetaJsonMaker.java new file mode 100644 index 000000000..b71b501c9 --- /dev/null +++ b/wings/silencer/src/main/java/pro/fessional/wings/silencer/support/MetaJsonMaker.java @@ -0,0 +1,258 @@ +package pro.fessional.wings.silencer.support; + +import lombok.Data; +import org.jetbrains.annotations.NotNull; +import org.springframework.beans.factory.config.BeanDefinition; +import org.springframework.boot.autoconfigure.AutoConfiguration; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.ScannedGenericBeanDefinition; +import org.springframework.core.type.AnnotationMetadata; +import org.springframework.core.type.classreading.MetadataReader; +import pro.fessional.wings.silencer.spring.boot.ConditionalWingsEnabled; + +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.io.PrintWriter; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Set; +import java.util.TreeSet; + +/** + * META-INF/additional-spring-configuration-metadata.json + * + * @author trydofor + * @since 2024-07-30 + */ +public class MetaJsonMaker { + + @Data + public static class Meta { + @NotNull + private final String abs; + @NotNull + private final String name; + @NotNull + private final String root; + @NotNull + private final String claz; + private final String pkg; + + private final boolean bool; + private final boolean conf; + } + + @Data + public static class Proj { + private final String root; + private final Set grp = new TreeSet<>(); + private final List meta = new ArrayList<>(); + } + + /** + * maven compile first + */ + @NotNull + public List scanMeta() throws Exception { + return scanMeta("pro.fessional"); + } + + /** + * maven compile first + */ + @NotNull + public List scanMeta(@NotNull String pkg) throws Exception { + + var scanner = new ClassPathScanningCandidateComponentProvider(true) { + @Override + protected boolean isCandidateComponent(MetadataReader metadataReader) { + return true; + } + }; + + Set beans = scanner.findCandidateComponents(pkg); + if (beans.isEmpty()) return Collections.emptyList(); + + List result = new ArrayList<>(beans.size()); + + final String cwe = ConditionalWingsEnabled.class.getName(); + final String acn = AutoConfiguration.class.getName(); + final String ccn = Configuration.class.getName(); + final String cbn = Bean.class.getName(); + for (BeanDefinition bd : beans) { + if (!(bd instanceof ScannedGenericBeanDefinition gbd)) continue; + + final String name = gbd.getBeanClassName(); + if (!name.startsWith(pkg)) continue; + + final String pack = name.substring(0, name.lastIndexOf('.')); + + String tmp = Objects.requireNonNull(gbd.getResource().getFile()).getCanonicalPath(); + final String root = tmp.substring(0, tmp.indexOf("/target/classes")); + + final AnnotationMetadata amd = gbd.getMetadata(); + Map caa = amd.getAnnotationAttributes(cwe, true); + if (caa != null) { + boolean conf = !amd.hasEnclosingClass() && (amd.hasAnnotation(acn) || amd.hasAnnotation(ccn)); + Meta wm = new Meta((String) caa.get("abs"), name, root, name, pack, (Boolean) caa.get("value"), conf); + result.add(wm); + } + + for (var md : amd.getDeclaredMethods()) { + var ban = md.getAnnotationAttributes(cbn, true); + if (ban == null) continue; + + var maa = md.getAnnotationAttributes(cwe, true); + if (maa != null) { + String mdn = name + "." + md.getMethodName(); + Meta wm = new Meta((String) maa.get("abs"), mdn, root, name, pack, (Boolean) maa.get("value"), false); + result.add(wm); + } + } + } + + return result; + } + + @NotNull + public List projMeta(@NotNull List meta) { + if (meta.isEmpty()) return Collections.emptyList(); + Map prjs = new LinkedHashMap<>(); + for (Meta mt : meta) { + Proj prj = prjs.computeIfAbsent(mt.root, Proj::new); + prj.grp.add(mt.pkg); + prj.meta.add(mt); + } + + List list = new ArrayList<>(prjs.values()); + list.sort(Comparator.comparing(Proj::getRoot)); + for (Proj prj : list) { + prj.meta.sort(Comparator.comparing(Meta::getName)); + } + return list; + } + + /** + * configuration-metadata + */ + public void writeMeta(@NotNull List proj) throws IOException { + writeMeta(proj, "additional-spring-configuration-metadata.json"); + } + + /** + * configuration-metadata + */ + public void writeMeta(@NotNull List proj, String json) throws IOException { + int c = 1; + for (Proj prj : proj) { + String file = prj.root + "/src/main/resources/META-INF/" + json; + System.out.printf("\n%2d %s", c++, file); + + try (var fw = new FileWriter(file)) { + fw.write("{"); + + fw.write("\n \"groups\": ["); + int i = prj.grp.size() - 1; + for (String grp : prj.grp) { + fw.write("\n {\"name\": \"wings.enabled."); + fw.write(grp); + fw.write("\"}"); + if (i-- > 0) fw.write(","); + } + fw.write("\n ],"); + + fw.write("\n \"properties\": ["); + i = prj.meta.size() - 1; + Meta pre = null; + for (Meta mt : prj.meta) { + + if (pre != null && !mt.claz.equals(pre.claz)) { + if (mt.conf) { + fw.write('\n'); + } + else if (!mt.pkg.equals(pre.pkg)) { + fw.write('\n'); + } + } + pre = mt; + + if (mt.abs.isEmpty()) { + fw.write("\n {\"name\": \"wings.enabled."); + fw.write(mt.name); + fw.write("\", "); + if (!mt.bool) fw.write("\"defaultValue\": false, "); + fw.write("\"type\": \"java.lang.Boolean\"}"); + } + else { + fw.write("\n {\"name\": \"wings.enabled."); + fw.write(mt.name); + fw.write("\", "); + if (!mt.bool) fw.write("\"defaultValue\": false, "); + fw.write("\"type\": \"java.lang.Boolean\", \"description\": \""); + fw.write(mt.abs); + fw.write(" for short.\"}"); + } + if (i-- > 0) fw.write(","); + } + fw.write("\n ],"); + + fw.write("\n \"hints\": []"); + fw.write("\n}"); + } + } + } + + /** + * observe/docs/src/0-wings/0h-prop-index.md + */ + public void printMeta(@NotNull List proj) { + printMeta(new PrintWriter(System.out), proj, "pro.fessional.wings."); + } + + /** + * observe/docs/src/0-wings/0h-prop-index.md + */ + public void printMeta(@NotNull PrintWriter writer, @NotNull List proj, String omit) { + for (Proj prj : proj) { + File tmp = new File(prj.root); + writer.println("\n### " + tmp.getParentFile().getName() + "/" + tmp.getName()); + boolean uls = true; + String pkg = null; + String nms = null; + for (Meta mt : prj.meta) { + String pg = mt.pkg; + if (pkg == null || !pkg.equals(pg)) { + uls = true; + writer.println("\n#### " + pg.replace(omit, "")); + } + pkg = pg; + + String pd = mt.bool ? "" : " (false)"; + if (!mt.abs.isEmpty()) { + pd = pd + " = " + mt.abs; + } + String nm = mt.name.substring(pg.length() + 1); + if (nms != null && nm.contains(nms)) { + writer.println(" - " + nm.substring(nms.length()) + pd); + } + else { + if (uls) writer.println(); + uls = false; + writer.println("* ." + nm + pd); + nms = nm; + } + } + writer.flush(); + } + writer.println(); + writer.flush(); + } +} diff --git a/wings/silencer/src/main/resources/META-INF/additional-spring-configuration-metadata.json b/wings/silencer/src/main/resources/META-INF/additional-spring-configuration-metadata.json index 588b4deb9..987e50a5d 100644 --- a/wings/silencer/src/main/resources/META-INF/additional-spring-configuration-metadata.json +++ b/wings/silencer/src/main/resources/META-INF/additional-spring-configuration-metadata.json @@ -1,18 +1,19 @@ { "groups": [ - {"name": "wings.enabled.pro.fessional.wings.silencer.spring.conf"}, - {"name": "wings.enabled.pro.fessional.wings.silencer.spring.bean"} + {"name": "wings.enabled.pro.fessional.wings.silencer.spring.bean"}, + {"name": "wings.enabled.pro.fessional.wings.silencer.spring.conf"} ], "properties": [ - {"name": "wings.enabled.pro.fessional.wings.silencer.spring.conf.SilencerAutoConfiguration", "type": "java.lang.Boolean"}, - {"name": "wings.enabled.pro.fessional.wings.silencer.spring.bean.SilencerConfiguration", "type": "java.lang.Boolean"}, {"name": "wings.enabled.pro.fessional.wings.silencer.spring.bean.SilencerConfiguration.applicationInspectRunner", "type": "java.lang.Boolean"}, {"name": "wings.enabled.pro.fessional.wings.silencer.spring.bean.SilencerConfiguration.messageSourceHelper", "type": "java.lang.Boolean"}, + {"name": "wings.enabled.pro.fessional.wings.silencer.spring.bean.SilencerConfiguration.wingsReorderProcessor", "type": "java.lang.Boolean", "description": "wings.enabled.silencer.bean-reorder for short."}, {"name": "wings.enabled.pro.fessional.wings.silencer.spring.bean.SilencerRunnerConfiguration", "type": "java.lang.Boolean"}, {"name": "wings.enabled.pro.fessional.wings.silencer.spring.bean.SilencerRunnerConfiguration$ReadyEvent", "type": "java.lang.Boolean"}, - {"name": "wings.enabled.pro.fessional.wings.silencer.spring.bean.SilencerRunnerConfiguration$StartedEvent", "type": "java.lang.Boolean"} + {"name": "wings.enabled.pro.fessional.wings.silencer.spring.bean.SilencerRunnerConfiguration$StartedEvent", "type": "java.lang.Boolean"}, + + {"name": "wings.enabled.pro.fessional.wings.silencer.spring.conf.SilencerAutoConfiguration", "type": "java.lang.Boolean"} ], "hints": [] } \ No newline at end of file diff --git a/wings/slardar-hazel-caching/src/main/resources/META-INF/additional-spring-configuration-metadata.json b/wings/slardar-hazel-caching/src/main/resources/META-INF/additional-spring-configuration-metadata.json index 0a5adea4f..5f8e3ed5a 100644 --- a/wings/slardar-hazel-caching/src/main/resources/META-INF/additional-spring-configuration-metadata.json +++ b/wings/slardar-hazel-caching/src/main/resources/META-INF/additional-spring-configuration-metadata.json @@ -1,21 +1,24 @@ { "groups": [ - {"name": "wings.enabled.pro.fessional.wings.slardar.spring.conf"}, - {"name": "wings.enabled.pro.fessional.wings.slardar.spring.bean"} + {"name": "wings.enabled.pro.fessional.wings.slardar.spring.bean"}, + {"name": "wings.enabled.pro.fessional.wings.slardar.spring.conf"} ], "properties": [ - {"name": "wings.enabled.pro.fessional.wings.slardar.spring.conf.SlardarCacheAutoConfiguration", "type": "java.lang.Boolean"}, - {"name": "wings.enabled.pro.fessional.wings.slardar.spring.bean.HazelcastConfigConfiguration", "type": "java.lang.Boolean"}, - {"name": "wings.enabled.pro.fessional.wings.slardar.spring.bean.HazelcastConfigConfiguration.wingsHazelcastAloneCustomizer", "type": "java.lang.Boolean", "description": "wings.enabled.slardar.hazelcast-standalone for short."}, + {"name": "wings.enabled.pro.fessional.wings.slardar.spring.bean.HazelcastConfigConfiguration.wingsHazelcastAloneCustomizer", "defaultValue": false, "type": "java.lang.Boolean", "description": "wings.enabled.slardar.hazelcast-standalone for short."}, {"name": "wings.enabled.pro.fessional.wings.slardar.spring.bean.HazelcastConfigConfiguration.wingsHazelcastCacheCustomizer", "type": "java.lang.Boolean"}, + {"name": "wings.enabled.pro.fessional.wings.slardar.spring.bean.HazelcastConfigConfiguration.wingsHazelcastGlobalSerializer", "type": "java.lang.Boolean"}, + + {"name": "wings.enabled.pro.fessional.wings.slardar.spring.bean.HazelcastFacelessConfiguration", "type": "java.lang.Boolean"}, + {"name": "wings.enabled.pro.fessional.wings.slardar.spring.bean.HazelcastFacelessConfiguration.flakeIdService", "type": "java.lang.Boolean"}, + {"name": "wings.enabled.pro.fessional.wings.slardar.spring.bean.HazelcastFacelessConfiguration.hzLightIdProvider", "type": "java.lang.Boolean"}, {"name": "wings.enabled.pro.fessional.wings.slardar.spring.bean.HazelcastServiceConfiguration", "type": "java.lang.Boolean"}, - {"name": "wings.enabled.pro.fessional.wings.slardar.spring.bean.HazelcastServiceConfiguration$FlakeIdServiceBean", "type": "java.lang.Boolean"}, {"name": "wings.enabled.pro.fessional.wings.slardar.spring.bean.HazelcastServiceConfiguration$GlobalPublisherWired", "type": "java.lang.Boolean"}, {"name": "wings.enabled.pro.fessional.wings.slardar.spring.bean.HazelcastServiceConfiguration.hazelcastCacheManager", "type": "java.lang.Boolean"}, {"name": "wings.enabled.pro.fessional.wings.slardar.spring.bean.HazelcastServiceConfiguration.hazelcastGlobalLock", "type": "java.lang.Boolean"}, - {"name": "wings.enabled.pro.fessional.wings.slardar.spring.bean.HazelcastServiceConfiguration.hzLightIdProvider", "type": "java.lang.Boolean"} + + {"name": "wings.enabled.pro.fessional.wings.slardar.spring.conf.SlardarHazelcastAutoConfiguration", "type": "java.lang.Boolean"} ], "hints": [] } \ No newline at end of file diff --git a/wings/slardar-hazel-session/src/main/resources/META-INF/additional-spring-configuration-metadata.json b/wings/slardar-hazel-session/src/main/resources/META-INF/additional-spring-configuration-metadata.json index 175254ad1..7359a9b73 100644 --- a/wings/slardar-hazel-session/src/main/resources/META-INF/additional-spring-configuration-metadata.json +++ b/wings/slardar-hazel-session/src/main/resources/META-INF/additional-spring-configuration-metadata.json @@ -1,14 +1,15 @@ { "groups": [ - {"name": "wings.enabled.pro.fessional.wings.slardar.spring.conf"}, - {"name": "wings.enabled.pro.fessional.wings.slardar.spring.bean"} + {"name": "wings.enabled.pro.fessional.wings.slardar.spring.bean"}, + {"name": "wings.enabled.pro.fessional.wings.slardar.spring.conf"} ], "properties": [ - {"name": "wings.enabled.pro.fessional.wings.slardar.spring.conf.SlardarHazelSessionAutoConfiguration", "type": "java.lang.Boolean"}, - {"name": "wings.enabled.pro.fessional.wings.slardar.spring.bean.SlardarHazelSessionConfiguration", "type": "java.lang.Boolean"}, {"name": "wings.enabled.pro.fessional.wings.slardar.spring.bean.SlardarHazelSessionConfiguration.sessionRegistry", "type": "java.lang.Boolean"}, - {"name": "wings.enabled.pro.fessional.wings.slardar.spring.bean.SlardarHazelSessionConfiguration.wingsSessionHelper", "type": "java.lang.Boolean"} + {"name": "wings.enabled.pro.fessional.wings.slardar.spring.bean.SlardarHazelSessionConfiguration.wingsHazelcastSessionSerializer", "type": "java.lang.Boolean"}, + {"name": "wings.enabled.pro.fessional.wings.slardar.spring.bean.SlardarHazelSessionConfiguration.wingsSessionHelper", "type": "java.lang.Boolean"}, + + {"name": "wings.enabled.pro.fessional.wings.slardar.spring.conf.SlardarHazelSessionAutoConfiguration", "type": "java.lang.Boolean"} ], "hints": [] } \ No newline at end of file diff --git a/wings/slardar-sprint/src/main/resources/META-INF/additional-spring-configuration-metadata.json b/wings/slardar-sprint/src/main/resources/META-INF/additional-spring-configuration-metadata.json index c78e60017..64bad0b0f 100644 --- a/wings/slardar-sprint/src/main/resources/META-INF/additional-spring-configuration-metadata.json +++ b/wings/slardar-sprint/src/main/resources/META-INF/additional-spring-configuration-metadata.json @@ -1,31 +1,30 @@ { "groups": [ - {"name": "wings.enabled.pro.fessional.wings.slardar.spring.conf"}, - {"name": "wings.enabled.pro.fessional.wings.slardar.spring.bean"} + {"name": "wings.enabled.pro.fessional.wings.slardar.spring.bean"}, + {"name": "wings.enabled.pro.fessional.wings.slardar.spring.conf"} ], "properties": [ - {"name": "wings.enabled.pro.fessional.wings.slardar.spring.conf.SlardarBootAdminAutoConfiguration", "type": "java.lang.Boolean"}, + {"name": "wings.enabled.pro.fessional.wings.slardar.spring.bean.SlardarActuatorConfiguration", "type": "java.lang.Boolean"}, + {"name": "wings.enabled.pro.fessional.wings.slardar.spring.bean.SlardarActuatorConfiguration.slardarCacheManageEndpoint", "type": "java.lang.Boolean"}, {"name": "wings.enabled.pro.fessional.wings.slardar.spring.bean.SlardarBootAdminClientConfiguration", "type": "java.lang.Boolean"}, {"name": "wings.enabled.pro.fessional.wings.slardar.spring.bean.SlardarBootAdminClientConfiguration.registrationClient", "type": "java.lang.Boolean"}, {"name": "wings.enabled.pro.fessional.wings.slardar.spring.bean.SlardarBootAdminServerConfiguration", "type": "java.lang.Boolean"}, {"name": "wings.enabled.pro.fessional.wings.slardar.spring.bean.SlardarBootAdminServerConfiguration.basicAuthHttpHeadersProvider", "type": "java.lang.Boolean"}, - {"name": "wings.enabled.pro.fessional.wings.slardar.spring.bean.SlardarBootAdminServerConfiguration.bootAdminMappingOrderPostProcessor", "type": "java.lang.Boolean"}, {"name": "wings.enabled.pro.fessional.wings.slardar.spring.bean.SlardarBootAdminServerConfiguration.dingTalkNotifier", "type": "java.lang.Boolean"}, - {"name": "wings.enabled.pro.fessional.wings.slardar.spring.conf.SlardarSprintAutoConfiguration", "type": "java.lang.Boolean"}, - - {"name": "wings.enabled.pro.fessional.wings.slardar.spring.bean.SlardarActuatorConfiguration", "type": "java.lang.Boolean"}, - {"name": "wings.enabled.pro.fessional.wings.slardar.spring.bean.SlardarActuatorConfiguration.slardarCacheManageEndpoint", "type": "java.lang.Boolean"}, - {"name": "wings.enabled.pro.fessional.wings.slardar.spring.bean.SlardarSecurityConfiguration", "type": "java.lang.Boolean"}, {"name": "wings.enabled.pro.fessional.wings.slardar.spring.bean.SlardarSecurityConfiguration.httpSessionEventPublisher", "type": "java.lang.Boolean"}, {"name": "wings.enabled.pro.fessional.wings.slardar.spring.bean.SlardarSecurityConfiguration.localeContextHolderTerminalContextListener", "type": "java.lang.Boolean"}, {"name": "wings.enabled.pro.fessional.wings.slardar.spring.bean.SlardarSecurityConfiguration.passsaltEncoder", "type": "java.lang.Boolean"}, {"name": "wings.enabled.pro.fessional.wings.slardar.spring.bean.SlardarSecurityConfiguration.passwordEncoder", "type": "java.lang.Boolean"}, {"name": "wings.enabled.pro.fessional.wings.slardar.spring.bean.SlardarSecurityConfiguration.terminalContextListenerRunner", "type": "java.lang.Boolean"}, - {"name": "wings.enabled.pro.fessional.wings.slardar.spring.bean.SlardarSecurityConfiguration.wingsSecBeanInitConfigurer", "type": "java.lang.Boolean"} + {"name": "wings.enabled.pro.fessional.wings.slardar.spring.bean.SlardarSecurityConfiguration.wingsSecBeanInitConfigurer", "type": "java.lang.Boolean"}, + + {"name": "wings.enabled.pro.fessional.wings.slardar.spring.conf.SlardarBootAdminAutoConfiguration", "type": "java.lang.Boolean"}, + + {"name": "wings.enabled.pro.fessional.wings.slardar.spring.conf.SlardarSprintAutoConfiguration", "type": "java.lang.Boolean"} ], "hints": [] } \ No newline at end of file diff --git a/wings/slardar-webmvc/src/main/resources/META-INF/additional-spring-configuration-metadata.json b/wings/slardar-webmvc/src/main/resources/META-INF/additional-spring-configuration-metadata.json index e5a60c151..ac4621390 100644 --- a/wings/slardar-webmvc/src/main/resources/META-INF/additional-spring-configuration-metadata.json +++ b/wings/slardar-webmvc/src/main/resources/META-INF/additional-spring-configuration-metadata.json @@ -1,34 +1,23 @@ { "groups": [ - {"name": "wings.enabled.pro.fessional.wings.slardar.spring.conf"}, - {"name": "wings.enabled.pro.fessional.wings.slardar.spring.bean"} + {"name": "wings.enabled.pro.fessional.wings.slardar.spring.bean"}, + {"name": "wings.enabled.pro.fessional.wings.slardar.spring.conf"} ], "properties": [ - {"name": "wings.enabled.pro.fessional.wings.slardar.spring.conf.SlardarWebCnfAutoConfiguration", "type": "java.lang.Boolean"}, - - {"name": "wings.enabled.pro.fessional.wings.slardar.spring.bean.SlardarLocaleConfiguration", "type": "java.lang.Boolean"}, - {"name": "wings.enabled.pro.fessional.wings.slardar.spring.bean.SlardarLocaleConfiguration.localeResolver", "type": "java.lang.Boolean"}, - - {"name": "wings.enabled.pro.fessional.wings.slardar.spring.bean.SlardarOkhttpWebConfiguration", "type": "java.lang.Boolean"}, - {"name": "wings.enabled.pro.fessional.wings.slardar.spring.bean.SlardarOkhttpWebConfiguration.okhttpRestTemplate", "type": "java.lang.Boolean"}, - {"name": "wings.enabled.pro.fessional.wings.slardar.spring.bean.SlardarOkhttpWebConfiguration.restTemplateBuilder", "type": "java.lang.Boolean"}, - - {"name": "wings.enabled.pro.fessional.wings.slardar.spring.conf.SlardarWebFunAutoConfiguration", "type": "java.lang.Boolean"}, - - {"name": "wings.enabled.pro.fessional.wings.slardar.spring.bean.SlardarCookieConfiguration", "type": "java.lang.Boolean", "description": "wings.enabled.slardar.cookie for short."}, + {"name": "wings.enabled.pro.fessional.wings.slardar.spring.bean.SlardarCookieConfiguration", "defaultValue": false, "type": "java.lang.Boolean", "description": "wings.enabled.slardar.cookie for short."}, {"name": "wings.enabled.pro.fessional.wings.slardar.spring.bean.SlardarCookieConfiguration.wingsCookieFilter", "type": "java.lang.Boolean"}, {"name": "wings.enabled.pro.fessional.wings.slardar.spring.bean.SlardarCookieConfiguration.wingsCookieInterceptor", "type": "java.lang.Boolean"}, {"name": "wings.enabled.pro.fessional.wings.slardar.spring.bean.SlardarDebounceConfiguration", "type": "java.lang.Boolean", "description": "wings.enabled.slardar.debounce for short."}, {"name": "wings.enabled.pro.fessional.wings.slardar.spring.bean.SlardarDebounceConfiguration.debounceInterceptor", "type": "java.lang.Boolean"}, - {"name": "wings.enabled.pro.fessional.wings.slardar.spring.bean.SlardarDomainExtendConfiguration", "type": "java.lang.Boolean", "description": "wings.enabled.slardar.domainx for short."}, + {"name": "wings.enabled.pro.fessional.wings.slardar.spring.bean.SlardarDomainExtendConfiguration", "defaultValue": false, "type": "java.lang.Boolean", "description": "wings.enabled.slardar.domainx for short."}, {"name": "wings.enabled.pro.fessional.wings.slardar.spring.bean.SlardarDomainExtendConfiguration.wingsDomainExtendFilter", "type": "java.lang.Boolean"}, - {"name": "wings.enabled.pro.fessional.wings.slardar.spring.conf.SlardarDoubleKillWebConfiguration", "type": "java.lang.Boolean", "description": "wings.enabled.slardar.double-kill for short."}, - {"name": "wings.enabled.pro.fessional.wings.slardar.spring.conf.SlardarDoubleKillWebConfiguration.doubleKillExceptionResolver", "type": "java.lang.Boolean"}, + {"name": "wings.enabled.pro.fessional.wings.slardar.spring.bean.SlardarDoubleKillWebConfiguration", "type": "java.lang.Boolean", "description": "wings.enabled.slardar.double-kill for short."}, + {"name": "wings.enabled.pro.fessional.wings.slardar.spring.bean.SlardarDoubleKillWebConfiguration.doubleKillExceptionResolver", "type": "java.lang.Boolean"}, - {"name": "wings.enabled.pro.fessional.wings.slardar.spring.bean.SlardarFirstBloodConfiguration", "type": "java.lang.Boolean", "description": "wings.enabled.slardar.first-blood for short."}, + {"name": "wings.enabled.pro.fessional.wings.slardar.spring.bean.SlardarFirstBloodConfiguration", "defaultValue": false, "type": "java.lang.Boolean", "description": "wings.enabled.slardar.first-blood for short."}, {"name": "wings.enabled.pro.fessional.wings.slardar.spring.bean.SlardarFirstBloodConfiguration.firstBloodImageHandler", "type": "java.lang.Boolean", "description": "wings.enabled.slardar.first-blood-image for short."}, {"name": "wings.enabled.pro.fessional.wings.slardar.spring.bean.SlardarFirstBloodConfiguration.firstBloodInterceptor", "type": "java.lang.Boolean"}, @@ -42,6 +31,17 @@ {"name": "wings.enabled.pro.fessional.wings.slardar.spring.bean.SlardarJacksonWebConfiguration.jacksonFilterProvider", "type": "java.lang.Boolean"}, {"name": "wings.enabled.pro.fessional.wings.slardar.spring.bean.SlardarJacksonWebConfiguration.jacksonHelperRunner", "type": "java.lang.Boolean"}, + {"name": "wings.enabled.pro.fessional.wings.slardar.spring.bean.SlardarLocaleConfiguration", "type": "java.lang.Boolean"}, + {"name": "wings.enabled.pro.fessional.wings.slardar.spring.bean.SlardarLocaleConfiguration.localeResolver", "type": "java.lang.Boolean"}, + + {"name": "wings.enabled.pro.fessional.wings.slardar.spring.bean.SlardarOkhttpWebConfiguration", "type": "java.lang.Boolean"}, + {"name": "wings.enabled.pro.fessional.wings.slardar.spring.bean.SlardarOkhttpWebConfiguration.okhttpRestTemplate", "type": "java.lang.Boolean"}, + {"name": "wings.enabled.pro.fessional.wings.slardar.spring.bean.SlardarOkhttpWebConfiguration.restTemplateBuilder", "type": "java.lang.Boolean"}, + + {"name": "wings.enabled.pro.fessional.wings.slardar.spring.bean.SlardarOverloadConfiguration", "defaultValue": false, "type": "java.lang.Boolean"}, + {"name": "wings.enabled.pro.fessional.wings.slardar.spring.bean.SlardarOverloadConfiguration.overloadFallback", "type": "java.lang.Boolean"}, + {"name": "wings.enabled.pro.fessional.wings.slardar.spring.bean.SlardarOverloadConfiguration.wingsOverloadFilter", "type": "java.lang.Boolean"}, + {"name": "wings.enabled.pro.fessional.wings.slardar.spring.bean.SlardarPageQueryConfiguration", "type": "java.lang.Boolean", "description": "wings.enabled.slardar.pagequery for short."}, {"name": "wings.enabled.pro.fessional.wings.slardar.spring.bean.SlardarPageQueryConfiguration.pageQueryArgumentResolver", "type": "java.lang.Boolean"}, @@ -71,9 +71,10 @@ {"name": "wings.enabled.pro.fessional.wings.slardar.spring.bean.SlardarUndertowConfiguration.ut026010Customizer", "type": "java.lang.Boolean"}, {"name": "wings.enabled.pro.fessional.wings.slardar.spring.bean.SlardarWebMvcConfiguration", "type": "java.lang.Boolean"}, - {"name": "wings.enabled.pro.fessional.wings.slardar.spring.bean.SlardarWebMvcConfiguration.mvcRequestMatcherBuilder", "type": "java.lang.Boolean"}, - {"name": "wings.enabled.pro.fessional.wings.slardar.monitor.viewer.LogViewer", "type": "java.lang.Boolean", "description": "wings.slardar.monitor.view.enable for short."} + {"name": "wings.enabled.pro.fessional.wings.slardar.spring.conf.SlardarWebCnfAutoConfiguration", "type": "java.lang.Boolean"}, + + {"name": "wings.enabled.pro.fessional.wings.slardar.spring.conf.SlardarWebFunAutoConfiguration", "type": "java.lang.Boolean"} ], "hints": [] } \ No newline at end of file diff --git a/wings/slardar/src/main/java/pro/fessional/wings/slardar/spring/bean/SlardarMonitorConfiguration.java b/wings/slardar/src/main/java/pro/fessional/wings/slardar/spring/bean/SlardarMonitorConfiguration.java index 54e1aa9f3..22522ebb4 100644 --- a/wings/slardar/src/main/java/pro/fessional/wings/slardar/spring/bean/SlardarMonitorConfiguration.java +++ b/wings/slardar/src/main/java/pro/fessional/wings/slardar/spring/bean/SlardarMonitorConfiguration.java @@ -10,10 +10,10 @@ import org.springframework.boot.info.GitProperties; import org.springframework.context.EnvironmentAware; import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; import org.springframework.core.env.Environment; import org.springframework.scheduling.annotation.EnableScheduling; +import org.springframework.stereotype.Component; import org.springframework.util.unit.DataSize; import pro.fessional.wings.silencer.spring.boot.ConditionalWingsEnabled; import pro.fessional.wings.slardar.monitor.MonitorTask; @@ -44,9 +44,8 @@ public class SlardarMonitorConfiguration { // Dynamic register Bean LogMetric - @Configuration(proxyBeanMethods = false) + @Component @ConditionalWingsEnabled(abs = SlardarEnabledProp.Key$monitorLog) - @ComponentScan(basePackageClasses = MonitorTask.class) public static class LogMonitor implements BeanFactoryPostProcessor, EnvironmentAware { private SlardarMonitorProp slardarMonitorProp; diff --git a/wings/slardar/src/main/resources/META-INF/additional-spring-configuration-metadata.json b/wings/slardar/src/main/resources/META-INF/additional-spring-configuration-metadata.json index 87d69907d..cb361d1a6 100644 --- a/wings/slardar/src/main/resources/META-INF/additional-spring-configuration-metadata.json +++ b/wings/slardar/src/main/resources/META-INF/additional-spring-configuration-metadata.json @@ -1,27 +1,23 @@ { "groups": [ - {"name": "wings.enabled.pro.fessional.wings.slardar.spring.conf"}, - {"name": "wings.enabled.pro.fessional.wings.slardar.spring.bean"} + {"name": "wings.enabled.pro.fessional.wings.slardar.spring.bean"}, + {"name": "wings.enabled.pro.fessional.wings.slardar.spring.conf"} ], "properties": [ - {"name": "wings.enabled.pro.fessional.wings.slardar.spring.conf.SlardarAsyncAutoConfiguration", "type": "java.lang.Boolean"}, - {"name": "wings.enabled.pro.fessional.wings.slardar.spring.bean.SlardarAsyncConfiguration", "type": "java.lang.Boolean"}, {"name": "wings.enabled.pro.fessional.wings.slardar.spring.bean.SlardarAsyncConfiguration.applicationTaskExecutor", "type": "java.lang.Boolean"}, - {"name": "wings.enabled.pro.fessional.wings.slardar.spring.bean.SlardarAsyncConfiguration.slardarHeavyScheduler", "type": "java.lang.Boolean"}, + {"name": "wings.enabled.pro.fessional.wings.slardar.spring.bean.SlardarAsyncConfiguration.asyncHelper", "type": "java.lang.Boolean"}, + {"name": "wings.enabled.pro.fessional.wings.slardar.spring.bean.SlardarAsyncConfiguration.slardarFastScheduler", "type": "java.lang.Boolean"}, {"name": "wings.enabled.pro.fessional.wings.slardar.spring.bean.SlardarAsyncConfiguration.taskExecutor", "type": "java.lang.Boolean"}, {"name": "wings.enabled.pro.fessional.wings.slardar.spring.bean.SlardarAsyncConfiguration.taskScheduler", "type": "java.lang.Boolean"}, {"name": "wings.enabled.pro.fessional.wings.slardar.spring.bean.SlardarAsyncConfiguration.taskSchedulerHelper", "type": "java.lang.Boolean"}, - - {"name": "wings.enabled.pro.fessional.wings.slardar.spring.conf.SlardarCacheAutoConfiguration", "type": "java.lang.Boolean"}, + {"name": "wings.enabled.pro.fessional.wings.slardar.spring.bean.SlardarAsyncConfiguration.ttlTaskDecorator", "type": "java.lang.Boolean"}, {"name": "wings.enabled.pro.fessional.wings.slardar.spring.bean.SlardarCacheConfiguration", "type": "java.lang.Boolean"}, {"name": "wings.enabled.pro.fessional.wings.slardar.spring.bean.SlardarCacheConfiguration$CacheAop", "type": "java.lang.Boolean"}, {"name": "wings.enabled.pro.fessional.wings.slardar.spring.bean.SlardarCacheConfiguration$CacheMgr", "type": "java.lang.Boolean"}, {"name": "wings.enabled.pro.fessional.wings.slardar.spring.bean.SlardarCacheConfiguration.cache2kCacheManager", "type": "java.lang.Boolean"}, - {"name": "wings.enabled.pro.fessional.wings.slardar.spring.conf.SlardarAutoConfiguration", "type": "java.lang.Boolean"}, - {"name": "wings.enabled.pro.fessional.wings.slardar.spring.bean.SlardarDateTimeConfiguration", "type": "java.lang.Boolean"}, {"name": "wings.enabled.pro.fessional.wings.slardar.spring.bean.SlardarDateTimeConfiguration.localDateStringConverter", "type": "java.lang.Boolean"}, {"name": "wings.enabled.pro.fessional.wings.slardar.spring.bean.SlardarDateTimeConfiguration.localDateTimeStringConverter", "type": "java.lang.Boolean"}, @@ -53,11 +49,11 @@ {"name": "wings.enabled.pro.fessional.wings.slardar.spring.bean.SlardarJacksonConfiguration.emptyValuePropertyFilter", "type": "java.lang.Boolean"}, {"name": "wings.enabled.pro.fessional.wings.slardar.spring.bean.SlardarJacksonConfiguration.i18nResultPropertyFilter", "type": "java.lang.Boolean"}, - {"name": "wings.enabled.pro.fessional.wings.slardar.spring.bean.SlardarJacksonConfiguration", "type": "java.lang.Boolean"}, - {"name": "wings.enabled.pro.fessional.wings.slardar.spring.bean.SlardarJacksonConfiguration$LogMonitor", "type": "java.lang.Boolean", "description": "wings.enabled.slardar.monitor-log for short."}, - {"name": "wings.enabled.pro.fessional.wings.slardar.spring.bean.SlardarJacksonConfiguration.dingTalkReport", "type": "java.lang.Boolean"}, - {"name": "wings.enabled.pro.fessional.wings.slardar.spring.bean.SlardarJacksonConfiguration.jvmMonitor", "type": "java.lang.Boolean", "description": "wings.enabled.slardar.monitor-jvm for short."}, - {"name": "wings.enabled.pro.fessional.wings.slardar.spring.bean.SlardarJacksonConfiguration.monitorTask", "type": "java.lang.Boolean"}, + {"name": "wings.enabled.pro.fessional.wings.slardar.spring.bean.SlardarMonitorConfiguration", "type": "java.lang.Boolean"}, + {"name": "wings.enabled.pro.fessional.wings.slardar.spring.bean.SlardarMonitorConfiguration$LogMonitor", "type": "java.lang.Boolean", "description": "wings.enabled.slardar.monitor-log for short."}, + {"name": "wings.enabled.pro.fessional.wings.slardar.spring.bean.SlardarMonitorConfiguration.dingTalkReport", "type": "java.lang.Boolean"}, + {"name": "wings.enabled.pro.fessional.wings.slardar.spring.bean.SlardarMonitorConfiguration.jvmMonitor", "type": "java.lang.Boolean", "description": "wings.enabled.slardar.monitor-jvm for short."}, + {"name": "wings.enabled.pro.fessional.wings.slardar.spring.bean.SlardarMonitorConfiguration.monitorTask", "type": "java.lang.Boolean"}, {"name": "wings.enabled.pro.fessional.wings.slardar.spring.bean.SlardarOkhttpConfiguration", "type": "java.lang.Boolean"}, {"name": "wings.enabled.pro.fessional.wings.slardar.spring.bean.SlardarOkhttpConfiguration.okhttpClient", "type": "java.lang.Boolean"}, @@ -68,30 +64,13 @@ {"name": "wings.enabled.pro.fessional.wings.slardar.spring.bean.SlardarTweakConfiguration", "type": "java.lang.Boolean"}, {"name": "wings.enabled.pro.fessional.wings.slardar.spring.bean.SlardarTweakConfiguration.okhttpTweakLogInterceptor", "type": "java.lang.Boolean"}, - {"name": "wings.enabled.pro.fessional.wings.slardar.spring.bean.SlardarTweakConfiguration.tweakEventListener", "type": "java.lang.Boolean"} + {"name": "wings.enabled.pro.fessional.wings.slardar.spring.bean.SlardarTweakConfiguration.tweakEventListener", "type": "java.lang.Boolean"}, + + {"name": "wings.enabled.pro.fessional.wings.slardar.spring.conf.SlardarAsyncAutoConfiguration", "type": "java.lang.Boolean"}, + + {"name": "wings.enabled.pro.fessional.wings.slardar.spring.conf.SlardarAutoConfiguration", "type": "java.lang.Boolean"}, + + {"name": "wings.enabled.pro.fessional.wings.slardar.spring.conf.SlardarCacheAutoConfiguration", "type": "java.lang.Boolean"} ], - "hints": [ - { - "name": "wings.slardar.cache.primary", - "values": [ - {"value": "Memory", "description": "jvm cache, cache2k by default."}, - {"value": "Server", "description": "server/distributed cache, hazelcast by default."} - ] - }, - { - "name": "wings.slardar.cache.level.keys", - "values": [ - {"value": "program", "description": "program level caching, ttl available in app running."}, - {"value": "general", "description": "general level 24 hours."}, - {"value": "service", "description": "service level 1 hour."}, - {"value": "session", "description": "session, 10 minutes."} - ] - }, - { - "name": "wings.slardar.cache.level.values", - "providers": [ - {"name": "handle-as", "parameters": {"target": "pro.fessional.wings.slardar.spring.prop.SlardarCacheProp$Conf"}} - ] - } - ] -} + "hints": [] +} \ No newline at end of file diff --git a/wings/warlock-bond/src/main/resources/META-INF/additional-spring-configuration-metadata.json b/wings/warlock-bond/src/main/resources/META-INF/additional-spring-configuration-metadata.json index 66ec30098..829ff509d 100644 --- a/wings/warlock-bond/src/main/resources/META-INF/additional-spring-configuration-metadata.json +++ b/wings/warlock-bond/src/main/resources/META-INF/additional-spring-configuration-metadata.json @@ -1,13 +1,13 @@ { "groups": [ - {"name": "wings.enabled.pro.fessional.wings.warlock.spring.conf"}, - {"name": "wings.enabled.pro.fessional.wings.warlock.spring.bean"} + {"name": "wings.enabled.pro.fessional.wings.warlock.controller.admin"}, + {"name": "wings.enabled.pro.fessional.wings.warlock.spring.bean"}, + {"name": "wings.enabled.pro.fessional.wings.warlock.spring.conf"} ], "properties": [ - {"name": "wings.enabled.pro.fessional.wings.warlock.spring.conf.WarlockBondAutoConfiguration", "type": "java.lang.Boolean"}, + {"name": "wings.enabled.pro.fessional.wings.warlock.controller.admin.AdminAuthnController", "type": "java.lang.Boolean", "description": "wings.enabled.warlock.mvc-auth for short."}, {"name": "wings.enabled.pro.fessional.wings.warlock.spring.bean.WarlockBondBeanConfiguration", "type": "java.lang.Boolean"}, - {"name": "wings.enabled.pro.fessional.wings.warlock.spring.bean.WarlockBondBeanConfiguration.autoRegisterCacheConst", "type": "java.lang.Boolean"}, {"name": "wings.enabled.pro.fessional.wings.warlock.spring.bean.WarlockBondBeanConfiguration.defaultDaoAuthnCombo", "type": "java.lang.Boolean"}, {"name": "wings.enabled.pro.fessional.wings.warlock.spring.bean.WarlockBondBeanConfiguration.warlockDangerService", "type": "java.lang.Boolean"}, {"name": "wings.enabled.pro.fessional.wings.warlock.spring.bean.WarlockBondBeanConfiguration.warlockGrantService", "type": "java.lang.Boolean"}, @@ -19,7 +19,7 @@ {"name": "wings.enabled.pro.fessional.wings.warlock.spring.bean.WarlockBondBeanConfiguration.warlockUserBasisService", "type": "java.lang.Boolean"}, {"name": "wings.enabled.pro.fessional.wings.warlock.spring.bean.WarlockBondBeanConfiguration.warlockUserLoginService", "type": "java.lang.Boolean"}, - {"name": "pro.fessional.wings.warlock.controller.admin.AdminAuthnController", "type": "java.lang.Boolean", "description": "wings.enabled.warlock.mvc-auth for short."} + {"name": "wings.enabled.pro.fessional.wings.warlock.spring.conf.WarlockBondAutoConfiguration", "type": "java.lang.Boolean"} ], "hints": [] } \ No newline at end of file diff --git a/wings/slardar-webmvc/src/main/java/pro/fessional/wings/slardar/monitor/viewer/WebLogViewer.java b/wings/warlock-shadow/src/main/java/pro/fessional/wings/warlock/controller/api/WebLogViewer.java similarity index 88% rename from wings/slardar-webmvc/src/main/java/pro/fessional/wings/slardar/monitor/viewer/WebLogViewer.java rename to wings/warlock-shadow/src/main/java/pro/fessional/wings/warlock/controller/api/WebLogViewer.java index 12ed55802..89e90d2d9 100644 --- a/wings/slardar-webmvc/src/main/java/pro/fessional/wings/slardar/monitor/viewer/WebLogViewer.java +++ b/wings/warlock-shadow/src/main/java/pro/fessional/wings/warlock/controller/api/WebLogViewer.java @@ -1,4 +1,4 @@ -package pro.fessional.wings.slardar.monitor.viewer; +package pro.fessional.wings.warlock.controller.api; import io.swagger.v3.oas.annotations.Operation; import jakarta.servlet.http.HttpServletResponse; @@ -8,6 +8,8 @@ import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; import pro.fessional.wings.silencer.spring.boot.ConditionalWingsEnabled; +import pro.fessional.wings.slardar.monitor.viewer.LogConf; +import pro.fessional.wings.slardar.monitor.viewer.LogViewer; import pro.fessional.wings.slardar.spring.prop.SlardarMonitorProp; import java.io.IOException; diff --git a/wings/warlock-shadow/src/main/resources/META-INF/additional-spring-configuration-metadata.json b/wings/warlock-shadow/src/main/resources/META-INF/additional-spring-configuration-metadata.json index 3c0d4bf18..6424dc126 100644 --- a/wings/warlock-shadow/src/main/resources/META-INF/additional-spring-configuration-metadata.json +++ b/wings/warlock-shadow/src/main/resources/META-INF/additional-spring-configuration-metadata.json @@ -1,17 +1,32 @@ { "groups": [ - {"name": "wings.enabled.pro.fessional.wings.warlock.spring.conf"}, - {"name": "wings.enabled.pro.fessional.wings.warlock.spring.bean"} + {"name": "wings.enabled.pro.fessional.wings.warlock.controller.admin"}, + {"name": "wings.enabled.pro.fessional.wings.warlock.controller.api"}, + {"name": "wings.enabled.pro.fessional.wings.warlock.controller.auth"}, + {"name": "wings.enabled.pro.fessional.wings.warlock.controller.mock"}, + {"name": "wings.enabled.pro.fessional.wings.warlock.controller.test"}, + {"name": "wings.enabled.pro.fessional.wings.warlock.controller.user"}, + {"name": "wings.enabled.pro.fessional.wings.warlock.spring.bean"}, + {"name": "wings.enabled.pro.fessional.wings.warlock.spring.conf"} ], "properties": [ - {"name": "wings.enabled.pro.fessional.wings.warlock.spring.conf.WarlockShadowAutoConfiguration", "type": "java.lang.Boolean"}, + {"name": "wings.enabled.pro.fessional.wings.warlock.controller.admin.AdminTweakController", "defaultValue": false, "type": "java.lang.Boolean", "description": "wings.enabled.warlock.mvc-tweak for short."}, + + {"name": "wings.enabled.pro.fessional.wings.warlock.controller.api.WebLogViewer", "type": "java.lang.Boolean", "description": "wings.slardar.monitor.view.enable for short."}, + + {"name": "wings.enabled.pro.fessional.wings.warlock.controller.auth.LoginPageController", "type": "java.lang.Boolean", "description": "wings.enabled.warlock.mvc-login for short."}, + {"name": "wings.enabled.pro.fessional.wings.warlock.controller.auth.LoginProcController", "type": "java.lang.Boolean", "description": "wings.enabled.warlock.mvc-proc for short."}, + {"name": "wings.enabled.pro.fessional.wings.warlock.controller.auth.SimpleOauthController", "type": "java.lang.Boolean", "description": "wings.enabled.warlock.mvc-oauth for short."}, + + {"name": "wings.enabled.pro.fessional.wings.warlock.controller.mock.MockSampleController", "type": "java.lang.Boolean", "description": "wings.enabled.warlock.mvc-mock for short."}, + + {"name": "wings.enabled.pro.fessional.wings.warlock.controller.test.TestEnvsController", "type": "java.lang.Boolean", "description": "wings.enabled.warlock.mvc-test for short."}, + + {"name": "wings.enabled.pro.fessional.wings.warlock.controller.user.AuthedUserController", "type": "java.lang.Boolean", "description": "wings.enabled.warlock.mvc-user for short."}, {"name": "wings.enabled.pro.fessional.wings.warlock.spring.bean.WarlockExceptionConfiguration", "type": "java.lang.Boolean"}, {"name": "wings.enabled.pro.fessional.wings.warlock.spring.bean.WarlockExceptionConfiguration.defaultExceptionResolver", "type": "java.lang.Boolean"}, - {"name": "wings.enabled.pro.fessional.wings.warlock.spring.bean.WarlockJournalConfiguration", "type": "java.lang.Boolean"}, - {"name": "wings.enabled.pro.fessional.wings.warlock.spring.bean.WarlockJournalConfiguration.terminalJournalService", "type": "java.lang.Boolean"}, - {"name": "wings.enabled.pro.fessional.wings.warlock.spring.bean.WarlockJustAuthConfiguration", "type": "java.lang.Boolean"}, {"name": "wings.enabled.pro.fessional.wings.warlock.spring.bean.WarlockJustAuthConfiguration.authStateCache", "type": "java.lang.Boolean"}, {"name": "wings.enabled.pro.fessional.wings.warlock.spring.bean.WarlockJustAuthConfiguration.justAuthRequestBuilder", "type": "java.lang.Boolean"}, @@ -26,17 +41,12 @@ {"name": "wings.enabled.pro.fessional.wings.warlock.spring.bean.WarlockOtherBeanConfiguration$MvcRestScan", "type": "java.lang.Boolean"}, {"name": "wings.enabled.pro.fessional.wings.warlock.spring.bean.WarlockOtherBeanConfiguration.righterSecretProvider", "type": "java.lang.Boolean"}, - {"name": "wings.enabled.pro.fessional.wings.warlock.spring.bean.WarlockWatching2Configuration", "type": "java.lang.Boolean"}, - {"name": "wings.enabled.pro.fessional.wings.warlock.spring.bean.WarlockWatching2Configuration.slowResponseInterceptor", "type": "java.lang.Boolean"}, - - {"name": "wings.enabled.pro.fessional.wings.warlock.spring.conf.WarlockSecurityAutoConfiguration", "type": "java.lang.Boolean"}, - {"name": "wings.enabled.pro.fessional.wings.warlock.spring.bean.WarlockSecurityBeanConfiguration", "type": "java.lang.Boolean"}, {"name": "wings.enabled.pro.fessional.wings.warlock.spring.bean.WarlockSecurityBeanConfiguration.accessDeniedHandler", "type": "java.lang.Boolean"}, {"name": "wings.enabled.pro.fessional.wings.warlock.spring.bean.WarlockSecurityBeanConfiguration.authAppPermChecker", "type": "java.lang.Boolean"}, - {"name": "wings.enabled.pro.fessional.wings.warlock.spring.bean.WarlockSecurityBeanConfiguration.authenticationEventPublisher", "type": "java.lang.Boolean"}, {"name": "wings.enabled.pro.fessional.wings.warlock.spring.bean.WarlockSecurityBeanConfiguration.authStateBuilder", "type": "java.lang.Boolean"}, {"name": "wings.enabled.pro.fessional.wings.warlock.spring.bean.WarlockSecurityBeanConfiguration.authZonePermChecker", "type": "java.lang.Boolean"}, + {"name": "wings.enabled.pro.fessional.wings.warlock.spring.bean.WarlockSecurityBeanConfiguration.authenticationEventPublisher", "type": "java.lang.Boolean"}, {"name": "wings.enabled.pro.fessional.wings.warlock.spring.bean.WarlockSecurityBeanConfiguration.comboWarlockAuthnService", "type": "java.lang.Boolean"}, {"name": "wings.enabled.pro.fessional.wings.warlock.spring.bean.WarlockSecurityBeanConfiguration.comboWarlockAuthzService", "type": "java.lang.Boolean"}, {"name": "wings.enabled.pro.fessional.wings.warlock.spring.bean.WarlockSecurityBeanConfiguration.comboWingsAuthCheckService", "type": "java.lang.Boolean"}, @@ -64,6 +74,7 @@ {"name": "wings.enabled.pro.fessional.wings.warlock.spring.bean.WarlockSecurityBeanConfiguration.wingsUserDetailsService", "type": "java.lang.Boolean"}, {"name": "wings.enabled.pro.fessional.wings.warlock.spring.bean.WarlockSecurityConfConfiguration", "type": "java.lang.Boolean"}, + {"name": "wings.enabled.pro.fessional.wings.warlock.spring.bean.WarlockSecurityConfConfiguration.securityCheckUrlRunner", "type": "java.lang.Boolean", "description": "wings.enabled.warlock.sec-check-url for short."}, {"name": "wings.enabled.pro.fessional.wings.warlock.spring.bean.WarlockSecurityConfConfiguration.securityFilterChain", "type": "java.lang.Boolean", "description": "wings.enabled.warlock.sec-http-chain for short."}, {"name": "wings.enabled.pro.fessional.wings.warlock.spring.bean.WarlockSecurityConfConfiguration.warlockSecurityAuthHttpConfigure", "type": "java.lang.Boolean", "description": "wings.enabled.warlock.sec-http-auth for short."}, {"name": "wings.enabled.pro.fessional.wings.warlock.spring.bean.WarlockSecurityConfConfiguration.warlockSecurityAutoHttpConfigure", "type": "java.lang.Boolean", "description": "wings.enabled.warlock.sec-http-auto for short."}, @@ -71,7 +82,7 @@ {"name": "wings.enabled.pro.fessional.wings.warlock.spring.bean.WarlockSecurityConfConfiguration.warlockSecurityHttpBaseConfigure", "type": "java.lang.Boolean", "description": "wings.enabled.warlock.sec-http-base for short."}, {"name": "wings.enabled.pro.fessional.wings.warlock.spring.bean.WarlockSecurityConfConfiguration.warlockWebCustomizer", "type": "java.lang.Boolean", "description": "wings.enabled.warlock.sec-web-auto for short."}, - {"name": "wings.enabled.pro.fessional.wings.warlock.spring.bean.WarlockSecurityDummyConfiguration", "type": "java.lang.Boolean", "description": "wings.enabled.warlock.dummy-service for short."}, + {"name": "wings.enabled.pro.fessional.wings.warlock.spring.bean.WarlockSecurityDummyConfiguration", "defaultValue": false, "type": "java.lang.Boolean", "description": "wings.enabled.warlock.dummy-service for short."}, {"name": "wings.enabled.pro.fessional.wings.warlock.spring.bean.WarlockSecurityDummyConfiguration.warlockGrantService", "type": "java.lang.Boolean"}, {"name": "wings.enabled.pro.fessional.wings.warlock.spring.bean.WarlockSecurityDummyConfiguration.warlockPermService", "type": "java.lang.Boolean"}, {"name": "wings.enabled.pro.fessional.wings.warlock.spring.bean.WarlockSecurityDummyConfiguration.warlockRoleService", "type": "java.lang.Boolean"}, @@ -79,13 +90,12 @@ {"name": "wings.enabled.pro.fessional.wings.warlock.spring.bean.WarlockSecurityDummyConfiguration.warlockUserBasisService", "type": "java.lang.Boolean"}, {"name": "wings.enabled.pro.fessional.wings.warlock.spring.bean.WarlockSecurityDummyConfiguration.warlockUserLoginService", "type": "java.lang.Boolean"}, - {"name": "wings.enabled.pro.fessional.wings.warlock.controller.admin.AdminTweakController", "type": "java.lang.Boolean", "description": "wings.enabled.warlock.mvc-tweak for short."}, - {"name": "wings.enabled.pro.fessional.wings.warlock.controller.auth.LoginPageController", "type": "java.lang.Boolean", "description": "wings.enabled.warlock.mvc-login for short."}, - {"name": "wings.enabled.pro.fessional.wings.warlock.controller.auth.LoginProcController", "type": "java.lang.Boolean", "description": "wings.enabled.warlock.mvc-proc for short."}, - {"name": "wings.enabled.pro.fessional.wings.warlock.controller.auth.SimpleOauthController", "type": "java.lang.Boolean", "description": "wings.enabled.warlock.mvc-oauth for short."}, - {"name": "wings.enabled.pro.fessional.wings.warlock.controller.mock.MockSampleController", "type": "java.lang.Boolean", "description": "wings.enabled.warlock.mvc-mock for short."}, - {"name": "wings.enabled.pro.fessional.wings.warlock.controller.test.TestEnvsController", "type": "java.lang.Boolean", "description": "wings.enabled.warlock.mvc-test for short."}, - {"name": "wings.enabled.pro.fessional.wings.warlock.controller.user.AuthedUserController", "type": "java.lang.Boolean", "description": "wings.enabled.warlock.mvc-user for short."} + {"name": "wings.enabled.pro.fessional.wings.warlock.spring.bean.WarlockWatching2Configuration", "type": "java.lang.Boolean"}, + {"name": "wings.enabled.pro.fessional.wings.warlock.spring.bean.WarlockWatching2Configuration.slowResponseInterceptor", "type": "java.lang.Boolean"}, + + {"name": "wings.enabled.pro.fessional.wings.warlock.spring.conf.WarlockSecurityAutoConfiguration", "type": "java.lang.Boolean"}, + + {"name": "wings.enabled.pro.fessional.wings.warlock.spring.conf.WarlockShadowAutoConfiguration", "type": "java.lang.Boolean"} ], "hints": [] } \ No newline at end of file diff --git a/wings/warlock/src/main/java/pro/fessional/wings/warlock/spring/conf/WarlockAwesomeAutoConfiguration.java b/wings/warlock/src/main/java/pro/fessional/wings/warlock/spring/conf/WarlockAwesomeAutoConfiguration.java deleted file mode 100644 index c6bde33d5..000000000 --- a/wings/warlock/src/main/java/pro/fessional/wings/warlock/spring/conf/WarlockAwesomeAutoConfiguration.java +++ /dev/null @@ -1,17 +0,0 @@ -package pro.fessional.wings.warlock.spring.conf; - -import org.springframework.boot.autoconfigure.AutoConfiguration; -import org.springframework.context.annotation.Import; -import pro.fessional.wings.silencer.spring.boot.ConditionalWingsEnabled; -import pro.fessional.wings.warlock.spring.bean.WarlockAwesomeConfiguration; - - -/** - * @author trydofor - * @since 2019-12-01 - */ -@AutoConfiguration -@ConditionalWingsEnabled -@Import(WarlockAwesomeConfiguration.class) -public class WarlockAwesomeAutoConfiguration { -} diff --git a/wings/warlock/src/main/resources/META-INF/additional-spring-configuration-metadata.json b/wings/warlock/src/main/resources/META-INF/additional-spring-configuration-metadata.json index 868c98f68..2915ac9b5 100644 --- a/wings/warlock/src/main/resources/META-INF/additional-spring-configuration-metadata.json +++ b/wings/warlock/src/main/resources/META-INF/additional-spring-configuration-metadata.json @@ -1,10 +1,20 @@ { "groups": [ - {"name": "wings.enabled.pro.fessional.wings.warlock.spring.conf"}, - {"name": "wings.enabled.pro.fessional.wings.warlock.spring.bean"} + {"name": "wings.enabled.pro.fessional.wings.warlock.database.autogen.tables.daos"}, + {"name": "wings.enabled.pro.fessional.wings.warlock.spring.bean"}, + {"name": "wings.enabled.pro.fessional.wings.warlock.spring.conf"} ], "properties": [ - {"name": "wings.enabled.pro.fessional.wings.warlock.spring.conf.WarlockAutoConfiguration", "type": "java.lang.Boolean"}, + {"name": "wings.enabled.pro.fessional.wings.warlock.database.autogen.tables.daos.SysConstantEnumDao", "type": "java.lang.Boolean"}, + {"name": "wings.enabled.pro.fessional.wings.warlock.database.autogen.tables.daos.SysStandardI18nDao", "type": "java.lang.Boolean"}, + {"name": "wings.enabled.pro.fessional.wings.warlock.database.autogen.tables.daos.WinConfRuntimeDao", "type": "java.lang.Boolean"}, + {"name": "wings.enabled.pro.fessional.wings.warlock.database.autogen.tables.daos.WinPermEntryDao", "type": "java.lang.Boolean"}, + {"name": "wings.enabled.pro.fessional.wings.warlock.database.autogen.tables.daos.WinRoleEntryDao", "type": "java.lang.Boolean"}, + {"name": "wings.enabled.pro.fessional.wings.warlock.database.autogen.tables.daos.WinRoleGrantDao", "type": "java.lang.Boolean"}, + {"name": "wings.enabled.pro.fessional.wings.warlock.database.autogen.tables.daos.WinUserAuthnDao", "type": "java.lang.Boolean"}, + {"name": "wings.enabled.pro.fessional.wings.warlock.database.autogen.tables.daos.WinUserBasisDao", "type": "java.lang.Boolean"}, + {"name": "wings.enabled.pro.fessional.wings.warlock.database.autogen.tables.daos.WinUserGrantDao", "type": "java.lang.Boolean"}, + {"name": "wings.enabled.pro.fessional.wings.warlock.database.autogen.tables.daos.WinUserLoginDao", "type": "java.lang.Boolean"}, {"name": "wings.enabled.pro.fessional.wings.warlock.spring.bean.WarlockAutoRunConfiguration", "type": "java.lang.Boolean"}, {"name": "wings.enabled.pro.fessional.wings.warlock.spring.bean.WarlockAutoRunConfiguration.databaseCheckerRunner", "type": "java.lang.Boolean"}, @@ -15,6 +25,9 @@ {"name": "wings.enabled.pro.fessional.wings.warlock.spring.bean.WarlockAwesomeConfiguration.registerRuntimeModeRunner", "type": "java.lang.Boolean"}, {"name": "wings.enabled.pro.fessional.wings.warlock.spring.bean.WarlockAwesomeConfiguration.runtimeConfService", "type": "java.lang.Boolean"}, + {"name": "wings.enabled.pro.fessional.wings.warlock.spring.bean.WarlockJournalConfiguration", "type": "java.lang.Boolean"}, + {"name": "wings.enabled.pro.fessional.wings.warlock.spring.bean.WarlockJournalConfiguration.terminalJournalService", "type": "java.lang.Boolean"}, + {"name": "wings.enabled.pro.fessional.wings.warlock.spring.bean.WarlockLockBeanConfiguration", "type": "java.lang.Boolean"}, {"name": "wings.enabled.pro.fessional.wings.warlock.spring.bean.WarlockLockBeanConfiguration.databaseGlobalLock", "type": "java.lang.Boolean"}, {"name": "wings.enabled.pro.fessional.wings.warlock.spring.bean.WarlockLockBeanConfiguration.jvmStaticGlobalLock", "type": "java.lang.Boolean"}, @@ -23,9 +36,11 @@ {"name": "wings.enabled.pro.fessional.wings.warlock.spring.bean.WarlockTableChangeConfiguration.tableChangePublisher", "type": "java.lang.Boolean"}, {"name": "wings.enabled.pro.fessional.wings.warlock.spring.bean.WarlockTableChangeConfiguration.wingsTableCudHandler", "type": "java.lang.Boolean"}, - {"name": "wings.enabled.pro.fessional.wings.warlock.spring.bean.WarlockWatchingConfiguration", "type": "java.lang.Boolean", "description": "wings.enabled.warlock.watching for short."}, + {"name": "wings.enabled.pro.fessional.wings.warlock.spring.bean.WarlockWatchingConfiguration", "defaultValue": false, "type": "java.lang.Boolean", "description": "wings.enabled.warlock.watching for short."}, {"name": "wings.enabled.pro.fessional.wings.warlock.spring.bean.WarlockWatchingConfiguration.slowSqlJooqListener", "type": "java.lang.Boolean"}, - {"name": "wings.enabled.pro.fessional.wings.warlock.spring.bean.WarlockWatchingConfiguration.watchingAround", "type": "java.lang.Boolean"} + {"name": "wings.enabled.pro.fessional.wings.warlock.spring.bean.WarlockWatchingConfiguration.watchingAround", "type": "java.lang.Boolean"}, + + {"name": "wings.enabled.pro.fessional.wings.warlock.spring.conf.WarlockAutoConfiguration", "type": "java.lang.Boolean"} ], "hints": [] } \ No newline at end of file From 2b63203c7e3603f4ef3c450956988db3975d4c5e Mon Sep 17 00:00:00 2001 From: trydofor Date: Fri, 2 Aug 2024 09:19:59 +0800 Subject: [PATCH 35/51] =?UTF-8?q?=F0=9F=A7=91=E2=80=8D=F0=9F=92=BB=20tiny/?= =?UTF-8?q?task,grow=20optimization=20#282?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/release.yml | 2 +- .../tiny/grow/track/TinyTrackService.java | 11 ++++- .../tiny/grow/track/impl/TinyTrackAround.java | 9 ++-- .../track/impl/TinyTrackCollectorDaoImpl.java | 2 +- .../track/impl/TinyTrackPreparerPropImpl.java | 34 +++++++++++++++ .../track/impl/TinyTrackPreparerTermImpl.java | 43 +++++++++++++++++++ .../grow/track/impl/TinyTrackServiceImpl.java | 26 ++++------- ...itional-spring-configuration-metadata.json | 10 ++++- .../service/impl/TestTrackCollectorImpl.java | 3 +- .../tiny/grow/track/TinyTrackServiceTest.java | 2 +- .../service/impl/TinyMailServiceImpl.java | 4 +- .../tiny/task/service/TinyTaskService.java | 2 + .../service/impl/TinyTaskExecServiceImpl.java | 37 ++++++++++------ .../task/spring/prop/TinyTaskExecProp.java | 8 ++++ .../wings-tinytask-exec-79.properties | 2 + .../wings/silencer/support/MetaJsonMaker.java | 19 +++++--- 16 files changed, 160 insertions(+), 54 deletions(-) create mode 100644 radiant/tiny-grow/src/main/java/pro/fessional/wings/tiny/grow/track/impl/TinyTrackPreparerPropImpl.java create mode 100644 radiant/tiny-grow/src/main/java/pro/fessional/wings/tiny/grow/track/impl/TinyTrackPreparerTermImpl.java diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 49a4d99bc..f6b335264 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -148,7 +148,7 @@ jobs: EOF - name: Qodana Scan - uses: JetBrains/qodana-action@v2023.3 + uses: JetBrains/qodana-action@v2024.1 if: steps.settings.outputs.QODANA_SCAN == 'true' env: QODANA_TOKEN: ${{ secrets.QODANA_TOKEN }} diff --git a/radiant/tiny-grow/src/main/java/pro/fessional/wings/tiny/grow/track/TinyTrackService.java b/radiant/tiny-grow/src/main/java/pro/fessional/wings/tiny/grow/track/TinyTrackService.java index 098e96b3f..881a6fd7d 100644 --- a/radiant/tiny-grow/src/main/java/pro/fessional/wings/tiny/grow/track/TinyTrackService.java +++ b/radiant/tiny-grow/src/main/java/pro/fessional/wings/tiny/grow/track/TinyTrackService.java @@ -67,9 +67,16 @@ default TinyTracking begin(@NotNull Enum key) { } /** - * collect tracking to different impl, e.g. Dao to database + * sync prepare tracking prop, e.g. env, app + */ + interface Preparer { + void prepare(@NotNull TinyTracking tracking); + } + + /** + * aysnc collect tracking to different impl, e.g. Dao to database */ interface Collector { - void collect(TinyTracking tracking); + void collect(@NotNull TinyTracking tracking); } } diff --git a/radiant/tiny-grow/src/main/java/pro/fessional/wings/tiny/grow/track/impl/TinyTrackAround.java b/radiant/tiny-grow/src/main/java/pro/fessional/wings/tiny/grow/track/impl/TinyTrackAround.java index 475548a8a..04f5dbf36 100644 --- a/radiant/tiny-grow/src/main/java/pro/fessional/wings/tiny/grow/track/impl/TinyTrackAround.java +++ b/radiant/tiny-grow/src/main/java/pro/fessional/wings/tiny/grow/track/impl/TinyTrackAround.java @@ -23,6 +23,7 @@ import pro.fessional.wings.tiny.grow.track.TinyTracking; import java.lang.reflect.Method; +import java.util.Collections; import java.util.HashSet; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; @@ -124,12 +125,8 @@ protected TinyTracking tryTrack(@NotNull Method method, @NotNull TinyTracker ann protected Set omitRule(@NotNull Method method, @NotNull TinyTracker anno) { return omitRules.computeIfAbsent(method, k -> { Set set = new HashSet<>(); - for (Class clz : anno.omitClass()) { - set.add(clz); - } - for (String str : anno.omitEqual()) { - set.add(str); - } + Collections.addAll(set, anno.omitClass()); + Collections.addAll(set, anno.omitEqual()); for (String ptn : anno.omitRegex()) { set.add(Pattern.compile(ptn)); } diff --git a/radiant/tiny-grow/src/main/java/pro/fessional/wings/tiny/grow/track/impl/TinyTrackCollectorDaoImpl.java b/radiant/tiny-grow/src/main/java/pro/fessional/wings/tiny/grow/track/impl/TinyTrackCollectorDaoImpl.java index 1636da195..330a698ae 100644 --- a/radiant/tiny-grow/src/main/java/pro/fessional/wings/tiny/grow/track/impl/TinyTrackCollectorDaoImpl.java +++ b/radiant/tiny-grow/src/main/java/pro/fessional/wings/tiny/grow/track/impl/TinyTrackCollectorDaoImpl.java @@ -32,7 +32,7 @@ public class TinyTrackCollectorDaoImpl implements TinyTrackService.Collector { @Override @Transactional - public void collect(TinyTracking tracking) { + public void collect(@NotNull TinyTracking tracking) { WinGrowTrack pojo = new WinGrowTrack(); pojo.setId(lightIdService.getId(winGrowTrackDao.getTable())); diff --git a/radiant/tiny-grow/src/main/java/pro/fessional/wings/tiny/grow/track/impl/TinyTrackPreparerPropImpl.java b/radiant/tiny-grow/src/main/java/pro/fessional/wings/tiny/grow/track/impl/TinyTrackPreparerPropImpl.java new file mode 100644 index 000000000..33aecc18f --- /dev/null +++ b/radiant/tiny-grow/src/main/java/pro/fessional/wings/tiny/grow/track/impl/TinyTrackPreparerPropImpl.java @@ -0,0 +1,34 @@ +package pro.fessional.wings.tiny.grow.track.impl; + +import lombok.Setter; +import org.jetbrains.annotations.NotNull; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import pro.fessional.wings.silencer.modulate.RuntimeMode; +import pro.fessional.wings.silencer.spring.boot.ConditionalWingsEnabled; +import pro.fessional.wings.silencer.spring.help.ApplicationContextHelper; +import pro.fessional.wings.tiny.grow.spring.prop.TinyTrackOmitProp; +import pro.fessional.wings.tiny.grow.track.TinyTrackService; +import pro.fessional.wings.tiny.grow.track.TinyTracking; + +/** + * @author trydofor + * @since 2024-08-01 + */ +@Service +@ConditionalWingsEnabled +public class TinyTrackPreparerPropImpl implements TinyTrackService.Preparer { + + @Setter(onMethod_ = { @Autowired }) + protected TinyTrackOmitProp tinyTrackOmitProp; + + @Override + public void prepare(@NotNull TinyTracking tracking) { + tracking.setApp(ApplicationContextHelper.getApplicationName()); + tracking.addEnv("run", RuntimeMode.getRunMode().name()); + + tracking.addOmit(tinyTrackOmitProp.getClazz().values()); + tracking.addOmit(tinyTrackOmitProp.getEqual().values()); + tracking.addOmit(tinyTrackOmitProp.getRegex().values()); + } +} diff --git a/radiant/tiny-grow/src/main/java/pro/fessional/wings/tiny/grow/track/impl/TinyTrackPreparerTermImpl.java b/radiant/tiny-grow/src/main/java/pro/fessional/wings/tiny/grow/track/impl/TinyTrackPreparerTermImpl.java new file mode 100644 index 000000000..f3a858ce3 --- /dev/null +++ b/radiant/tiny-grow/src/main/java/pro/fessional/wings/tiny/grow/track/impl/TinyTrackPreparerTermImpl.java @@ -0,0 +1,43 @@ +package pro.fessional.wings.tiny.grow.track.impl; + +import org.jetbrains.annotations.NotNull; +import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; +import org.springframework.stereotype.Service; +import pro.fessional.wings.silencer.spring.boot.ConditionalWingsEnabled; +import pro.fessional.wings.slardar.context.TerminalContext; +import pro.fessional.wings.tiny.grow.track.TinyTrackService; +import pro.fessional.wings.tiny.grow.track.TinyTracking; + +import static pro.fessional.wings.slardar.context.TerminalAttribute.TerminalAddr; +import static pro.fessional.wings.slardar.context.TerminalAttribute.TerminalAgent; + +/** + * @author trydofor + * @since 2024-08-01 + */ +@Service +@ConditionalWingsEnabled +@ConditionalOnClass(TerminalContext.class) +public class TinyTrackPreparerTermImpl implements TinyTrackService.Preparer { + + @Override + public void prepare(@NotNull TinyTracking tracking) { + final TerminalContext.Context ctx = TerminalContext.get(false); + if (ctx.isNull()) return; + + tracking.addEnv("locale", ctx.getLocale().toLanguageTag()); + tracking.addEnv("zoneid", ctx.getZoneId().getId()); + long id = ctx.getUserId(); + tracking.addEnv("userId", id); + + if (id > 0) { + tracking.addEnv("authType", ctx.getAuthType().name()); + tracking.addEnv("username", ctx.getUsername()); + } + + String adr = ctx.getTerminal(TerminalAddr); + if (adr != null) tracking.addEnv("addr", id); + String agt = ctx.getTerminal(TerminalAgent); + if (agt != null) tracking.addEnv("agent", agt); + } +} diff --git a/radiant/tiny-grow/src/main/java/pro/fessional/wings/tiny/grow/track/impl/TinyTrackServiceImpl.java b/radiant/tiny-grow/src/main/java/pro/fessional/wings/tiny/grow/track/impl/TinyTrackServiceImpl.java index 1af4330a0..84224713c 100644 --- a/radiant/tiny-grow/src/main/java/pro/fessional/wings/tiny/grow/track/impl/TinyTrackServiceImpl.java +++ b/radiant/tiny-grow/src/main/java/pro/fessional/wings/tiny/grow/track/impl/TinyTrackServiceImpl.java @@ -9,11 +9,7 @@ import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.stereotype.Service; import pro.fessional.mirana.time.ThreadNow; -import pro.fessional.wings.silencer.modulate.RuntimeMode; import pro.fessional.wings.silencer.spring.boot.ConditionalWingsEnabled; -import pro.fessional.wings.silencer.spring.help.ApplicationContextHelper; -import pro.fessional.wings.slardar.context.TerminalContext; -import pro.fessional.wings.tiny.grow.spring.prop.TinyTrackOmitProp; import pro.fessional.wings.tiny.grow.track.TinyTrackService; import pro.fessional.wings.tiny.grow.track.TinyTracking; @@ -40,7 +36,7 @@ public class TinyTrackServiceImpl implements TinyTrackService, InitializingBean protected List trackCollector; @Setter(onMethod_ = { @Autowired }) - protected TinyTrackOmitProp tinyTrackOmitProp; + protected List trackPreparer; @Override public FutureTask async(Runnable run) { @@ -54,21 +50,15 @@ public FutureTask async(Runnable run) { public TinyTracking begin(@NotNull String key, @NotNull String ref) { final TinyTracking tracking = new TinyTracking(ThreadNow.millis(), key, ref); - tracking.setApp(ApplicationContextHelper.getApplicationName()); - tracking.addEnv("run", RuntimeMode.getRunMode().name()); - - final TerminalContext.Context ctx = TerminalContext.get(false); - if (!ctx.isNull()) { - tracking.addEnv("userId", ctx.getUserId()); - tracking.addEnv("locale", ctx.getLocale().toLanguageTag()); - tracking.addEnv("zoneid", ctx.getZoneId().getId()); - tracking.addEnv("authType", ctx.getAuthType().name()); - tracking.addEnv("username", ctx.getUsername()); + for (Preparer pr : trackPreparer) { + try { + pr.prepare(tracking); + } + catch (Exception e) { + log.error("tiny-track skip failed preparer=" + pr.getClass(), e); + } } - tracking.addOmit(tinyTrackOmitProp.getClazz().values()); - tracking.addOmit(tinyTrackOmitProp.getEqual().values()); - tracking.addOmit(tinyTrackOmitProp.getRegex().values()); return tracking; } diff --git a/radiant/tiny-grow/src/main/resources/META-INF/additional-spring-configuration-metadata.json b/radiant/tiny-grow/src/main/resources/META-INF/additional-spring-configuration-metadata.json index 45ff386ec..a93730dd6 100644 --- a/radiant/tiny-grow/src/main/resources/META-INF/additional-spring-configuration-metadata.json +++ b/radiant/tiny-grow/src/main/resources/META-INF/additional-spring-configuration-metadata.json @@ -1,16 +1,22 @@ { "groups": [ + {"name": "wings.enabled.pro.fessional.wings.tiny.grow.database.autogen.tables.daos"}, + {"name": "wings.enabled.pro.fessional.wings.tiny.grow.spring.bean"}, {"name": "wings.enabled.pro.fessional.wings.tiny.grow.spring.conf"}, - {"name": "wings.enabled.pro.fessional.wings.tiny.grow.spring.bean"} + {"name": "wings.enabled.pro.fessional.wings.tiny.grow.track.impl"} ], "properties": [ - {"name": "wings.enabled.pro.fessional.wings.tiny.grow.spring.conf.TinyGrowAutoConfiguration", "type": "java.lang.Boolean"}, + {"name": "wings.enabled.pro.fessional.wings.tiny.grow.database.autogen.tables.daos.WinGrowTrackDao", "type": "java.lang.Boolean"}, {"name": "wings.enabled.pro.fessional.wings.tiny.grow.spring.bean.TinyTrackConfiguration", "type": "java.lang.Boolean"}, {"name": "wings.enabled.pro.fessional.wings.tiny.grow.spring.bean.TinyTrackConfiguration$DaoServScan", "type": "java.lang.Boolean"}, + {"name": "wings.enabled.pro.fessional.wings.tiny.grow.spring.conf.TinyGrowAutoConfiguration", "type": "java.lang.Boolean"}, + {"name": "wings.enabled.pro.fessional.wings.tiny.grow.track.impl.TinyTrackAround", "type": "java.lang.Boolean"}, {"name": "wings.enabled.pro.fessional.wings.tiny.grow.track.impl.TinyTrackCollectorDaoImpl", "type": "java.lang.Boolean"}, + {"name": "wings.enabled.pro.fessional.wings.tiny.grow.track.impl.TinyTrackPreparerPropImpl", "type": "java.lang.Boolean"}, + {"name": "wings.enabled.pro.fessional.wings.tiny.grow.track.impl.TinyTrackPreparerTermImpl", "type": "java.lang.Boolean"}, {"name": "wings.enabled.pro.fessional.wings.tiny.grow.track.impl.TinyTrackServiceImpl", "type": "java.lang.Boolean"} ], "hints": [] diff --git a/radiant/tiny-grow/src/test/java/pro/fessional/wings/tiny/app/service/impl/TestTrackCollectorImpl.java b/radiant/tiny-grow/src/test/java/pro/fessional/wings/tiny/app/service/impl/TestTrackCollectorImpl.java index 6cebd3a23..270b35df5 100644 --- a/radiant/tiny-grow/src/test/java/pro/fessional/wings/tiny/app/service/impl/TestTrackCollectorImpl.java +++ b/radiant/tiny-grow/src/test/java/pro/fessional/wings/tiny/app/service/impl/TestTrackCollectorImpl.java @@ -1,6 +1,7 @@ package pro.fessional.wings.tiny.app.service.impl; import lombok.extern.slf4j.Slf4j; +import org.jetbrains.annotations.NotNull; import org.springframework.stereotype.Service; import pro.fessional.wings.tiny.grow.track.TinyTrackService; import pro.fessional.wings.tiny.grow.track.TinyTracking; @@ -18,7 +19,7 @@ public class TestTrackCollectorImpl implements TinyTrackService.Collector { public static final ConcurrentHashMap CodeKeys = new ConcurrentHashMap<>(); @Override - public void collect(TinyTracking tracking) { + public void collect(@NotNull TinyTracking tracking) { String ck = (String) tracking.getIns()[1]; log.info("done code-key={}, tracking={}", ck, tracking); CodeKeys.remove(ck); diff --git a/radiant/tiny-grow/src/test/java/pro/fessional/wings/tiny/grow/track/TinyTrackServiceTest.java b/radiant/tiny-grow/src/test/java/pro/fessional/wings/tiny/grow/track/TinyTrackServiceTest.java index e7d921643..6f399f76d 100644 --- a/radiant/tiny-grow/src/test/java/pro/fessional/wings/tiny/grow/track/TinyTrackServiceTest.java +++ b/radiant/tiny-grow/src/test/java/pro/fessional/wings/tiny/grow/track/TinyTrackServiceTest.java @@ -113,7 +113,7 @@ private void checkPojo(int id, String str, boolean web, String key, String env, String ins = (web ? "[%s,\"%s\",{}]" : "[%s,\"%s\"]").formatted(iid, str); String out = "{\"id\":%s,\"str\":\"%s\"}".formatted(iid, str); WinGrowTrack pojo = winGrowTrackDao.fetchOne(t -> t.TrackIns.eq(ins)); - Assertions.assertNotNull(pojo); + Assertions.assertNotNull(pojo, ins); Assertions.assertEquals(key, pojo.getTrackKey()); Assertions.assertTrue(pojo.getTrackEnv().contains(env)); Assertions.assertEquals(dkey, pojo.getDataKey()); diff --git a/radiant/tiny-mail/src/main/java/pro/fessional/wings/tiny/mail/service/impl/TinyMailServiceImpl.java b/radiant/tiny-mail/src/main/java/pro/fessional/wings/tiny/mail/service/impl/TinyMailServiceImpl.java index e76daeed4..aafae5ea6 100644 --- a/radiant/tiny-mail/src/main/java/pro/fessional/wings/tiny/mail/service/impl/TinyMailServiceImpl.java +++ b/radiant/tiny-mail/src/main/java/pro/fessional/wings/tiny/mail/service/impl/TinyMailServiceImpl.java @@ -782,9 +782,7 @@ private long doSyncSend(@NotNull WinMailSender po, @NotNull TinyMailMessage mess if (nxt > 0) { planAsyncMail(new AsyncMail(id, nxt, retry, check, null, message)); log.debug("plan tiny-mail next-send, err={}, id={}, subject={}", exception == null, id, po.getMailSubj()); - if (exception != null) { - exception = new MailRetryException(nxt, exception); // runtime - } + if (exception != null) throw new MailRetryException(nxt, exception); } } diff --git a/radiant/tiny-task/src/main/java/pro/fessional/wings/tiny/task/service/TinyTaskService.java b/radiant/tiny-task/src/main/java/pro/fessional/wings/tiny/task/service/TinyTaskService.java index e4974533f..eab6380ce 100644 --- a/radiant/tiny-task/src/main/java/pro/fessional/wings/tiny/task/service/TinyTaskService.java +++ b/radiant/tiny-task/src/main/java/pro/fessional/wings/tiny/task/service/TinyTaskService.java @@ -5,6 +5,7 @@ import org.jetbrains.annotations.Nullable; import org.springframework.scheduling.Trigger; import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler; +import pro.fessional.mirana.best.AssertArgs; import pro.fessional.mirana.func.Lam; import pro.fessional.mirana.time.ThreadNow; @@ -106,6 +107,7 @@ default ScheduledFuture execute(boolean fast, Trigger trigger, @NotNull Runna * @see ThreadPoolTaskScheduler#schedule(Runnable, Trigger) */ default Task schedule(@NotNull Lam.Ref lambdaRefer, @Nullable Object taskerPara) { + AssertArgs.notNull(lambdaRefer.object, "schedule object is null"); return schedule(lambdaRefer.object, lambdaRefer.method, taskerPara); } diff --git a/radiant/tiny-task/src/main/java/pro/fessional/wings/tiny/task/service/impl/TinyTaskExecServiceImpl.java b/radiant/tiny-task/src/main/java/pro/fessional/wings/tiny/task/service/impl/TinyTaskExecServiceImpl.java index 36edca634..98759f21e 100644 --- a/radiant/tiny-task/src/main/java/pro/fessional/wings/tiny/task/service/impl/TinyTaskExecServiceImpl.java +++ b/radiant/tiny-task/src/main/java/pro/fessional/wings/tiny/task/service/impl/TinyTaskExecServiceImpl.java @@ -77,6 +77,8 @@ public class TinyTaskExecServiceImpl implements TinyTaskExecService { protected static final ConcurrentHashMap Booted = new ConcurrentHashMap<>(); protected static final ConcurrentHashMap Untune = new ConcurrentHashMap<>(); + private final AtomicInteger noticeCounter = new AtomicInteger(0); + @Setter(onMethod_ = { @Value("${spring.application.name}") }) protected String appName; @@ -349,27 +351,36 @@ private Set noticeWhen(String nw) { return rs; } - private String stringResult(Object result) { + protected String stringResult(Object result) { return JacksonHelper.string(result); } - private void postNotice(NoticeExec ntc, String cnf, Set whs, String sub, String msg, long ms, String... wh) { + protected void postNotice(NoticeExec ntc, String cnf, Set whs, String sub, String msg, long ms, String... wh) { if (ntc == null) return; - final String zdt = ZonedDateTime.ofInstant(Instant.ofEpochMilli(ms), ThreadNow.sysZoneId()).toString(); + + String key = null; + boolean rtn = StringUtils.isNotEmpty(msg); for (String w : wh) { - if (whs.contains(w)) { - if (w.equals(WhenFeed)) { - if (!execProp.isDryrun() && StringUtils.isNotEmpty(msg)) { - ntc.postNotice(cnf, sub + " " + w.toUpperCase(), zdt + "\n\n" + msg); - return; - } - } - else { - ntc.postNotice(cnf, sub + " " + w.toUpperCase(), msg == null ? zdt : zdt + "\n\n" + msg); - return; + if (!whs.contains(w)) continue; + if (w.equals(WhenFeed)) { + if (rtn && !execProp.isDryrun()) { + key = w; + break; } } + else { + key = w; + break; + } } + + if (key == null) return; + + String sb = execProp.getNoticePrefix() + " " + sub + " " + key + " #" + noticeCounter.incrementAndGet(); + String bd = appName + "\n" + ZonedDateTime.ofInstant(Instant.ofEpochMilli(ms), ThreadNow.sysZoneId()); + if (rtn) bd = bd + "\n\n" + msg; + + ntc.postNotice(cnf, sb, bd); } private boolean notNextLock(WinTaskDefine td, long now) { diff --git a/radiant/tiny-task/src/main/java/pro/fessional/wings/tiny/task/spring/prop/TinyTaskExecProp.java b/radiant/tiny-task/src/main/java/pro/fessional/wings/tiny/task/spring/prop/TinyTaskExecProp.java index d9fc6b1f8..b32a8dd5e 100644 --- a/radiant/tiny-task/src/main/java/pro/fessional/wings/tiny/task/spring/prop/TinyTaskExecProp.java +++ b/radiant/tiny-task/src/main/java/pro/fessional/wings/tiny/task/spring/prop/TinyTaskExecProp.java @@ -23,4 +23,12 @@ public class TinyTaskExecProp { */ private boolean dryrun = false; public static final String Key$dryrun = Key + ".dryrun"; + + /** + * prefix of notice subject + * + * @see #Key$noticePrefix + */ + private String noticePrefix = "tiny-task"; + public static final String Key$noticePrefix = Key + ".notice-prefix"; } diff --git a/radiant/tiny-task/src/main/resources/wings-conf/wings-tinytask-exec-79.properties b/radiant/tiny-task/src/main/resources/wings-conf/wings-tinytask-exec-79.properties index 9473b119f..88061796a 100644 --- a/radiant/tiny-task/src/main/resources/wings-conf/wings-tinytask-exec-79.properties +++ b/radiant/tiny-task/src/main/resources/wings-conf/wings-tinytask-exec-79.properties @@ -1,2 +1,4 @@ ## whether to dry run, log only without realy exec the task. wings.tiny.task.exec.dryrun=false +## prefix of notice subject +wings.tiny.task.exec.notice-prefix=tiny-task diff --git a/wings/silencer/src/main/java/pro/fessional/wings/silencer/support/MetaJsonMaker.java b/wings/silencer/src/main/java/pro/fessional/wings/silencer/support/MetaJsonMaker.java index b71b501c9..b38fef39b 100644 --- a/wings/silencer/src/main/java/pro/fessional/wings/silencer/support/MetaJsonMaker.java +++ b/wings/silencer/src/main/java/pro/fessional/wings/silencer/support/MetaJsonMaker.java @@ -8,6 +8,7 @@ import org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.ScannedGenericBeanDefinition; +import org.springframework.core.io.Resource; import org.springframework.core.type.AnnotationMetadata; import org.springframework.core.type.classreading.MetadataReader; import pro.fessional.wings.silencer.spring.boot.ConditionalWingsEnabled; @@ -22,7 +23,6 @@ import java.util.LinkedHashMap; import java.util.List; import java.util.Map; -import java.util.Objects; import java.util.Set; import java.util.TreeSet; @@ -44,6 +44,7 @@ public static class Meta { private final String root; @NotNull private final String claz; + @NotNull private final String pkg; private final boolean bool; @@ -62,7 +63,7 @@ public static class Proj { */ @NotNull public List scanMeta() throws Exception { - return scanMeta("pro.fessional"); + return scanMeta("pro.fessional.wings"); } /** @@ -71,9 +72,12 @@ public List scanMeta() throws Exception { @NotNull public List scanMeta(@NotNull String pkg) throws Exception { - var scanner = new ClassPathScanningCandidateComponentProvider(true) { + var scanner = new ClassPathScanningCandidateComponentProvider(false) { + { + addIncludeFilter((mr, ignore) -> mr.getClassMetadata().getClassName().startsWith(pkg)); + } @Override - protected boolean isCandidateComponent(MetadataReader metadataReader) { + protected boolean isCandidateComponent(@NotNull MetadataReader ignore) { return true; } }; @@ -91,11 +95,14 @@ protected boolean isCandidateComponent(MetadataReader metadataReader) { if (!(bd instanceof ScannedGenericBeanDefinition gbd)) continue; final String name = gbd.getBeanClassName(); - if (!name.startsWith(pkg)) continue; + if (name == null || !name.startsWith(pkg)) continue; final String pack = name.substring(0, name.lastIndexOf('.')); - String tmp = Objects.requireNonNull(gbd.getResource().getFile()).getCanonicalPath(); + final Resource res = gbd.getResource(); + if(res == null || !res.isFile()) continue; + + final String tmp = res.getFile().getCanonicalPath(); final String root = tmp.substring(0, tmp.indexOf("/target/classes")); final AnnotationMetadata amd = gbd.getMetadata(); From f0227f0329370a4f1099cfc4c660274957350d00 Mon Sep 17 00:00:00 2001 From: trydofor Date: Sat, 3 Aug 2024 08:57:45 +0800 Subject: [PATCH 36/51] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20executor=20should=20?= =?UTF-8?q?shutdown=20if=20kill=20#283?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- WingsBoot.t.md | 1 + observe/docs | 2 +- .../grow/track/impl/TinyTrackServiceImpl.java | 17 +++++- .../wings/tiny/mail/sender/MailNotice.java | 15 ++++- .../service/impl/TinyMailServiceImpl.java | 33 ++++++++++- .../service/impl/TinyTaskBeatServiceImpl.java | 15 ++++- .../service/impl/TinyTaskExecServiceImpl.java | 33 ++++++++++- .../task/service/TinyTaskExecServiceTest.java | 4 +- .../impl/TinyTaskBeatServiceImplTest.java | 42 ++++++++++++++ .../app/TestSilencerCurseApplication.java | 41 +++++++++++++- .../app/conf/TestApplicationEventLogger.java | 7 +-- .../conf/TestSpringOrderConfiguration.java | 56 ++++++++----------- .../service/impl/TestSpringOrderService.java | 43 ++++++++++++++ .../bean/SilencerRunnerConfiguration.java | 17 +++--- .../stream/WingsReuseStreamFilter.java | 3 +- .../bean/SlardarOverloadConfiguration.java | 10 +--- .../wings/slardar/async/AsyncHelper.java | 8 ++- .../slardar/async/TaskSchedulerHelper.java | 7 ++- .../wings/slardar/monitor/MonitorTask.java | 19 ++++--- .../wings/slardar/notice/DingTalkNotice.java | 15 ++++- 20 files changed, 310 insertions(+), 78 deletions(-) create mode 100644 radiant/tiny-task/src/test/java/pro/fessional/wings/tiny/task/service/impl/TinyTaskBeatServiceImplTest.java create mode 100644 wings/silencer-curse/src/test/java/pro/fessional/wings/silencer/app/service/impl/TestSpringOrderService.java diff --git a/WingsBoot.t.md b/WingsBoot.t.md index 6c6e9f694..401acb305 100644 --- a/WingsBoot.t.md +++ b/WingsBoot.t.md @@ -437,4 +437,5 @@ Use `t.md` as local [Test Management](https://www.jetbrains.com/help/idea/test-m * 15017 TinyMailServiceDbTest: mock fail and check database * 15018 TinyTrackServiceTest: tiny track AOP service * 15019 TinyTrackServiceTest: tiny track Mvc controller +* 15020 TinyTaskBeatServiceImplTest: beat mills cron/rate/idle diff --git a/observe/docs b/observe/docs index 01b278add..fb007f207 160000 --- a/observe/docs +++ b/observe/docs @@ -1 +1 @@ -Subproject commit 01b278addb932d3a99aff3c3f1bb987273a7bd6b +Subproject commit fb007f207b8b0ea860a4b66c40453516e4fc8555 diff --git a/radiant/tiny-grow/src/main/java/pro/fessional/wings/tiny/grow/track/impl/TinyTrackServiceImpl.java b/radiant/tiny-grow/src/main/java/pro/fessional/wings/tiny/grow/track/impl/TinyTrackServiceImpl.java index 84224713c..2ff5d298b 100644 --- a/radiant/tiny-grow/src/main/java/pro/fessional/wings/tiny/grow/track/impl/TinyTrackServiceImpl.java +++ b/radiant/tiny-grow/src/main/java/pro/fessional/wings/tiny/grow/track/impl/TinyTrackServiceImpl.java @@ -4,6 +4,7 @@ import lombok.Setter; import lombok.extern.slf4j.Slf4j; import org.jetbrains.annotations.NotNull; +import org.springframework.beans.factory.DisposableBean; import org.springframework.beans.factory.InitializingBean; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; @@ -15,6 +16,7 @@ import java.util.List; import java.util.concurrent.Executor; +import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.FutureTask; @@ -27,10 +29,11 @@ @Service @ConditionalWingsEnabled @Slf4j -public class TinyTrackServiceImpl implements TinyTrackService, InitializingBean { +public class TinyTrackServiceImpl implements TinyTrackService, InitializingBean, DisposableBean { @Setter(onMethod_ = { @Autowired(required = false), @Qualifier(DEFAULT_TASK_EXECUTOR_BEAN_NAME) }) private Executor executor; + private boolean innerExecutor = false; @Setter(onMethod_ = { @Autowired }) protected List trackCollector; @@ -85,10 +88,18 @@ public void track(@NotNull TinyTracking tracking) { } @Override - public void afterPropertiesSet() throws Exception { + public void afterPropertiesSet() { if (executor == null) { log.warn("should reuse autowired thread pool"); - executor = TtlExecutors.getTtlExecutor(Executors.newWorkStealingPool(2)); + executor = TtlExecutors.getTtlExecutorService(Executors.newWorkStealingPool(2)); + innerExecutor = true; + } + } + + @Override + public void destroy() { + if (innerExecutor && executor instanceof ExecutorService es) { + es.shutdown(); } } } diff --git a/radiant/tiny-mail/src/main/java/pro/fessional/wings/tiny/mail/sender/MailNotice.java b/radiant/tiny-mail/src/main/java/pro/fessional/wings/tiny/mail/sender/MailNotice.java index 82c2cbd0f..483d6bd14 100644 --- a/radiant/tiny-mail/src/main/java/pro/fessional/wings/tiny/mail/sender/MailNotice.java +++ b/radiant/tiny-mail/src/main/java/pro/fessional/wings/tiny/mail/sender/MailNotice.java @@ -8,6 +8,7 @@ import lombok.extern.slf4j.Slf4j; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import org.springframework.beans.factory.DisposableBean; import org.springframework.beans.factory.InitializingBean; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; @@ -16,6 +17,7 @@ import java.util.Collections; import java.util.Map; import java.util.concurrent.Executor; +import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import static org.springframework.scheduling.annotation.ScheduledAnnotationBeanPostProcessor.DEFAULT_TASK_SCHEDULER_BEAN_NAME; @@ -26,7 +28,7 @@ */ @Slf4j @RequiredArgsConstructor -public class MailNotice implements SmallNotice, InitializingBean { +public class MailNotice implements SmallNotice, InitializingBean, DisposableBean { @NotNull @Getter protected final MailConfigProvider configProvider; @@ -35,6 +37,7 @@ public class MailNotice implements SmallNotice, InitializingBean @Setter(onMethod_ = { @Autowired(required = false), @Qualifier(DEFAULT_TASK_SCHEDULER_BEAN_NAME) }) private Executor executor; + private boolean innerExecutor = false; @Setter @Getter private Map configs = Collections.emptyMap(); @@ -92,7 +95,15 @@ public void emit(TinyMailConfig config, String subject, String content) { public void afterPropertiesSet() { if (executor == null) { log.warn("should reuse autowired thread pool"); - executor = TtlExecutors.getTtlExecutor(Executors.newWorkStealingPool(2)); + executor = TtlExecutors.getTtlExecutorService(Executors.newWorkStealingPool(2)); + innerExecutor = true; + } + } + + @Override + public void destroy() { + if (innerExecutor && executor instanceof ExecutorService es) { + es.shutdown(); } } } diff --git a/radiant/tiny-mail/src/main/java/pro/fessional/wings/tiny/mail/service/impl/TinyMailServiceImpl.java b/radiant/tiny-mail/src/main/java/pro/fessional/wings/tiny/mail/service/impl/TinyMailServiceImpl.java index aafae5ea6..fab530b60 100644 --- a/radiant/tiny-mail/src/main/java/pro/fessional/wings/tiny/mail/service/impl/TinyMailServiceImpl.java +++ b/radiant/tiny-mail/src/main/java/pro/fessional/wings/tiny/mail/service/impl/TinyMailServiceImpl.java @@ -8,6 +8,7 @@ import org.apache.commons.lang3.StringUtils; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import org.springframework.beans.factory.DisposableBean; import org.springframework.beans.factory.InitializingBean; import org.springframework.beans.factory.ObjectProvider; import org.springframework.beans.factory.annotation.Autowired; @@ -83,7 +84,7 @@ @Service @ConditionalWingsEnabled @Slf4j -public class TinyMailServiceImpl implements TinyMailService, InitializingBean { +public class TinyMailServiceImpl implements TinyMailService, InitializingBean, DisposableBean { @Setter(onMethod_ = { @Value("${spring.application.name}") }) protected String appName; @@ -108,6 +109,7 @@ public class TinyMailServiceImpl implements TinyMailService, InitializingBean { // init by afterPropertiesSet protected ThreadPoolTaskScheduler taskScheduler; + protected volatile boolean isShutdown = false; protected SingletonSupplier> lazyBeanHolder; protected SingletonSupplier> statusHookHolder; @@ -196,6 +198,7 @@ public void afterPropertiesSet() { taskScheduler = TaskSchedulerHelper.Ttl(builder); taskScheduler.initialize(); + isShutdown = false; log.info("tiny-mail taskScheduler, prefix=" + taskScheduler.getThreadNamePrefix()); final long idle = tinyMailServiceProp.getBootScan().toMillis(); @@ -217,6 +220,14 @@ public void afterPropertiesSet() { }); } + @Override + public void destroy() { + isShutdown = true; + if (taskScheduler != null) { + taskScheduler.shutdown(); + } + } + @Override @SuppressWarnings("DuplicatedCode") public long save(@NotNull TinyMailPlain msg, boolean check) { @@ -552,6 +563,11 @@ protected long doSend(boolean sync, @NotNull TinyMail message, boolean retry) { final WinMailSender po = saveMailSender(config, message); + if (isShutdown) { + log.warn("save but skip tiny-mail for shutdwon, subject={}", message.getSubject()); + return ErrOther; + } + final TinyMailMessage mailMessage = makeMailMessage(config, po, message); if (sync) { return doSyncSend(po, mailMessage, retry, true); @@ -562,6 +578,11 @@ protected long doSend(boolean sync, @NotNull TinyMail message, boolean retry) { } protected long doSend(boolean sync, long id, boolean retry, boolean check) { + if (isShutdown) { + log.warn("skip tiny-mail for shutdwon, id={}", id); + return ErrOther; + } + final WinMailSender po = winMailSenderDao.fetchOneById(id); AssertArgs.notNull(po, "skip tiny-mail not found by id={}", id); @@ -746,6 +767,11 @@ protected void editLazyMail(@NotNull WinMailSender po, @NotNull @Param.Out TinyM } private long doSyncSend(@NotNull WinMailSender po, @NotNull TinyMailMessage message, boolean retry, boolean check) { + if (isShutdown) { + log.warn("skip tiny-mail for shutdwon, id={}", po.getId()); + return ErrOther; + } + final long start; if (check) { // condition not match @@ -798,6 +824,11 @@ else if (exception instanceof RuntimeException re) { } private long doAsyncSend(@NotNull WinMailSender po, @NotNull TinyMailMessage message, boolean retry, boolean check) { + if (isShutdown) { + log.warn("skip tiny-mail for shutdwon, id={}", po.getId()); + return ErrOther; + } + // condition not match if (check && notMatchProp(po)) return ErrCheck; diff --git a/radiant/tiny-task/src/main/java/pro/fessional/wings/tiny/task/service/impl/TinyTaskBeatServiceImpl.java b/radiant/tiny-task/src/main/java/pro/fessional/wings/tiny/task/service/impl/TinyTaskBeatServiceImpl.java index a363b25bb..5c9441e2c 100644 --- a/radiant/tiny-task/src/main/java/pro/fessional/wings/tiny/task/service/impl/TinyTaskBeatServiceImpl.java +++ b/radiant/tiny-task/src/main/java/pro/fessional/wings/tiny/task/service/impl/TinyTaskBeatServiceImpl.java @@ -13,6 +13,7 @@ import pro.fessional.mirana.time.DateLocaling; import pro.fessional.mirana.time.ThreadNow; import pro.fessional.wings.faceless.convention.EmptySugar; +import pro.fessional.wings.silencer.modulate.RuntimeMode; import pro.fessional.wings.silencer.spring.boot.ConditionalWingsEnabled; import pro.fessional.wings.tiny.task.database.autogen.tables.WinTaskDefineTable; import pro.fessional.wings.tiny.task.database.autogen.tables.WinTaskResultTable; @@ -112,6 +113,12 @@ public String checkHealth() { final StringBuilder mis = warmed ? new StringBuilder() : null; for (WinTaskDefine r : tks) { log.debug("check health tiny-task id={}, name={}", r.getId(), r.getTaskerName()); + + final String runs = r.getTaskerRuns(); + if (StringUtils.isNotBlank(runs) && !RuntimeMode.voteRunMode(runs)) { + continue; + } + // coordinate to system timezone long beat = calcBeatMills(r, now); if (beat <= 0) continue; @@ -125,10 +132,12 @@ public String checkHealth() { } warmed = true; - return mis == null || mis.isEmpty() ? null : "misfired tiny-task id@name\n" + mis; + return mis == null || mis.isEmpty() ? null + : "misfired tiny-task id@name, beat=-1 to skip\n" + + mis; } - private long calcBeatMills(WinTaskDefine td, long now) { + protected long calcBeatMills(WinTaskDefine td, long now) { // no previous LocalDateTime lastExec = td.getLastExec(); if (EmptySugar.asEmptyValue(lastExec)) { @@ -156,7 +165,7 @@ private long calcBeatMills(WinTaskDefine td, long now) { for (int i = 0; i < beatTimes; i++) { ZonedDateTime nxt = cronExpr.next(beatZdt); if (nxt == null) break; - + beatZdt = nxt; } diff --git a/radiant/tiny-task/src/main/java/pro/fessional/wings/tiny/task/service/impl/TinyTaskExecServiceImpl.java b/radiant/tiny-task/src/main/java/pro/fessional/wings/tiny/task/service/impl/TinyTaskExecServiceImpl.java index 98759f21e..b770117b5 100644 --- a/radiant/tiny-task/src/main/java/pro/fessional/wings/tiny/task/service/impl/TinyTaskExecServiceImpl.java +++ b/radiant/tiny-task/src/main/java/pro/fessional/wings/tiny/task/service/impl/TinyTaskExecServiceImpl.java @@ -4,6 +4,8 @@ import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.jooq.Field; +import org.springframework.beans.factory.DisposableBean; +import org.springframework.beans.factory.InitializingBean; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.scheduling.Trigger; @@ -70,7 +72,7 @@ @Service @ConditionalWingsEnabled @Slf4j -public class TinyTaskExecServiceImpl implements TinyTaskExecService { +public class TinyTaskExecServiceImpl implements TinyTaskExecService, InitializingBean, DisposableBean { protected static final ConcurrentHashMap> Handle = new ConcurrentHashMap<>(); protected static final ConcurrentHashMap Cancel = new ConcurrentHashMap<>(); @@ -97,6 +99,25 @@ public class TinyTaskExecServiceImpl implements TinyTaskExecService { @Setter(onMethod_ = { @Autowired }) protected TinyTaskExecProp execProp; + protected volatile boolean isShutdown = false; + + @Override + public void afterPropertiesSet() { + isShutdown = false; + } + + @Override + public void destroy() { + isShutdown = true; + for (var en : Handle.entrySet()) { + var task = en.getValue(); + if (task.isDone()) continue; + + log.info("try to cancal tiny-task for shutdown, id={}", en.getKey()); + task.cancel(false); + } + } + @Override public boolean launch(long id) { Cancel.remove(id); @@ -105,6 +126,11 @@ public boolean launch(long id) { @Override public boolean force(long id) { + if (isShutdown) { + log.warn("skip tiny-task for shutdwon, id={}", id); + return false; + } + final WinTaskDefine td = winTaskDefineDao.fetchOneById(id); if (td == null) { log.info("skip tiny-task for not found, id={}", id); @@ -192,6 +218,11 @@ public Set running() { } private boolean relaunch(long id) { + if (isShutdown) { + log.warn("skip tiny-task for shutdwon, id={}", id); + return false; + } + final Lock lock = JvmStaticGlobalLock.get(id); try { lock.lock(); diff --git a/radiant/tiny-task/src/test/java/pro/fessional/wings/tiny/task/service/TinyTaskExecServiceTest.java b/radiant/tiny-task/src/test/java/pro/fessional/wings/tiny/task/service/TinyTaskExecServiceTest.java index b046e7d6c..cb042ab2c 100644 --- a/radiant/tiny-task/src/test/java/pro/fessional/wings/tiny/task/service/TinyTaskExecServiceTest.java +++ b/radiant/tiny-task/src/test/java/pro/fessional/wings/tiny/task/service/TinyTaskExecServiceTest.java @@ -80,8 +80,8 @@ private void check(PageResult result, int size, int span) { long spaned = 0; if (prevExec != null) { spaned = Duration.between(timeExec, prevExec).abs().toSeconds() + 2; - log.info("WinTaskResult, id={}, exec={}, exit={}, fail={}, span={}", it.getTaskId(), timeExec, it.getTimeExit(), it.getExitFail(), spaned); - Assertions.assertTrue(spaned >= span); + log.info("WinTaskResult, id={}, exec={}, exit={}, fail={}, spaned={}", it.getTaskId(), timeExec, it.getTimeExit(), it.getExitFail(), spaned); + Assertions.assertTrue(spaned >= span, "spaned=" + spaned + " vs span=" + span); } else { log.info("WinTaskResult, id={}, exec={}, exit={}, fail={}", it.getTaskId(), timeExec, it.getTimeExit(), it.getExitFail()); diff --git a/radiant/tiny-task/src/test/java/pro/fessional/wings/tiny/task/service/impl/TinyTaskBeatServiceImplTest.java b/radiant/tiny-task/src/test/java/pro/fessional/wings/tiny/task/service/impl/TinyTaskBeatServiceImplTest.java new file mode 100644 index 000000000..85c0b78c8 --- /dev/null +++ b/radiant/tiny-task/src/test/java/pro/fessional/wings/tiny/task/service/impl/TinyTaskBeatServiceImplTest.java @@ -0,0 +1,42 @@ +package pro.fessional.wings.tiny.task.service.impl; + +import io.qameta.allure.TmsLink; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import pro.fessional.mirana.time.ThreadNow; +import pro.fessional.wings.tiny.task.database.autogen.tables.pojos.WinTaskDefine; + +import java.time.Instant; +import java.time.LocalDateTime; +import java.time.ZoneId; + +/** + * @author trydofor + * @since 2024-08-02 + */ +class TinyTaskBeatServiceImplTest { + + @Test + @TmsLink("C15020") + void calcBeatMills() { + TinyTaskBeatServiceImpl bs = new TinyTaskBeatServiceImpl(); + WinTaskDefine td = new WinTaskDefine(); + td.setLastExec(LocalDateTime.parse("2024-07-31T02:01:00")); + td.setTimingBeat(0); + td.setTimingCron("0 1 2 * * *"); + td.setTimingZone(""); + long now = ThreadNow.millis(); + long next = bs.calcBeatMills(td, now); + LocalDateTime ldt = LocalDateTime.ofInstant(Instant.ofEpochMilli(next), ZoneId.systemDefault()); + LocalDateTime nxt2 = LocalDateTime.parse("2024-08-02T02:00:00"); + Assertions.assertTrue(ldt.isAfter(nxt2), ldt + " > " + nxt2); + + td.setLastExec(LocalDateTime.ofInstant(Instant.ofEpochMilli(now), ZoneId.systemDefault())); + td.setTimingRate(60); + td.setTimingIdle(50); + td.setTimingCron(""); + long nr2 = bs.calcBeatMills(td, now); + long df = (nr2 - now) / 1000; + Assertions.assertTrue(df > 120 - 2, "s=" + df); + } +} \ No newline at end of file diff --git a/wings/silencer-curse/src/test/java/pro/fessional/wings/silencer/app/TestSilencerCurseApplication.java b/wings/silencer-curse/src/test/java/pro/fessional/wings/silencer/app/TestSilencerCurseApplication.java index 04889639f..c1e50ee85 100644 --- a/wings/silencer-curse/src/test/java/pro/fessional/wings/silencer/app/TestSilencerCurseApplication.java +++ b/wings/silencer-curse/src/test/java/pro/fessional/wings/silencer/app/TestSilencerCurseApplication.java @@ -6,7 +6,39 @@ import org.springframework.context.annotation.Bean; import pro.fessional.wings.silencer.app.conf.TestMergingProp; +import java.util.concurrent.atomic.AtomicInteger; + /** + * #01, 244ms, (spring.factories): ApplicationStartingEvent + * #02, 2209ms, (spring.factories): ApplicationEnvironmentPreparedEvent + * #03, 2758ms, (spring.factories): ApplicationContextInitializedEvent + * #04, 2809ms, (spring.factories): ApplicationPreparedEvent + * #05, 3365ms, @PostConstruct: TestSpringOrderService + * #06, 3365ms, @Override: InitializingBean TestSpringOrderService + * #07, 3381ms, (constructor): can inject para, autoconf=true + * #08, 3384ms, @Autowired: testAutowired1 can inject para, autoconf=true + * #09, 3384ms, @PostConstruct: postConstruct1 + * #10, 3384ms, @PostConstruct: postConstruct2 + * #11, 3385ms, @Override: InitializingBean TestSpringOrderConfiguration + * #12, 3385ms, @Bean: testBean1 can inject para, autoconf=true + * #13, 3386ms, @Bean: testBean2 can inject para, autoconf=true + * #14, 3657ms, (spring.factories): ContextRefreshedEvent + * #15, 3662ms, (spring.factories): ApplicationStartedEvent + * #16, 3664ms, @EventListener: ApplicationStartedEvent + * #17, 3665ms, (spring.factories): AvailabilityChangeEvent + * #18, 3669ms, CommandLineRunner: CommandLineRunner1 + * #19, 3673ms, CommandLineRunner: CommandLineRunner2 + * #20, 3674ms, (spring.factories): ApplicationReadyEvent + * #21, 3675ms, @EventListener: ApplicationReadyEvent + * #22, 3676ms, (spring.factories): AvailabilityChangeEvent + * #23, 3678ms, Jvm ShutdownHook + * #24, 3679ms, (spring.factories): ContextClosedEvent + * #25, 3679ms, @EventListener: ContextClosedEvent + * #26, 3682ms, @PreDestroy: TestSpringOrderConfiguration + * #27, 3682ms, @Override: DisposableBean TestSpringOrderConfiguration + * #28, 3682ms, @PreDestroy: TestSpringOrderService + * #29, 3682ms, @Override: DisposableBean TestSpringOrderService + * * @author trydofor * @since 2019-07-20 */ @@ -14,6 +46,13 @@ @EnableConfigurationProperties(TestMergingProp.class) public class TestSilencerCurseApplication { + private static final AtomicInteger seq = new AtomicInteger(0); + private static final long start = System.currentTimeMillis(); + + public static void log(String msg) { + System.err.printf(">>>>> #%02d, %4dms, %s\n", seq.incrementAndGet(), (System.currentTimeMillis() - start), msg); + } + public interface InnerFace { } @@ -22,8 +61,8 @@ public InnerFace innerFace() { return new InnerFace() {}; } - public static void main(String[] args) { + Runtime.getRuntime().addShutdownHook(new Thread(() -> log("Jvm ShutdownHook"))); SpringApplication.run(TestSilencerCurseApplication.class, args); } } diff --git a/wings/silencer-curse/src/test/java/pro/fessional/wings/silencer/app/conf/TestApplicationEventLogger.java b/wings/silencer-curse/src/test/java/pro/fessional/wings/silencer/app/conf/TestApplicationEventLogger.java index ab6568956..2921c6681 100644 --- a/wings/silencer-curse/src/test/java/pro/fessional/wings/silencer/app/conf/TestApplicationEventLogger.java +++ b/wings/silencer-curse/src/test/java/pro/fessional/wings/silencer/app/conf/TestApplicationEventLogger.java @@ -1,9 +1,8 @@ package pro.fessional.wings.silencer.app.conf; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; import org.springframework.context.ApplicationEvent; import org.springframework.context.ApplicationListener; +import pro.fessional.wings.silencer.app.TestSilencerCurseApplication; /** * @author trydofor @@ -11,10 +10,8 @@ */ public class TestApplicationEventLogger implements ApplicationListener { - private static final Log log = LogFactory.getLog(TestApplicationEventLogger.class); - @Override public void onApplicationEvent(ApplicationEvent event) { - log.info(">>>>> " + event.getClass().getSimpleName() + "(spring.factories) timestamp=" + event.getTimestamp()); + TestSilencerCurseApplication.log("(spring.factories): " + event.getClass().getSimpleName()); } } diff --git a/wings/silencer-curse/src/test/java/pro/fessional/wings/silencer/app/conf/TestSpringOrderConfiguration.java b/wings/silencer-curse/src/test/java/pro/fessional/wings/silencer/app/conf/TestSpringOrderConfiguration.java index 7c3cf214d..600968d1b 100644 --- a/wings/silencer-curse/src/test/java/pro/fessional/wings/silencer/app/conf/TestSpringOrderConfiguration.java +++ b/wings/silencer-curse/src/test/java/pro/fessional/wings/silencer/app/conf/TestSpringOrderConfiguration.java @@ -1,8 +1,8 @@ package pro.fessional.wings.silencer.app.conf; import jakarta.annotation.PostConstruct; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; +import jakarta.annotation.PreDestroy; +import org.springframework.beans.factory.DisposableBean; import org.springframework.beans.factory.InitializingBean; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.CommandLineRunner; @@ -10,39 +10,21 @@ import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.event.EventListener; +import pro.fessional.wings.silencer.app.TestSilencerCurseApplication; import pro.fessional.wings.silencer.other.CollectionInjectTest; import pro.fessional.wings.silencer.spring.prop.SilencerEnabledProp; /** - * ApplicationEnvironmentPreparedEvent(spring.factories) - * ApplicationContextInitializedEvent(spring.factories) - * ApplicationPreparedEvent(spring.factories) - * constructor - * testAutowired1 - * postConstruct1 - * postConstruct2 - * afterPropertiesSet - * testBean1 - * testBean2 - * ContextRefreshedEvent(spring.factories) - * ApplicationStartedEvent - * CommandLineRunner1 - * CommandLineRunner2 - * ApplicationReadyEvent - * ContextClosedEvent(spring.factories) - * * @author trydofor * @since 2022-11-02 */ @Configuration(proxyBeanMethods = false) -public class TestSpringOrderConfiguration implements InitializingBean { - private static final Log log = LogFactory.getLog(TestSpringOrderConfiguration.class); +public class TestSpringOrderConfiguration implements InitializingBean, DisposableBean { public TestSpringOrderConfiguration(SilencerEnabledProp prop) { - log.info(">>>>> constructor can inject parameter Autoconf=" + prop.isAutoconf()); + TestSilencerCurseApplication.log("(constructor): can inject para, autoconf=" + prop.isAutoconf()); } - @Bean public CollectionInjectTest.Dto dto2() { return new CollectionInjectTest.Dto(2); @@ -50,38 +32,48 @@ public CollectionInjectTest.Dto dto2() { @Bean public CommandLineRunner testBean1(SilencerEnabledProp prop) { - log.info(">>>>> testBean1 can inject parameter autoconf=" + prop.isAutoconf()); - return ignored -> log.info(">>>>> CommandLineRunner1 " + prop.isAutoconf()); + TestSilencerCurseApplication.log("@Bean: testBean1 can inject para, autoconf=" + prop.isAutoconf()); + return ignored -> TestSilencerCurseApplication.log("CommandLineRunner: CommandLineRunner1 "); } @PostConstruct public void postConstruct1() { - log.info(">>>>> postConstruct1 can NOT inject parameter"); + TestSilencerCurseApplication.log("@PostConstruct: postConstruct1"); } @Autowired public void testAutowired1(SilencerEnabledProp prop) { - log.info(">>>>> testAutowired1 can inject parameter autoconf=" + prop.isAutoconf()); + TestSilencerCurseApplication.log("@Autowired: testAutowired1 can inject para, autoconf=" + prop.isAutoconf()); } @PostConstruct public void postConstruct2() { - log.info(">>>>> postConstruct2"); + TestSilencerCurseApplication.log("@PostConstruct: postConstruct2"); } @Bean public CommandLineRunner testBean2(SilencerEnabledProp prop) { - log.info(">>>>> testBean2 autoconf=" + prop.isAutoconf()); - return ignored -> log.info(">>>>> CommandLineRunner2 autoconf=" + prop.isAutoconf()); + TestSilencerCurseApplication.log("@Bean: testBean2 can inject para, autoconf=" + prop.isAutoconf()); + return ignored -> TestSilencerCurseApplication.log("CommandLineRunner: CommandLineRunner2"); } @EventListener public void testApplicationReadyEvent(SpringApplicationEvent event) { - log.info(">>>>> " + event.getClass().getSimpleName() + " timestamp=" + event.getTimestamp()); + TestSilencerCurseApplication.log("@EventListener: " + event.getClass().getSimpleName()); } @Override public void afterPropertiesSet() { - log.info(">>>>> afterPropertiesSet"); + TestSilencerCurseApplication.log("@Override: InitializingBean TestSpringOrderConfiguration"); + } + + @PreDestroy + public void preDestroy() { + TestSilencerCurseApplication.log("@PreDestroy: TestSpringOrderConfiguration"); + } + + @Override + public void destroy() { + TestSilencerCurseApplication.log("@Override: DisposableBean TestSpringOrderConfiguration"); } } diff --git a/wings/silencer-curse/src/test/java/pro/fessional/wings/silencer/app/service/impl/TestSpringOrderService.java b/wings/silencer-curse/src/test/java/pro/fessional/wings/silencer/app/service/impl/TestSpringOrderService.java new file mode 100644 index 000000000..a10e793c9 --- /dev/null +++ b/wings/silencer-curse/src/test/java/pro/fessional/wings/silencer/app/service/impl/TestSpringOrderService.java @@ -0,0 +1,43 @@ +package pro.fessional.wings.silencer.app.service.impl; + +import jakarta.annotation.PostConstruct; +import jakarta.annotation.PreDestroy; +import org.springframework.beans.factory.DisposableBean; +import org.springframework.beans.factory.InitializingBean; +import org.springframework.context.event.ContextClosedEvent; +import org.springframework.context.event.EventListener; +import org.springframework.stereotype.Service; +import pro.fessional.wings.silencer.app.TestSilencerCurseApplication; + +/** + * @author trydofor + * @since 2024-08-02 + */ +@Service +public class TestSpringOrderService implements InitializingBean, DisposableBean { + + @EventListener + public void testApplicationReadyEvent(ContextClosedEvent event) { + TestSilencerCurseApplication.log("@EventListener: " + event.getClass().getSimpleName()); + } + + @PostConstruct + public void PostConstruct() { + TestSilencerCurseApplication.log("@PostConstruct: TestSpringOrderService"); + } + + @Override + public void afterPropertiesSet() { + TestSilencerCurseApplication.log("@Override: InitializingBean TestSpringOrderService"); + } + + @PreDestroy + public void preDestroy() { + TestSilencerCurseApplication.log("@PreDestroy: TestSpringOrderService"); + } + + @Override + public void destroy() { + TestSilencerCurseApplication.log("@Override: DisposableBean TestSpringOrderService"); + } +} diff --git a/wings/silencer/src/main/java/pro/fessional/wings/silencer/spring/bean/SilencerRunnerConfiguration.java b/wings/silencer/src/main/java/pro/fessional/wings/silencer/spring/bean/SilencerRunnerConfiguration.java index 68bed16d1..73136a876 100644 --- a/wings/silencer/src/main/java/pro/fessional/wings/silencer/spring/bean/SilencerRunnerConfiguration.java +++ b/wings/silencer/src/main/java/pro/fessional/wings/silencer/spring/bean/SilencerRunnerConfiguration.java @@ -2,12 +2,13 @@ import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.jetbrains.annotations.NotNull; import org.springframework.boot.ApplicationArguments; import org.springframework.boot.context.event.ApplicationReadyEvent; import org.springframework.boot.context.event.ApplicationStartedEvent; +import org.springframework.context.ApplicationListener; import org.springframework.context.ConfigurableApplicationContext; import org.springframework.context.annotation.Configuration; -import org.springframework.context.event.EventListener; import org.springframework.stereotype.Component; import pro.fessional.wings.silencer.runner.ApplicationReadyEventRunner; import pro.fessional.wings.silencer.runner.ApplicationStartedEventRunner; @@ -30,9 +31,9 @@ public class SilencerRunnerConfiguration { @Component @ConditionalWingsEnabled - public static class ReadyEvent { - @EventListener - public void on(ApplicationReadyEvent event) { + public static class ReadyEvent implements ApplicationListener { + @Override + public void onApplicationEvent(@NotNull ApplicationReadyEvent event) { final ConfigurableApplicationContext context = event.getApplicationContext(); final Map beans = context.getBeansOfType(ApplicationReadyEventRunner.class); if (beans.isEmpty()) { @@ -57,10 +58,10 @@ public void on(ApplicationReadyEvent event) { @Component @ConditionalWingsEnabled - public static class StartedEvent { - @EventListener - public void on(ApplicationStartedEvent startedEvent) { - final ConfigurableApplicationContext context = startedEvent.getApplicationContext(); + public static class StartedEvent implements ApplicationListener { + @Override + public void onApplicationEvent(@NotNull ApplicationStartedEvent event) { + final ConfigurableApplicationContext context = event.getApplicationContext(); final Map beans = context.getBeansOfType(ApplicationStartedEventRunner.class); if (beans.isEmpty()) { log.info("===>>> Silencer applicationStartedEventRunner empty"); diff --git a/wings/slardar-webmvc/src/main/java/pro/fessional/wings/slardar/servlet/stream/WingsReuseStreamFilter.java b/wings/slardar-webmvc/src/main/java/pro/fessional/wings/slardar/servlet/stream/WingsReuseStreamFilter.java index 517589e7f..bd5025c24 100644 --- a/wings/slardar-webmvc/src/main/java/pro/fessional/wings/slardar/servlet/stream/WingsReuseStreamFilter.java +++ b/wings/slardar-webmvc/src/main/java/pro/fessional/wings/slardar/servlet/stream/WingsReuseStreamFilter.java @@ -20,8 +20,9 @@ @Setter @Getter public class WingsReuseStreamFilter extends OncePerRequestFilter implements Ordered { + public static final int ORDER = WingsOrdered.Lv4Application; - private int order = WingsOrdered.Lv4Application; + private int order = ORDER; private RequestResponseLogging requestResponseLogging; @Override diff --git a/wings/slardar-webmvc/src/main/java/pro/fessional/wings/slardar/spring/bean/SlardarOverloadConfiguration.java b/wings/slardar-webmvc/src/main/java/pro/fessional/wings/slardar/spring/bean/SlardarOverloadConfiguration.java index e46a50307..f6c9aea0f 100644 --- a/wings/slardar-webmvc/src/main/java/pro/fessional/wings/slardar/spring/bean/SlardarOverloadConfiguration.java +++ b/wings/slardar-webmvc/src/main/java/pro/fessional/wings/slardar/spring/bean/SlardarOverloadConfiguration.java @@ -2,7 +2,6 @@ import jakarta.servlet.Filter; import jakarta.servlet.http.HttpServletResponse; -import lombok.RequiredArgsConstructor; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.jetbrains.annotations.NotNull; @@ -14,7 +13,6 @@ import org.springframework.core.annotation.Order; import org.springframework.stereotype.Component; import pro.fessional.mirana.best.DummyBlock; -import pro.fessional.wings.silencer.spring.WingsOrdered; import pro.fessional.wings.silencer.spring.boot.ConditionalWingsEnabled; import pro.fessional.wings.slardar.servlet.filter.WingsOverloadFilter; import pro.fessional.wings.slardar.servlet.resolver.WingsRemoteResolver; @@ -39,18 +37,16 @@ public class SlardarOverloadConfiguration { private final Log log = LogFactory.getLog(SlardarOverloadConfiguration.class); @Component - @Order(WingsOrdered.Lv4Application) + @Order @ConditionalWingsEnabled - @RequiredArgsConstructor public class SafelyShutdown implements ApplicationListener { - private final WingsOverloadFilter overloadFilter; - @Override @SuppressWarnings("BusyWait") public void onApplicationEvent(@NotNull ContextClosedEvent event) { + final WingsOverloadFilter overloadFilter = event.getApplicationContext().getBean(WingsOverloadFilter.class); overloadFilter.setRequestCapacity(Integer.MIN_VALUE); log.warn("SlardarWebmvc shutting down, deny new request, current=" + overloadFilter.getRequestProcess()); - for (long breaks = 60 * 1000, step = 30; overloadFilter.getRequestProcess() > 0 && breaks > 0; ) { + for (long breaks = 20 * 1000, step = 100; overloadFilter.getRequestProcess() > 0 && breaks > 0; ) { try { Thread.sleep(step); // busy wait breaks -= step; diff --git a/wings/slardar/src/main/java/pro/fessional/wings/slardar/async/AsyncHelper.java b/wings/slardar/src/main/java/pro/fessional/wings/slardar/async/AsyncHelper.java index 8a9cdbd9d..497aadbcd 100644 --- a/wings/slardar/src/main/java/pro/fessional/wings/slardar/async/AsyncHelper.java +++ b/wings/slardar/src/main/java/pro/fessional/wings/slardar/async/AsyncHelper.java @@ -2,6 +2,7 @@ import com.alibaba.ttl.threadpool.TtlExecutors; import org.jetbrains.annotations.NotNull; +import org.springframework.beans.factory.DisposableBean; import org.springframework.boot.task.ThreadPoolTaskExecutorBuilder; import org.springframework.core.task.AsyncTaskExecutor; @@ -17,7 +18,7 @@ * @see TtlExecutors * @since 2024-05-13 */ -public class AsyncHelper { +public class AsyncHelper implements DisposableBean { private static Executor AsyncExecutor = null; private static AsyncTaskExecutor AppTaskExecutor = null; @@ -34,6 +35,11 @@ protected AsyncHelper(@NotNull Executor async, @NotNull AsyncTaskExecutor appTas helperPrepared = true; } + @Override + public void destroy() { + helperPrepared = false; + } + /** * whether this helper is prepared */ diff --git a/wings/slardar/src/main/java/pro/fessional/wings/slardar/async/TaskSchedulerHelper.java b/wings/slardar/src/main/java/pro/fessional/wings/slardar/async/TaskSchedulerHelper.java index 64c768c16..cea75834b 100644 --- a/wings/slardar/src/main/java/pro/fessional/wings/slardar/async/TaskSchedulerHelper.java +++ b/wings/slardar/src/main/java/pro/fessional/wings/slardar/async/TaskSchedulerHelper.java @@ -1,6 +1,7 @@ package pro.fessional.wings.slardar.async; import org.jetbrains.annotations.NotNull; +import org.springframework.beans.factory.DisposableBean; import org.springframework.boot.task.ThreadPoolTaskSchedulerBuilder; import org.springframework.scheduling.Trigger; import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler; @@ -14,7 +15,7 @@ * @author trydofor * @since 2022-12-05 */ -public class TaskSchedulerHelper { +public class TaskSchedulerHelper implements DisposableBean { private static ThreadPoolTaskScheduler FastScheduler; private static ThreadPoolTaskScheduler ScheduledScheduler; @@ -32,6 +33,10 @@ protected TaskSchedulerHelper(@NotNull ThreadPoolTaskScheduler fast, @NotNull Th helperPrepared = true; } + @Override + public void destroy() { + helperPrepared = false; + } /** * whether this helper is prepared diff --git a/wings/slardar/src/main/java/pro/fessional/wings/slardar/monitor/MonitorTask.java b/wings/slardar/src/main/java/pro/fessional/wings/slardar/monitor/MonitorTask.java index 6927d4657..87da82237 100644 --- a/wings/slardar/src/main/java/pro/fessional/wings/slardar/monitor/MonitorTask.java +++ b/wings/slardar/src/main/java/pro/fessional/wings/slardar/monitor/MonitorTask.java @@ -3,13 +3,14 @@ import lombok.Getter; import lombok.Setter; import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.DisposableBean; import org.springframework.beans.factory.InitializingBean; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.scheduling.annotation.Scheduled; +import pro.fessional.mirana.stat.JvmStat; import pro.fessional.wings.silencer.spring.help.ApplicationContextHelper; import pro.fessional.wings.slardar.context.Now; -import java.lang.management.ManagementFactory; import java.util.Collections; import java.util.LinkedHashMap; import java.util.List; @@ -21,7 +22,7 @@ */ @Slf4j @Setter @Getter -public class MonitorTask implements InitializingBean { +public class MonitorTask implements InitializingBean, DisposableBean { @Setter(onMethod_ = { @Autowired }) private List warnMetrics = Collections.emptyList(); @@ -75,7 +76,7 @@ public void report(Map> warns) { log.warn("the app name of report should NOT blank"); } - String jvm = ManagementFactory.getRuntimeMXBean().getName(); + String jvm = JvmStat.jvmName(); if (jvm != null) jvm = jvm.replace("@", "_"); for (WarnReport report : warnReports) { @@ -96,15 +97,19 @@ public void report(Map> warns) { } } + @Override + public void destroy() { + reportHook("shutting"); + } + @Override public void afterPropertiesSet() { - if (hookSelf) { - reportHook("started"); - Runtime.getRuntime().addShutdownHook(new Thread(() -> reportHook("shutting"))); - } + reportHook("started"); } private void reportHook(String key) { + if (!hookSelf) return; + try { WarnMetric.Warn wn = new WarnMetric.Warn(); wn.setType(WarnMetric.Type.Text); diff --git a/wings/slardar/src/main/java/pro/fessional/wings/slardar/notice/DingTalkNotice.java b/wings/slardar/src/main/java/pro/fessional/wings/slardar/notice/DingTalkNotice.java index 601a72cd8..339bf86dd 100644 --- a/wings/slardar/src/main/java/pro/fessional/wings/slardar/notice/DingTalkNotice.java +++ b/wings/slardar/src/main/java/pro/fessional/wings/slardar/notice/DingTalkNotice.java @@ -11,6 +11,7 @@ import org.jetbrains.annotations.Contract; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import org.springframework.beans.factory.DisposableBean; import org.springframework.beans.factory.InitializingBean; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; @@ -27,6 +28,7 @@ import java.util.Collections; import java.util.List; import java.util.concurrent.Executor; +import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import static java.nio.charset.StandardCharsets.UTF_8; @@ -42,7 +44,7 @@ */ @RequiredArgsConstructor @Slf4j -public class DingTalkNotice implements SmallNotice, InitializingBean { +public class DingTalkNotice implements SmallNotice, InitializingBean, DisposableBean { @NotNull private final Call.Factory callFactory; @@ -51,6 +53,7 @@ public class DingTalkNotice implements SmallNotice, InitializingBe @Setter(onMethod_ = { @Autowired(required = false), @Qualifier(DEFAULT_TASK_SCHEDULER_BEAN_NAME) }) private Executor executor; + private boolean innerExecutor = false; @Setter(onMethod_ = { @Autowired(required = false) }) @Getter @@ -174,7 +177,15 @@ public void emit(DingTalkConf config, String subject, String content) { public void afterPropertiesSet() { if (executor == null) { log.warn("should reuse autowired thread pool"); - executor = TtlExecutors.getTtlExecutor(Executors.newWorkStealingPool(2)); + executor = TtlExecutors.getTtlExecutorService(Executors.newWorkStealingPool(2)); + innerExecutor = true; + } + } + + @Override + public void destroy() { + if (innerExecutor && executor instanceof ExecutorService es) { + es.shutdown(); } } From e0330bc6b161aa2f52cd1961343e6de5283416e6 Mon Sep 17 00:00:00 2001 From: trydofor Date: Sun, 4 Aug 2024 11:23:24 +0800 Subject: [PATCH 37/51] =?UTF-8?q?=F0=9F=92=A5=20tinytask=20redefine=20miss?= =?UTF-8?q?/beat=20#284?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- WingsBoot.t.md | 1 + observe/docs | 2 +- .../autogen/tables/WinTaskDefineTable.java | 18 ++- .../autogen/tables/daos/WinTaskDefineDao.java | 40 +++--- .../tables/interfaces/IWinTaskDefine.java | 17 ++- .../autogen/tables/pojos/WinTaskDefine.java | 61 +++++---- .../tables/records/WinTaskDefineRecord.java | 24 ++-- .../wings/tiny/task/schedule/TinyTasker.java | 10 ++ .../tiny/task/schedule/conf/TaskerProp.java | 20 ++- .../service/impl/TinyTaskBeatServiceImpl.java | 8 +- .../service/impl/TinyTaskConfServiceImpl.java | 6 +- .../service/impl/TinyTaskExecServiceImpl.java | 34 +++-- .../wings-tinytask-define-79.properties | 10 +- .../03-task-tune/2021-10-26u02-task-tune.sql | 9 +- .../03-task-tune/2021-10-26v02-task-tune.sql | 7 +- .../06-task/2020-10-26v01-tiny_task.sql | 4 +- .../impl/TinyTaskBeatServiceImplTest.java | 19 ++- .../impl/TinyTaskExecServiceImplTest.java | 127 ++++++++++++++++++ 18 files changed, 294 insertions(+), 123 deletions(-) create mode 100644 radiant/tiny-task/src/test/java/pro/fessional/wings/tiny/task/service/impl/TinyTaskExecServiceImplTest.java diff --git a/WingsBoot.t.md b/WingsBoot.t.md index 401acb305..99e60d542 100644 --- a/WingsBoot.t.md +++ b/WingsBoot.t.md @@ -438,4 +438,5 @@ Use `t.md` as local [Test Management](https://www.jetbrains.com/help/idea/test-m * 15018 TinyTrackServiceTest: tiny track AOP service * 15019 TinyTrackServiceTest: tiny track Mvc controller * 15020 TinyTaskBeatServiceImplTest: beat mills cron/rate/idle +* 15021 TinyTaskExecServiceImplTest: calculate next schedule diff --git a/observe/docs b/observe/docs index fb007f207..b655b98bf 160000 --- a/observe/docs +++ b/observe/docs @@ -1 +1 @@ -Subproject commit fb007f207b8b0ea860a4b66c40453516e4fc8555 +Subproject commit b655b98bfadf5279196e39ed38f494ffe2e0bba0 diff --git a/radiant/tiny-task/src/main/java-gen/pro/fessional/wings/tiny/task/database/autogen/tables/WinTaskDefineTable.java b/radiant/tiny-task/src/main/java-gen/pro/fessional/wings/tiny/task/database/autogen/tables/WinTaskDefineTable.java index 750871153..88b4dc469 100644 --- a/radiant/tiny-task/src/main/java-gen/pro/fessional/wings/tiny/task/database/autogen/tables/WinTaskDefineTable.java +++ b/radiant/tiny-task/src/main/java-gen/pro/fessional/wings/tiny/task/database/autogen/tables/WinTaskDefineTable.java @@ -4,12 +4,6 @@ package pro.fessional.wings.tiny.task.database.autogen.tables; -import java.time.LocalDateTime; -import java.util.HashMap; -import java.util.Map; - -import javax.annotation.processing.Generated; - import org.jetbrains.annotations.NotNull; import org.jooq.Condition; import org.jooq.Field; @@ -23,7 +17,6 @@ import org.jooq.impl.Internal; import org.jooq.impl.SQLDataType; import org.jooq.impl.TableImpl; - import pro.fessional.wings.faceless.convention.EmptyValue; import pro.fessional.wings.faceless.database.jooq.WingsJournalTable; import pro.fessional.wings.faceless.service.journal.JournalService; @@ -31,6 +24,11 @@ import pro.fessional.wings.tiny.task.database.autogen.DefaultSchemaTinyTask; import pro.fessional.wings.tiny.task.database.autogen.tables.records.WinTaskDefineRecord; +import javax.annotation.processing.Generated; +import java.time.LocalDateTime; +import java.util.HashMap; +import java.util.Map; + /** * The table wings.win_task_define. @@ -39,7 +37,7 @@ value = { "https://www.jooq.org", "jOOQ version:3.18.9", - "schema version:2020102701" + "schema version:2020102801" }, comments = "This class is generated by jOOQ" ) @@ -185,12 +183,12 @@ public Class getRecordType() { /** * The column win_task_define.timing_miss. */ - public final TableField TimingMiss = createField(DSL.name("timing_miss"), SQLDataType.INTEGER.nullable(false).defaultValue(DSL.inline("0", SQLDataType.INTEGER)), this, ""); + public final TableField TimingMiss = createField(DSL.name("timing_miss"), SQLDataType.BIGINT.nullable(false).defaultValue(DSL.inline("0", SQLDataType.BIGINT)), this, ""); /** * The column win_task_define.timing_beat. */ - public final TableField TimingBeat = createField(DSL.name("timing_beat"), SQLDataType.INTEGER.nullable(false).defaultValue(DSL.inline("0", SQLDataType.INTEGER)), this, ""); + public final TableField TimingBeat = createField(DSL.name("timing_beat"), SQLDataType.BIGINT.nullable(false).defaultValue(DSL.inline("0", SQLDataType.BIGINT)), this, ""); /** * The column win_task_define.during_from. diff --git a/radiant/tiny-task/src/main/java-gen/pro/fessional/wings/tiny/task/database/autogen/tables/daos/WinTaskDefineDao.java b/radiant/tiny-task/src/main/java-gen/pro/fessional/wings/tiny/task/database/autogen/tables/daos/WinTaskDefineDao.java index 9eedfe84b..29f92e8b4 100644 --- a/radiant/tiny-task/src/main/java-gen/pro/fessional/wings/tiny/task/database/autogen/tables/daos/WinTaskDefineDao.java +++ b/radiant/tiny-task/src/main/java-gen/pro/fessional/wings/tiny/task/database/autogen/tables/daos/WinTaskDefineDao.java @@ -4,23 +4,21 @@ package pro.fessional.wings.tiny.task.database.autogen.tables.daos; -import java.time.LocalDateTime; -import java.util.Collection; -import java.util.List; -import java.util.Optional; - -import javax.annotation.processing.Generated; - import org.jooq.Configuration; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Repository; - import pro.fessional.wings.faceless.database.jooq.WingsJooqDaoJournalImpl; import pro.fessional.wings.silencer.spring.boot.ConditionalWingsEnabled; import pro.fessional.wings.tiny.task.database.autogen.tables.WinTaskDefineTable; import pro.fessional.wings.tiny.task.database.autogen.tables.pojos.WinTaskDefine; import pro.fessional.wings.tiny.task.database.autogen.tables.records.WinTaskDefineRecord; +import javax.annotation.processing.Generated; +import java.time.LocalDateTime; +import java.util.Collection; +import java.util.List; +import java.util.Optional; + /** * The table wings.win_task_define. @@ -29,7 +27,7 @@ value = { "https://www.jooq.org", "jOOQ version:3.18.9", - "schema version:2020102701" + "schema version:2020102801" }, comments = "This class is generated by jOOQ" ) @@ -878,32 +876,32 @@ public List fetchByTimingTuneLive(Collection v * Fetch records that have timing_miss BETWEEN lowerInclusive AND * upperInclusive */ - public List fetchRangeOfTimingMiss(Integer lowerInclusive, Integer upperInclusive) { + public List fetchRangeOfTimingMiss(Long lowerInclusive, Long upperInclusive) { return fetchRange(WinTaskDefineTable.WinTaskDefine.TimingMiss, lowerInclusive, upperInclusive); } - public List fetchRangeOfTimingMissLive(Integer lowerInclusive, Integer upperInclusive) { + public List fetchRangeOfTimingMissLive(Long lowerInclusive, Long upperInclusive) { return fetchRangeLive(WinTaskDefineTable.WinTaskDefine.TimingMiss, lowerInclusive, upperInclusive); } /** * Fetch records that have timing_miss IN (values) */ - public List fetchByTimingMiss(Integer... values) { + public List fetchByTimingMiss(Long... values) { return fetch(WinTaskDefineTable.WinTaskDefine.TimingMiss, values); } - public List fetchByTimingMiss(Collection values) { + public List fetchByTimingMiss(Collection values) { return fetch(WinTaskDefineTable.WinTaskDefine.TimingMiss, values); } - public List fetchByTimingMissLive(Integer... values) { + public List fetchByTimingMissLive(Long... values) { return fetchLive(WinTaskDefineTable.WinTaskDefine.TimingMiss, values); } - public List fetchByTimingMissLive(Collection values) { + public List fetchByTimingMissLive(Collection values) { return fetchLive(WinTaskDefineTable.WinTaskDefine.TimingMiss, values); } @@ -911,32 +909,32 @@ public List fetchByTimingMissLive(Collection v * Fetch records that have timing_beat BETWEEN lowerInclusive AND * upperInclusive */ - public List fetchRangeOfTimingBeat(Integer lowerInclusive, Integer upperInclusive) { + public List fetchRangeOfTimingBeat(Long lowerInclusive, Long upperInclusive) { return fetchRange(WinTaskDefineTable.WinTaskDefine.TimingBeat, lowerInclusive, upperInclusive); } - public List fetchRangeOfTimingBeatLive(Integer lowerInclusive, Integer upperInclusive) { + public List fetchRangeOfTimingBeatLive(Long lowerInclusive, Long upperInclusive) { return fetchRangeLive(WinTaskDefineTable.WinTaskDefine.TimingBeat, lowerInclusive, upperInclusive); } /** * Fetch records that have timing_beat IN (values) */ - public List fetchByTimingBeat(Integer... values) { + public List fetchByTimingBeat(Long... values) { return fetch(WinTaskDefineTable.WinTaskDefine.TimingBeat, values); } - public List fetchByTimingBeat(Collection values) { + public List fetchByTimingBeat(Collection values) { return fetch(WinTaskDefineTable.WinTaskDefine.TimingBeat, values); } - public List fetchByTimingBeatLive(Integer... values) { + public List fetchByTimingBeatLive(Long... values) { return fetchLive(WinTaskDefineTable.WinTaskDefine.TimingBeat, values); } - public List fetchByTimingBeatLive(Collection values) { + public List fetchByTimingBeatLive(Collection values) { return fetchLive(WinTaskDefineTable.WinTaskDefine.TimingBeat, values); } diff --git a/radiant/tiny-task/src/main/java-gen/pro/fessional/wings/tiny/task/database/autogen/tables/interfaces/IWinTaskDefine.java b/radiant/tiny-task/src/main/java-gen/pro/fessional/wings/tiny/task/database/autogen/tables/interfaces/IWinTaskDefine.java index 623b300ca..6a5e0d552 100644 --- a/radiant/tiny-task/src/main/java-gen/pro/fessional/wings/tiny/task/database/autogen/tables/interfaces/IWinTaskDefine.java +++ b/radiant/tiny-task/src/main/java-gen/pro/fessional/wings/tiny/task/database/autogen/tables/interfaces/IWinTaskDefine.java @@ -4,12 +4,11 @@ package pro.fessional.wings.tiny.task.database.autogen.tables.interfaces; -import java.io.Serializable; -import java.time.LocalDateTime; +import pro.fessional.wings.faceless.service.journal.JournalAware; import javax.annotation.processing.Generated; - -import pro.fessional.wings.faceless.service.journal.JournalAware; +import java.io.Serializable; +import java.time.LocalDateTime; /** @@ -19,7 +18,7 @@ value = { "https://www.jooq.org", "jOOQ version:3.18.9", - "schema version:2020102701" + "schema version:2020102801" }, comments = "This class is generated by jOOQ" ) @@ -269,22 +268,22 @@ public interface IWinTaskDefine extends JournalAware, Serializable { /** * Setter for win_task_define.timing_miss. */ - public void setTimingMiss(Integer value); + public void setTimingMiss(Long value); /** * Getter for win_task_define.timing_miss. */ - public Integer getTimingMiss(); + public Long getTimingMiss(); /** * Setter for win_task_define.timing_beat. */ - public void setTimingBeat(Integer value); + public void setTimingBeat(Long value); /** * Getter for win_task_define.timing_beat. */ - public Integer getTimingBeat(); + public Long getTimingBeat(); /** * Setter for win_task_define.during_from. diff --git a/radiant/tiny-task/src/main/java-gen/pro/fessional/wings/tiny/task/database/autogen/tables/pojos/WinTaskDefine.java b/radiant/tiny-task/src/main/java-gen/pro/fessional/wings/tiny/task/database/autogen/tables/pojos/WinTaskDefine.java index d097f11c9..a023c0b3e 100644 --- a/radiant/tiny-task/src/main/java-gen/pro/fessional/wings/tiny/task/database/autogen/tables/pojos/WinTaskDefine.java +++ b/radiant/tiny-task/src/main/java-gen/pro/fessional/wings/tiny/task/database/autogen/tables/pojos/WinTaskDefine.java @@ -4,16 +4,15 @@ package pro.fessional.wings.tiny.task.database.autogen.tables.pojos; +import pro.fessional.wings.tiny.task.database.autogen.tables.interfaces.IWinTaskDefine; + +import javax.annotation.processing.Generated; import java.beans.Transient; import java.time.LocalDateTime; import java.util.function.Predicate; import java.util.function.Supplier; import java.util.function.UnaryOperator; -import javax.annotation.processing.Generated; - -import pro.fessional.wings.tiny.task.database.autogen.tables.interfaces.IWinTaskDefine; - /** * The table wings.win_task_define. @@ -22,7 +21,7 @@ value = { "https://www.jooq.org", "jOOQ version:3.18.9", - "schema version:2020102701" + "schema version:2020102801" }, comments = "This class is generated by jOOQ" ) @@ -55,8 +54,8 @@ public class WinTaskDefine implements IWinTaskDefine { private Integer timingIdle; private Integer timingRate; private Integer timingTune; - private Integer timingMiss; - private Integer timingBeat; + private Long timingMiss; + private Long timingBeat; private String duringFrom; private String duringStop; private Integer duringExec; @@ -146,8 +145,8 @@ public WinTaskDefine( Integer timingIdle, Integer timingRate, Integer timingTune, - Integer timingMiss, - Integer timingBeat, + Long timingMiss, + Long timingBeat, String duringFrom, String duringStop, Integer duringExec, @@ -2133,7 +2132,7 @@ public void setTimingTuneIf(UnaryOperator timingTune) { * Getter for win_task_define.timing_miss. */ @Override - public Integer getTimingMiss() { + public Long getTimingMiss() { return this.timingMiss; } @@ -2141,38 +2140,38 @@ public Integer getTimingMiss() { * Setter for win_task_define.timing_miss. */ @Override - public void setTimingMiss(Integer timingMiss) { + public void setTimingMiss(Long timingMiss) { this.timingMiss = timingMiss; } @Transient - public void setTimingMissIf(Integer timingMiss, boolean bool) { + public void setTimingMissIf(Long timingMiss, boolean bool) { if (bool) { this.timingMiss = timingMiss; } } @Transient - public void setTimingMissIf(Supplier timingMiss, boolean bool) { + public void setTimingMissIf(Supplier timingMiss, boolean bool) { if (bool) { this.timingMiss = timingMiss.get(); } } @Transient - public void setTimingMissIf(Integer timingMiss, Predicate bool) { + public void setTimingMissIf(Long timingMiss, Predicate bool) { if (bool.test(timingMiss)) { this.timingMiss = timingMiss; } } @Transient - public void setTimingMissIf(Integer timingMiss, Predicate bool, Supplier... timingMisss) { + public void setTimingMissIf(Long timingMiss, Predicate bool, Supplier... timingMisss) { if (bool.test(timingMiss)) { this.timingMiss = timingMiss; return; } - for (Supplier supplier : timingMisss) { + for (Supplier supplier : timingMisss) { timingMiss = supplier.get(); if (bool.test(timingMiss)) { this.timingMiss = timingMiss; @@ -2182,19 +2181,19 @@ public void setTimingMissIf(Integer timingMiss, Predicate bool, Supplie } @Transient - public void setTimingMissIfNot(Integer timingMiss, Predicate bool) { + public void setTimingMissIfNot(Long timingMiss, Predicate bool) { if (!bool.test(timingMiss)) { this.timingMiss = timingMiss; } } @Transient - public void setTimingMissIfNot(Integer timingMiss, Predicate bool, Supplier... timingMisss) { + public void setTimingMissIfNot(Long timingMiss, Predicate bool, Supplier... timingMisss) { if (!bool.test(timingMiss)) { this.timingMiss = timingMiss; return; } - for (Supplier supplier : timingMisss) { + for (Supplier supplier : timingMisss) { timingMiss = supplier.get(); if (!bool.test(timingMiss)) { this.timingMiss = timingMiss; @@ -2204,7 +2203,7 @@ public void setTimingMissIfNot(Integer timingMiss, Predicate bool, Supp } @Transient - public void setTimingMissIf(UnaryOperator timingMiss) { + public void setTimingMissIf(UnaryOperator timingMiss) { this.timingMiss = timingMiss.apply(this.timingMiss); } @@ -2213,7 +2212,7 @@ public void setTimingMissIf(UnaryOperator timingMiss) { * Getter for win_task_define.timing_beat. */ @Override - public Integer getTimingBeat() { + public Long getTimingBeat() { return this.timingBeat; } @@ -2221,38 +2220,38 @@ public Integer getTimingBeat() { * Setter for win_task_define.timing_beat. */ @Override - public void setTimingBeat(Integer timingBeat) { + public void setTimingBeat(Long timingBeat) { this.timingBeat = timingBeat; } @Transient - public void setTimingBeatIf(Integer timingBeat, boolean bool) { + public void setTimingBeatIf(Long timingBeat, boolean bool) { if (bool) { this.timingBeat = timingBeat; } } @Transient - public void setTimingBeatIf(Supplier timingBeat, boolean bool) { + public void setTimingBeatIf(Supplier timingBeat, boolean bool) { if (bool) { this.timingBeat = timingBeat.get(); } } @Transient - public void setTimingBeatIf(Integer timingBeat, Predicate bool) { + public void setTimingBeatIf(Long timingBeat, Predicate bool) { if (bool.test(timingBeat)) { this.timingBeat = timingBeat; } } @Transient - public void setTimingBeatIf(Integer timingBeat, Predicate bool, Supplier... timingBeats) { + public void setTimingBeatIf(Long timingBeat, Predicate bool, Supplier... timingBeats) { if (bool.test(timingBeat)) { this.timingBeat = timingBeat; return; } - for (Supplier supplier : timingBeats) { + for (Supplier supplier : timingBeats) { timingBeat = supplier.get(); if (bool.test(timingBeat)) { this.timingBeat = timingBeat; @@ -2262,19 +2261,19 @@ public void setTimingBeatIf(Integer timingBeat, Predicate bool, Supplie } @Transient - public void setTimingBeatIfNot(Integer timingBeat, Predicate bool) { + public void setTimingBeatIfNot(Long timingBeat, Predicate bool) { if (!bool.test(timingBeat)) { this.timingBeat = timingBeat; } } @Transient - public void setTimingBeatIfNot(Integer timingBeat, Predicate bool, Supplier... timingBeats) { + public void setTimingBeatIfNot(Long timingBeat, Predicate bool, Supplier... timingBeats) { if (!bool.test(timingBeat)) { this.timingBeat = timingBeat; return; } - for (Supplier supplier : timingBeats) { + for (Supplier supplier : timingBeats) { timingBeat = supplier.get(); if (!bool.test(timingBeat)) { this.timingBeat = timingBeat; @@ -2284,7 +2283,7 @@ public void setTimingBeatIfNot(Integer timingBeat, Predicate bool, Supp } @Transient - public void setTimingBeatIf(UnaryOperator timingBeat) { + public void setTimingBeatIf(UnaryOperator timingBeat) { this.timingBeat = timingBeat.apply(this.timingBeat); } diff --git a/radiant/tiny-task/src/main/java-gen/pro/fessional/wings/tiny/task/database/autogen/tables/records/WinTaskDefineRecord.java b/radiant/tiny-task/src/main/java-gen/pro/fessional/wings/tiny/task/database/autogen/tables/records/WinTaskDefineRecord.java index a960bb87d..2b77e4ae4 100644 --- a/radiant/tiny-task/src/main/java-gen/pro/fessional/wings/tiny/task/database/autogen/tables/records/WinTaskDefineRecord.java +++ b/radiant/tiny-task/src/main/java-gen/pro/fessional/wings/tiny/task/database/autogen/tables/records/WinTaskDefineRecord.java @@ -4,17 +4,15 @@ package pro.fessional.wings.tiny.task.database.autogen.tables.records; -import java.time.LocalDateTime; - -import javax.annotation.processing.Generated; - import org.jooq.Record1; import org.jooq.impl.UpdatableRecordImpl; - import pro.fessional.wings.tiny.task.database.autogen.tables.WinTaskDefineTable; import pro.fessional.wings.tiny.task.database.autogen.tables.interfaces.IWinTaskDefine; import pro.fessional.wings.tiny.task.database.autogen.tables.pojos.WinTaskDefine; +import javax.annotation.processing.Generated; +import java.time.LocalDateTime; + /** * The table wings.win_task_define. @@ -23,7 +21,7 @@ value = { "https://www.jooq.org", "jOOQ version:3.18.9", - "schema version:2020102701" + "schema version:2020102801" }, comments = "This class is generated by jOOQ" ) @@ -420,7 +418,7 @@ public Integer getTimingTune() { * Setter for win_task_define.timing_miss. */ @Override - public void setTimingMiss(Integer value) { + public void setTimingMiss(Long value) { set(24, value); } @@ -428,15 +426,15 @@ public void setTimingMiss(Integer value) { * Getter for win_task_define.timing_miss. */ @Override - public Integer getTimingMiss() { - return (Integer) get(24); + public Long getTimingMiss() { + return (Long) get(24); } /** * Setter for win_task_define.timing_beat. */ @Override - public void setTimingBeat(Integer value) { + public void setTimingBeat(Long value) { set(25, value); } @@ -444,8 +442,8 @@ public void setTimingBeat(Integer value) { * Getter for win_task_define.timing_beat. */ @Override - public Integer getTimingBeat() { - return (Integer) get(25); + public Long getTimingBeat() { + return (Long) get(25); } /** @@ -784,7 +782,7 @@ public WinTaskDefineRecord() { /** * Create a detached, initialised WinTaskDefineRecord */ - public WinTaskDefineRecord(Long id, LocalDateTime createDt, LocalDateTime modifyDt, LocalDateTime deleteDt, Long commitId, String propkey, Boolean enabled, Boolean autorun, Integer version, String taskerBean, String taskerPara, String taskerName, Boolean taskerFast, String taskerApps, String taskerRuns, String noticeBean, String noticeWhen, String noticeConf, String timingZone, String timingType, String timingCron, Integer timingIdle, Integer timingRate, Integer timingTune, Integer timingMiss, Integer timingBeat, String duringFrom, String duringStop, Integer duringExec, Integer duringFail, Integer duringDone, Integer duringBoot, Integer resultKeep, LocalDateTime lastExec, LocalDateTime lastExit, Boolean lastFail, LocalDateTime nextExec, Integer nextLock, Integer durFail, Integer sumExec, Integer sumFail, Integer sumDone) { + public WinTaskDefineRecord(Long id, LocalDateTime createDt, LocalDateTime modifyDt, LocalDateTime deleteDt, Long commitId, String propkey, Boolean enabled, Boolean autorun, Integer version, String taskerBean, String taskerPara, String taskerName, Boolean taskerFast, String taskerApps, String taskerRuns, String noticeBean, String noticeWhen, String noticeConf, String timingZone, String timingType, String timingCron, Integer timingIdle, Integer timingRate, Integer timingTune, Long timingMiss, Long timingBeat, String duringFrom, String duringStop, Integer duringExec, Integer duringFail, Integer duringDone, Integer duringBoot, Integer resultKeep, LocalDateTime lastExec, LocalDateTime lastExit, Boolean lastFail, LocalDateTime nextExec, Integer nextLock, Integer durFail, Integer sumExec, Integer sumFail, Integer sumDone) { super(WinTaskDefineTable.WinTaskDefine); setId(id); diff --git a/radiant/tiny-task/src/main/java/pro/fessional/wings/tiny/task/schedule/TinyTasker.java b/radiant/tiny-task/src/main/java/pro/fessional/wings/tiny/task/schedule/TinyTasker.java index f5b447d2c..88df57a45 100644 --- a/radiant/tiny-task/src/main/java/pro/fessional/wings/tiny/task/schedule/TinyTasker.java +++ b/radiant/tiny-task/src/main/java/pro/fessional/wings/tiny/task/schedule/TinyTasker.java @@ -77,6 +77,16 @@ */ int tune() default 0; + /** + *
+     * Within how many seconds of a misfire, execution is required.
+     * * `<0` - disable execution
+     * * `0` - execute if N0 < now <= N0 + (N1-N0) * 25% < N1
+     * * `>0` - execute if N1 < now <= N1 + miss
+     * 
+ */ + int miss() default 0; + /** * Adding to a SpringBean can be auto config by Wings at startup. */ diff --git a/radiant/tiny-task/src/main/java/pro/fessional/wings/tiny/task/schedule/conf/TaskerProp.java b/radiant/tiny-task/src/main/java/pro/fessional/wings/tiny/task/schedule/conf/TaskerProp.java index 4ef31c3eb..7ba2c3d09 100644 --- a/radiant/tiny-task/src/main/java/pro/fessional/wings/tiny/task/schedule/conf/TaskerProp.java +++ b/radiant/tiny-task/src/main/java/pro/fessional/wings/tiny/task/schedule/conf/TaskerProp.java @@ -179,21 +179,29 @@ public boolean notTimingTune() { } /** - * Within how many seconds of a misfire, execution is required, - * 0 means no execution. not use Default config. + *
+     * Within how many seconds of a misfire, execution is required, not use Default config.
+     * * `<0` - execute as `0` if now + miss * 1000 >= 0
+     * * `0` - execute if N0 < now <= N0 + (N1-N0) * 25% < N1
+     * * `>0` - execute if N1 < now <= N1 + miss * 1000
+     * 
*/ - protected int timingMiss = 0; + protected long timingMiss = 0; + + public boolean notTimingMiss() { + return timingMiss == 0; + } /** *
      * the interval seconds of heartbeat and health-check, not use Default config.
      * it is considered as an exception if the last_exec is more than 2 heartbeats away from now.
-     * * `<0` - disable check
-     * * `0` - auto calculate, when cron, calc next_exec from last_exec, others, max rate and idle
+     * * `<0` - calculate as `0` if now + beat * 1000 >= 0
+     * * `0` - calculate, when cron, calc next_exec from last_exec, others, max rate and idle
      * * `>0` - fixed positive seconds
      * 
*/ - protected int timingBeat = 0; + protected long timingBeat = 0; /** * schedule start datetime at timingZone, in yyyy-MM-dd HH:mm:ss format, * 0 means disable, not use Default config. diff --git a/radiant/tiny-task/src/main/java/pro/fessional/wings/tiny/task/service/impl/TinyTaskBeatServiceImpl.java b/radiant/tiny-task/src/main/java/pro/fessional/wings/tiny/task/service/impl/TinyTaskBeatServiceImpl.java index 5c9441e2c..1bc8292c8 100644 --- a/radiant/tiny-task/src/main/java/pro/fessional/wings/tiny/task/service/impl/TinyTaskBeatServiceImpl.java +++ b/radiant/tiny-task/src/main/java/pro/fessional/wings/tiny/task/service/impl/TinyTaskBeatServiceImpl.java @@ -106,7 +106,7 @@ public String checkHealth() { .select(td.Id, td.TaskerName, td.LastExec, td.TimingBeat, td.TimingRate, td.TimingIdle, td.TimingTune, td.TimingCron, td.TimingZone) .from(td) - .where(td.Enabled.eq(Boolean.TRUE).and(td.TimingBeat.ge(0))) + .where(td.Enabled.eq(Boolean.TRUE)) .fetch() .into(WinTaskDefine.class); @@ -133,8 +133,8 @@ public String checkHealth() { warmed = true; return mis == null || mis.isEmpty() ? null - : "misfired tiny-task id@name, beat=-1 to skip\n" - + mis; + : "misfired tiny-task id@name\n" + + mis + "\nUPDATE win_task_define SET timing_beat = -UNIX_TIMESTAMP(now() + INTERVAL 1 hour ) WHERE id IN (...); to skip checking for 1 hour"; } protected long calcBeatMills(WinTaskDefine td, long now) { @@ -145,7 +145,7 @@ protected long calcBeatMills(WinTaskDefine td, long now) { } final long beat = td.getTimingBeat(); - if (beat < 0) return beat; + if (beat < 0 && now + beat * 1000 < 0) return beat; final long lastExecSys = DateLocaling.sysEpoch(lastExec); if (beat > 0) return lastExecSys + beat * 1000L; diff --git a/radiant/tiny-task/src/main/java/pro/fessional/wings/tiny/task/service/impl/TinyTaskConfServiceImpl.java b/radiant/tiny-task/src/main/java/pro/fessional/wings/tiny/task/service/impl/TinyTaskConfServiceImpl.java index 4c8e7a7ca..09b6fc45f 100644 --- a/radiant/tiny-task/src/main/java/pro/fessional/wings/tiny/task/service/impl/TinyTaskConfServiceImpl.java +++ b/radiant/tiny-task/src/main/java/pro/fessional/wings/tiny/task/service/impl/TinyTaskConfServiceImpl.java @@ -105,6 +105,7 @@ private TaskerProp property(@NotNull String key, @NotNull TinyTasker anno) { rp.setTimingIdle(anno.idle()); rp.setTimingRate(anno.rate()); rp.setTimingTune(anno.tune()); + rp.setTimingMiss(anno.miss()); log.debug("no prop, use annotation, key={}", key); } else { @@ -113,6 +114,7 @@ private TaskerProp property(@NotNull String key, @NotNull TinyTasker anno) { rp.setTimingIdle(pp.notTimingIdle() ? anno.idle() : pp.getTimingIdle()); rp.setTimingRate(pp.notTimingRate() ? anno.rate() : pp.getTimingRate()); rp.setTimingTune(pp.notTimingTune() ? anno.tune() : pp.getTimingTune()); + rp.setTimingMiss(pp.notTimingMiss() ? anno.miss() : pp.getTimingMiss()); } // not default @@ -125,7 +127,7 @@ private TaskerProp property(@NotNull String key, @NotNull TinyTasker anno) { rp.setTaskerName(pp.getTaskerName()); rp.setTaskerFast(pp.isTaskerFast()); // - rp.setTimingMiss(pp.getTimingMiss()); + rp.setTimingBeat(pp.getTimingBeat()); rp.setDuringFrom(pp.getDuringFrom()); rp.setDuringStop(pp.getDuringStop()); @@ -374,8 +376,8 @@ private WinTaskDefine genWinTaskDefine(TaskerProp prop, String key) { wtd.setTimingIdle(prop.getTimingIdle()); wtd.setTimingRate(prop.getTimingRate()); wtd.setTimingTune(prop.getTimingTune()); - wtd.setTimingMiss(prop.getTimingMiss()); + wtd.setTimingBeat(prop.getTimingBeat()); wtd.setDuringFrom(prop.getDuringFrom()); wtd.setDuringStop(prop.getDuringStop()); diff --git a/radiant/tiny-task/src/main/java/pro/fessional/wings/tiny/task/service/impl/TinyTaskExecServiceImpl.java b/radiant/tiny-task/src/main/java/pro/fessional/wings/tiny/task/service/impl/TinyTaskExecServiceImpl.java index b770117b5..73f306230 100644 --- a/radiant/tiny-task/src/main/java/pro/fessional/wings/tiny/task/service/impl/TinyTaskExecServiceImpl.java +++ b/radiant/tiny-task/src/main/java/pro/fessional/wings/tiny/task/service/impl/TinyTaskExecServiceImpl.java @@ -244,7 +244,7 @@ private boolean relaunch(long id) { return false; } - final long next = calcNextExec(td); + final long next = calcNextExec(td, ThreadNow.millis()); if (next < 0) return false; // temp save before schedule to avoid kill @@ -543,11 +543,10 @@ private boolean canRelaunch(long id, long doneTms, long failTms, WinTaskDefine t return true; } - private long calcNextExec(WinTaskDefine td) { + protected long calcNextExec(WinTaskDefine td, long now) { final String zid = td.getTimingZone(); final ZoneId zone = StringUtils.isEmpty(zid) ? ThreadNow.sysZoneId() : ZoneId.of(zid); - final long now = ThreadNow.millis(); if (notRanged(td, zone, now)) return -1; final Long id = td.getId(); @@ -555,15 +554,18 @@ private long calcNextExec(WinTaskDefine td) { final long timingMiss = td.getTimingMiss() * 1000L; // Planned, program was killed before execution ends final long nextMs = DateLocaling.sysEpoch(td.getNextExec()); - if (nextMs + timingMiss >= now) { + if (timingMiss >= 0 && nextMs + timingMiss >= now) { log.info("launch misfire tiny-task, id={}, prop={}", id, td.getPropkey()); return nextMs; } + final boolean zeroMiss = timingMiss <= 0 && timingMiss + now >= 0; + final Trigger trigger = makeTrigger(td, zone); final SimpleTriggerContext context = makeContext(td, zone, now); long nextExec = -1; + long n0 = -1; while (true) { Instant next = trigger.nextExecution(context); if (next == null) { @@ -571,22 +573,28 @@ private long calcNextExec(WinTaskDefine td) { break; } - final long nxt = next.toEpochMilli(); - if (nxt < now) { - if (timingMiss > 0 && nxt + timingMiss >= now) { - log.info("launch tiny-task for misfire={}, id={}, prop={}", next, id, td.getPropkey()); - nextExec = nxt; + final long n1 = next.toEpochMilli(); + if (n1 >= now) { + if (zeroMiss && n0 > 0 && now <= n0 + ((n1 - n0) * 25 / 100)) { + log.info("launch tiny-task for miss=0, next={}, id={}, prop={}", next, id, td.getPropkey()); + nextExec = n0; break; } else { - context.update(next, next, next); + log.info("launch tiny-task for next={}, id={}, prop={}", next, id, td.getPropkey()); + nextExec = n1; + break; } } - else { - log.info("launch tiny-task for next={}, id={}, prop={}", next, id, td.getPropkey()); - nextExec = nxt; + + if (timingMiss > 0 && now <= n1 + timingMiss) { + log.info("launch tiny-task for miss={}, next={}, id={}, prop={}", timingMiss, next, id, td.getPropkey()); + nextExec = n1; break; } + + context.update(next, next, next); + n0 = n1; } if (nextExec < 0) return -1; diff --git a/radiant/tiny-task/src/main/resources/wings-conf/wings-tinytask-define-79.properties b/radiant/tiny-task/src/main/resources/wings-conf/wings-tinytask-define-79.properties index 90dfd3fa5..69393f7a8 100644 --- a/radiant/tiny-task/src/main/resources/wings-conf/wings-tinytask-define-79.properties +++ b/radiant/tiny-task/src/main/resources/wings-conf/wings-tinytask-define-79.properties @@ -70,14 +70,16 @@ wings.tiny.task.define[default].timing-type=cron ## * cron - each time #wings.tiny.task.define[default].timing-tune=0 -## Within how many seconds of a misfire, execution is required, -## 0 means no execution. not use Default config. +## Within how many seconds of a misfire, execution is required, not use Default config. +## * `<0` - execute as `0` if now + miss * 1000 >= 0 +## * `0` - execute if N0 < now <= N0 + (N1-N0) * 25% < N1 +## * `>0` - execute if N1 < now <= N1 + miss * 1000 #wings.tiny.task.define[default].timing-miss=0 ## the interval seconds of heartbeat and health-check, not use Default config. ## it is considered as an exception if the last_exec is more than 2 heartbeats away from now. -## * `<0` - disable check -## * `0` - auto calculate, when cron, calc next_exec from last_exec, others, max rate and idle +## * `<0` - calculate as `0` if now + beat * 1000 >= 0 +## * `0` - calculate, when cron, calc next_exec from last_exec, others, max rate and idle ## * `>0` - fixed positive seconds #wings.tiny.task.define[default].timing-beat=0 diff --git a/radiant/tiny-task/src/main/resources/wings-flywave/branch/somefix/03-task-tune/2021-10-26u02-task-tune.sql b/radiant/tiny-task/src/main/resources/wings-flywave/branch/somefix/03-task-tune/2021-10-26u02-task-tune.sql index 0051cb419..e0c9545bb 100644 --- a/radiant/tiny-task/src/main/resources/wings-flywave/branch/somefix/03-task-tune/2021-10-26u02-task-tune.sql +++ b/radiant/tiny-task/src/main/resources/wings-flywave/branch/somefix/03-task-tune/2021-10-26u02-task-tune.sql @@ -1,4 +1,4 @@ --- win_task_define +-- https://github.com/trydofor/professional-wings/issues/256 UPDATE `win_task_define` SET timing_tune = last_fail WHERE TRUE; @@ -6,6 +6,8 @@ WHERE TRUE; ALTER TABLE `win_task_define` DROP COLUMN `last_fail`, CHANGE COLUMN `last_exit` `last_done` DATETIME(3) NOT NULL DEFAULT '1000-01-01' COMMENT 'previous success (sys)', + CHANGE COLUMN `timing_miss` `timing_miss` INT NOT NULL DEFAULT '0' COMMENT 'within how many seconds of a misfire', + CHANGE COLUMN `timing_beat` `timing_beat` INT NOT NULL DEFAULT '0' COMMENT 'interval seconds of heartbeat, default auto calc', ADD COLUMN `last_fail` DATETIME(3) NOT NULL DEFAULT '1000-01-01' COMMENT 'previous fail (sys)' AFTER last_exec; UPDATE `win_task_define` @@ -30,4 +32,9 @@ WHERE exit_fail = 1; ALTER TABLE `win_task_result` DROP COLUMN `exit_fail`; +-- https://github.com/trydofor/professional-wings/issues/284 +ALTER TABLE `win_task_define` + CHANGE COLUMN `timing_miss` `timing_miss` INT NOT NULL DEFAULT '0' COMMENT 'within how many seconds of a misfire', + CHANGE COLUMN `timing_beat` `timing_beat` INT NOT NULL DEFAULT '0' COMMENT 'interval seconds of heartbeat, default auto calc'; + -- CALL FLYWAVE('2021-10-26u02-task-tune.sql'); \ No newline at end of file diff --git a/radiant/tiny-task/src/main/resources/wings-flywave/branch/somefix/03-task-tune/2021-10-26v02-task-tune.sql b/radiant/tiny-task/src/main/resources/wings-flywave/branch/somefix/03-task-tune/2021-10-26v02-task-tune.sql index a5d3386fb..be1e4ead8 100644 --- a/radiant/tiny-task/src/main/resources/wings-flywave/branch/somefix/03-task-tune/2021-10-26v02-task-tune.sql +++ b/radiant/tiny-task/src/main/resources/wings-flywave/branch/somefix/03-task-tune/2021-10-26v02-task-tune.sql @@ -1,4 +1,4 @@ --- win_task_define +-- https://github.com/trydofor/professional-wings/issues/256 ALTER TABLE `win_task_define` ADD COLUMN `timing_tune` INT NOT NULL DEFAULT '0' COMMENT 'execute before or after tune (seconds)' AFTER `timing_rate`, CHANGE COLUMN `last_done` `last_exit` DATETIME(3) NOT NULL DEFAULT '1000-01-01' COMMENT 'previous done/fail (sys)'; @@ -36,4 +36,9 @@ WHERE time_fail > '2000-01-01'; ALTER TABLE `win_task_result` DROP COLUMN `time_fail`; +-- https://github.com/trydofor/professional-wings/issues/284 +ALTER TABLE `win_task_define` + CHANGE COLUMN `timing_miss` `timing_miss` BIGINT NOT NULL DEFAULT '0' COMMENT 'within how many seconds of a misfire, default auto calc', + CHANGE COLUMN `timing_beat` `timing_beat` BIGINT NOT NULL DEFAULT '0' COMMENT 'interval seconds of heartbeat, default auto calc'; + -- CALL FLYWAVE('2021-10-26v02-task-tune.sql'); \ No newline at end of file diff --git a/radiant/tiny-task/src/main/resources/wings-flywave/master/06-task/2020-10-26v01-tiny_task.sql b/radiant/tiny-task/src/main/resources/wings-flywave/master/06-task/2020-10-26v01-tiny_task.sql index 5dbcd1884..eaab3f58d 100644 --- a/radiant/tiny-task/src/main/resources/wings-flywave/master/06-task/2020-10-26v01-tiny_task.sql +++ b/radiant/tiny-task/src/main/resources/wings-flywave/master/06-task/2020-10-26v01-tiny_task.sql @@ -23,8 +23,8 @@ CREATE TABLE `win_task_define` ( `timing_idle` INT NOT NULL DEFAULT '0' COMMENT 'fixed idle interval (seconds)', `timing_rate` INT NOT NULL DEFAULT '0' COMMENT 'fixed frequency interval (seconds)', `timing_tune` INT NOT NULL DEFAULT '0' COMMENT 'execute before or after tune (seconds)', - `timing_miss` INT NOT NULL DEFAULT '0' COMMENT 'within how many seconds of a misfire', - `timing_beat` INT NOT NULL DEFAULT '0' COMMENT 'interval seconds of heartbeat, default auto calc', + `timing_miss` BIGINT NOT NULL DEFAULT '0' COMMENT 'within how many seconds of a misfire, default auto calc', + `timing_beat` BIGINT NOT NULL DEFAULT '0' COMMENT 'interval seconds of heartbeat, default auto calc', `during_from` VARCHAR(20) NOT NULL DEFAULT '' COMMENT 'schedule start datetime at timingZone, yyyy-MM-dd HH:mm:ss', `during_stop` VARCHAR(20) NOT NULL DEFAULT '' COMMENT 'schedule stop datetime at timingZone, yyyy-MM-dd HH:mm:ss', `during_exec` INT NOT NULL DEFAULT '0' COMMENT 'stop schedule after how many total executions', diff --git a/radiant/tiny-task/src/test/java/pro/fessional/wings/tiny/task/service/impl/TinyTaskBeatServiceImplTest.java b/radiant/tiny-task/src/test/java/pro/fessional/wings/tiny/task/service/impl/TinyTaskBeatServiceImplTest.java index 85c0b78c8..0df13b1cc 100644 --- a/radiant/tiny-task/src/test/java/pro/fessional/wings/tiny/task/service/impl/TinyTaskBeatServiceImplTest.java +++ b/radiant/tiny-task/src/test/java/pro/fessional/wings/tiny/task/service/impl/TinyTaskBeatServiceImplTest.java @@ -3,12 +3,11 @@ import io.qameta.allure.TmsLink; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; +import pro.fessional.mirana.time.DateLocaling; import pro.fessional.mirana.time.ThreadNow; import pro.fessional.wings.tiny.task.database.autogen.tables.pojos.WinTaskDefine; -import java.time.Instant; import java.time.LocalDateTime; -import java.time.ZoneId; /** * @author trydofor @@ -22,21 +21,31 @@ void calcBeatMills() { TinyTaskBeatServiceImpl bs = new TinyTaskBeatServiceImpl(); WinTaskDefine td = new WinTaskDefine(); td.setLastExec(LocalDateTime.parse("2024-07-31T02:01:00")); - td.setTimingBeat(0); + td.setTimingBeat(0L); td.setTimingCron("0 1 2 * * *"); td.setTimingZone(""); long now = ThreadNow.millis(); long next = bs.calcBeatMills(td, now); - LocalDateTime ldt = LocalDateTime.ofInstant(Instant.ofEpochMilli(next), ZoneId.systemDefault()); + LocalDateTime ldt = DateLocaling.sysLdt(next); LocalDateTime nxt2 = LocalDateTime.parse("2024-08-02T02:00:00"); Assertions.assertTrue(ldt.isAfter(nxt2), ldt + " > " + nxt2); - td.setLastExec(LocalDateTime.ofInstant(Instant.ofEpochMilli(now), ZoneId.systemDefault())); + td.setLastExec(DateLocaling.sysLdt(now)); td.setTimingRate(60); td.setTimingIdle(50); td.setTimingCron(""); long nr2 = bs.calcBeatMills(td, now); long df = (nr2 - now) / 1000; Assertions.assertTrue(df > 120 - 2, "s=" + df); + + long nb3 = -now/1000 - 10; + td.setTimingBeat(nb3); + long nr3 = bs.calcBeatMills(td, now); + Assertions.assertEquals(nb3, nr3); + + long nb4 = -now/1000 + 10; + td.setTimingBeat(nb4); + long nr4 = bs.calcBeatMills(td, now); + Assertions.assertEquals(nr2, nr4); // same as nr2 } } \ No newline at end of file diff --git a/radiant/tiny-task/src/test/java/pro/fessional/wings/tiny/task/service/impl/TinyTaskExecServiceImplTest.java b/radiant/tiny-task/src/test/java/pro/fessional/wings/tiny/task/service/impl/TinyTaskExecServiceImplTest.java new file mode 100644 index 000000000..98895477b --- /dev/null +++ b/radiant/tiny-task/src/test/java/pro/fessional/wings/tiny/task/service/impl/TinyTaskExecServiceImplTest.java @@ -0,0 +1,127 @@ +package pro.fessional.wings.tiny.task.service.impl; + +import io.qameta.allure.TmsLink; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import pro.fessional.mirana.time.DateLocaling; +import pro.fessional.wings.faceless.convention.EmptyValue; +import pro.fessional.wings.tiny.task.database.autogen.tables.pojos.WinTaskDefine; + +import java.time.LocalDateTime; + +/** + * @author trydofor + * @since 2024-08-03 + */ +class TinyTaskExecServiceImplTest { + + @Test + @TmsLink("C15021") + void calcNextExec() { + TinyTaskExecServiceImpl impl = new TinyTaskExecServiceImpl(); + WinTaskDefine td = new WinTaskDefine(); + td.setId(1L); + td.setDuringExec(0); + td.setDuringFail(0); + td.setDuringDone(0); + + td.setTimingMiss(0L); + td.setTimingTune(0); + LocalDateTime last = LocalDateTime.of(2024, 8, 1, 8, 1); + td.setLastExec(last); + td.setLastExit(last.withSecond(30)); + + + td.setTimingCron("0 21 * * * *"); + td.setTimingIdle(0); + td.setTimingRate(0); + td.setTimingZone(""); + + { + // killed before next + td.setNextExec(last.withHour(9)); // 2024-08-01 09:01 + long now = DateLocaling.sysEpoch(last.withMinute(20)); // 2024-08-01 08:20 + long next = impl.calcNextExec(td, now); + LocalDateTime nxt = DateLocaling.sysLdt(next); + Assertions.assertEquals(LocalDateTime.of(2024, 8, 1, 9, 1), nxt); + } + { + // empty next + td.setNextExec(EmptyValue.DATE_TIME); + long now = DateLocaling.sysEpoch(last.withMinute(20)); // 2024-08-01 08:20 + long next = impl.calcNextExec(td, now); + LocalDateTime nxt = DateLocaling.sysLdt(next); + Assertions.assertEquals(LocalDateTime.of(2024, 8, 1, 8, 21), nxt); + } + { + // 08:01___mis9___mis10___mis11 + //N0= 10:21 + //Now + //Nx= 10:36 = 10:21 + :15 (25% N1-N0) + //N1= 11:21 + td.setNextExec(last.withHour(9)); // 2024-08-01 09:01 + long now = DateLocaling.sysEpoch(last.withHour(10).withMinute(36)); // 2024-08-02 11:01 + long next = impl.calcNextExec(td, now); + LocalDateTime nxt = DateLocaling.sysLdt(next); + Assertions.assertEquals(LocalDateTime.of(2024, 8, 1, 10, 21), nxt); + } + { + // 08:01___mis9___mis10___mis11 + //N0= 10:21 + //Nx= 10:36 = 10:21 + :15 (25% N1-N0) + //Now + //N1= 11:21 + td.setNextExec(last.withHour(9)); // 2024-08-01 09:01 + long now = DateLocaling.sysEpoch(last.withHour(10).withMinute(37)); // 2024-08-02 11:01 + long next = impl.calcNextExec(td, now); + LocalDateTime nxt = DateLocaling.sysLdt(next); + Assertions.assertEquals(LocalDateTime.of(2024, 8, 1, 11, 21), nxt); + } + + td.setTimingCron(""); + td.setTimingIdle(0); + td.setTimingRate(3600); + td.setTimingZone(""); + + { + // killed before next + td.setNextExec(last.withHour(9)); // 2024-08-01 09:01 + long now = DateLocaling.sysEpoch(last.withMinute(20)); // 2024-08-01 08:20 + long next = impl.calcNextExec(td, now); + LocalDateTime nxt = DateLocaling.sysLdt(next); + Assertions.assertEquals(LocalDateTime.of(2024, 8, 1, 9, 1), nxt); + } + { + // empty next + td.setNextExec(EmptyValue.DATE_TIME); + long now = DateLocaling.sysEpoch(last.withMinute(20)); // 2024-08-01 08:20 + long next = impl.calcNextExec(td, now); + LocalDateTime nxt = DateLocaling.sysLdt(next); + Assertions.assertEquals(LocalDateTime.of(2024, 8, 1, 9, 1), nxt); + } + { + // 08:01___mis9___mis10___mis11 + //N0= 10:01 + //Now + //Nx= 10:16 = 10:01 + :15 (25% N1-N0) + //N1= 11:01 + td.setNextExec(last.withHour(9)); // 2024-08-01 09:01 + long now = DateLocaling.sysEpoch(last.withHour(10).withMinute(16)); // 2024-08-02 11:01 + long next = impl.calcNextExec(td, now); + LocalDateTime nxt = DateLocaling.sysLdt(next); + Assertions.assertEquals(LocalDateTime.of(2024, 8, 1, 10, 1), nxt); + } + { + // 08:01___mis9___mis10___mis11 + //N0= 10:01 + //Nx= 10:16 = 10:01 + :15 (25% N1-N0) + //Now + //N1= 11:01 + td.setNextExec(last.withHour(9)); // 2024-08-01 09:01 + long now = DateLocaling.sysEpoch(last.withHour(10).withMinute(17)); // 2024-08-02 11:01 + long next = impl.calcNextExec(td, now); + LocalDateTime nxt = DateLocaling.sysLdt(next); + Assertions.assertEquals(LocalDateTime.of(2024, 8, 1, 11, 1), nxt); + } + } +} \ No newline at end of file From 9e63d82060868d5d639eee38b0f7c40cf7cac4c2 Mon Sep 17 00:00:00 2001 From: trydofor Date: Sun, 4 Aug 2024 12:39:05 +0800 Subject: [PATCH 38/51] =?UTF-8?q?=F0=9F=9A=A8=20fix=20qodana=20lint=20#284?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- qodana.yaml | 37 ++++++++ .../tiny/grow/track/impl/TinyTrackAround.java | 3 + .../grow/track/impl/TinyTrackServiceImpl.java | 2 + .../tiny/mail/sender/MailSenderManager.java | 10 +- .../tiny/mail/service/TinyMailService.java | 11 ++- .../service/impl/TinyMailServiceImpl.java | 91 +++++++++++-------- .../tiny/task/schedule/exec/NoticeExec.java | 1 + .../service/impl/TinyTaskConfServiceImpl.java | 1 + .../service/impl/TinyTaskExecServiceImpl.java | 13 ++- .../service/impl/TinyTaskServiceImpl.java | 8 +- .../faceless/flywave/RevisionFitness.java | 2 +- .../faceless/util/FlywaveRevisionScanner.java | 34 +++---- .../jooq/listener/TableCudListener.java | 7 +- .../spring/prop/FacelessJooqCudProp.java | 2 +- .../impl/LightSequenceSelectJdbc.java | 1 + .../journal/impl/DefaultJournalService.java | 1 + .../WingsHazelcastCacheCustomizer.java | 1 + .../actuator/cache/SlardarCacheEndpoint.java | 4 +- .../concur/impl/RighterInterceptor.java | 1 + .../domainx/DefaultDomainRequestMatcher.java | 1 + .../servlet/cookie/CookieRequestWrapper.java | 1 + .../servlet/filter/WingsOverloadFilter.java | 9 +- .../request/ResourceHttpRequestUtil.java | 1 + .../jackson/EmptyValuePropertyFilter.java | 1 + .../wings/slardar/monitor/MonitorTask.java | 4 +- .../database/TestingDatabaseHelper.java | 4 +- .../perm/impl/WarlockRoleServiceImpl.java | 1 + .../impl/WarlockUserAuthnServiceImpl.java | 1 + 28 files changed, 166 insertions(+), 87 deletions(-) create mode 100644 qodana.yaml diff --git a/qodana.yaml b/qodana.yaml new file mode 100644 index 000000000..812b29951 --- /dev/null +++ b/qodana.yaml @@ -0,0 +1,37 @@ +#-------------------------------------------------------------------------------# +# Qodana analysis is configured by qodana.yaml file # +# https://www.jetbrains.com/help/qodana/qodana-yaml.html # +#-------------------------------------------------------------------------------# +version: "1.0" + +#Specify inspection profile for code analysis +profile: + name: qodana.starter + +#Enable inspections +#include: +# - name: + +exclude: + - name: HttpUrlsUsage + patterns: + - "**/src/test" + - name: SpringBootApplicationProperties + patterns: + - "**/src/test" + - "example/*" + - name: SpringComponentScan + paths: + - example/winx-common/src/main/java/com/moilioncircle/wings/common/spring/boot/WinxAutoConfiguration.java + +projectJDK: temurin-21 #(Applied in CI/CD pipeline) + +#Execute shell command before Qodana execution (Applied in CI/CD pipeline) +#bootstrap: sh ./prepare-qodana.sh + +#Install IDE plugins before Qodana execution (Applied in CI/CD pipeline) +#plugins: +# - id: #(plugin id can be found at https://plugins.jetbrains.com) + +#Specify Qodana linter for analysis (Applied in CI/CD pipeline) +linter: jetbrains/qodana-jvm-community:latest diff --git a/radiant/tiny-grow/src/main/java/pro/fessional/wings/tiny/grow/track/impl/TinyTrackAround.java b/radiant/tiny-grow/src/main/java/pro/fessional/wings/tiny/grow/track/impl/TinyTrackAround.java index 04f5dbf36..c1e7bd951 100644 --- a/radiant/tiny-grow/src/main/java/pro/fessional/wings/tiny/grow/track/impl/TinyTrackAround.java +++ b/radiant/tiny-grow/src/main/java/pro/fessional/wings/tiny/grow/track/impl/TinyTrackAround.java @@ -70,6 +70,7 @@ public Object track(ProceedingJoinPoint joinPoint) throws Throwable { mixAsync(tracking, method, anno, joinPoint); } catch (Throwable e) { + // noinspection StringConcatenationArgumentToLogCall log.error("tiny-track fails to mixAsync, method=" + MethodConvertor.method2Str(method), e); } } @@ -91,6 +92,7 @@ protected void mixAsync(@NotNull TinyTracking tracking, @NotNull Method method, mix.invoke(joinPoint.getTarget(), pn); } catch (Exception e) { + // noinspection StringConcatenationArgumentToLogCall log.error("tiny-track fails to mix=" + MethodConvertor.method2Str(mix), e); } } @@ -115,6 +117,7 @@ protected TinyTracking tryTrack(@NotNull Method method, @NotNull TinyTracker ann return tinyTrackService.begin(key, ref); } catch (Exception e) { + // noinspection StringConcatenationArgumentToLogCall log.error("tiny-track fails to beginTracking, method=" + MethodConvertor.method2Str(method), e); return null; } diff --git a/radiant/tiny-grow/src/main/java/pro/fessional/wings/tiny/grow/track/impl/TinyTrackServiceImpl.java b/radiant/tiny-grow/src/main/java/pro/fessional/wings/tiny/grow/track/impl/TinyTrackServiceImpl.java index 2ff5d298b..b72775843 100644 --- a/radiant/tiny-grow/src/main/java/pro/fessional/wings/tiny/grow/track/impl/TinyTrackServiceImpl.java +++ b/radiant/tiny-grow/src/main/java/pro/fessional/wings/tiny/grow/track/impl/TinyTrackServiceImpl.java @@ -58,6 +58,7 @@ public TinyTracking begin(@NotNull String key, @NotNull String ref) { pr.prepare(tracking); } catch (Exception e) { + // noinspection StringConcatenationArgumentToLogCall log.error("tiny-track skip failed preparer=" + pr.getClass(), e); } } @@ -82,6 +83,7 @@ public void track(@NotNull TinyTracking tracking) { cl.collect(tracking); } catch (Exception e) { + // noinspection StringConcatenationArgumentToLogCall log.error("tiny-track skip failed collector=" + cl.getClass(), e); } } diff --git a/radiant/tiny-mail/src/main/java/pro/fessional/wings/tiny/mail/sender/MailSenderManager.java b/radiant/tiny-mail/src/main/java/pro/fessional/wings/tiny/mail/sender/MailSenderManager.java index a19ec9102..a4e9ab663 100644 --- a/radiant/tiny-mail/src/main/java/pro/fessional/wings/tiny/mail/sender/MailSenderManager.java +++ b/radiant/tiny-mail/src/main/java/pro/fessional/wings/tiny/mail/sender/MailSenderManager.java @@ -124,9 +124,11 @@ public void singleSend(@NotNull TinyMailMessage message, long maxWait, @Nullable if (wt.host) { mailHostWait.put(host, wt.wait); } + // noinspection StringConcatenationArgumentToLogCall log.warn("failed to send and host wait for " + (wt.wait - now) + "ms, message=" + message.toMainString(), me); throw new MailWaitException(wt.wait, wt.host, wt.stop, me); } + // noinspection StringConcatenationArgumentToLogCall log.warn("failed to send message= " + message.toMainString(), me); throw me; } @@ -191,7 +193,7 @@ public List batchSend(Collection message final long avg = slp / dryrunCount; long end = ThreadNow.millis(); for (BatchResult rst : results) { - if(rst.costMillis == 0) continue; + if (rst.costMillis == 0) continue; rst.costMillis = avg; rst.exitMillis = end; } @@ -224,6 +226,7 @@ public List batchSend(Collection message for (String host : hosts) { mailHostWait.put(host, wt.wait); } + // noinspection StringConcatenationArgumentToLogCall log.warn("failed to send and host wait for " + (wt.wait - now) + "ms, hosts=" + hosts, me); } @@ -251,7 +254,7 @@ public List batchSend(Collection message br.costMillis = avg; br.exitMillis = now; if (br.exception != null) { - log.warn("failed to batch send message, " + br.tinyMessage.toMainString()); + log.warn("failed to batch send message, {}", br.tinyMessage.toMainString()); } } @@ -381,7 +384,8 @@ private MimeMessage prepareMimeMessage(TinyMailMessage message, MimeMessagePrepa helper.addAttachment(n1, en.getValue()); } catch (Exception e) { - log.warn("ignore error of optional resource, name=" + name); + // noinspection StringConcatenationArgumentToLogCall + log.warn("ignore error of optional resource, name=" + name, e); } } else { diff --git a/radiant/tiny-mail/src/main/java/pro/fessional/wings/tiny/mail/service/TinyMailService.java b/radiant/tiny-mail/src/main/java/pro/fessional/wings/tiny/mail/service/TinyMailService.java index c96abb87f..a635f91fc 100644 --- a/radiant/tiny-mail/src/main/java/pro/fessional/wings/tiny/mail/service/TinyMailService.java +++ b/radiant/tiny-mail/src/main/java/pro/fessional/wings/tiny/mail/service/TinyMailService.java @@ -145,9 +145,10 @@ default long emit(@NotNull TinyMailPlain message) { * Create(id is empty) or edit a mail with check, return the id. * NOTE: no schedule to send, need manually send/post/emit it. */ - default long save(@NotNull TinyMailPlain message){ + default long save(@NotNull TinyMailPlain message) { return save(message, true); } + /** * Create(id is empty) or edit a mail with check, return the id. * NOTE: no schedule to send, need manually send/post/emit it. @@ -217,11 +218,11 @@ interface StatusHook { /** * hook status, return true will stop mail next send * - * @param po mail info - * @param cost send cost - * @param exception error if fail + * @param po mail info + * @param cost send cost + * @param error if fail * @return whether stop next send */ - boolean stop(@NotNull WinMailSender po, long cost, Exception exception); + boolean stop(@NotNull WinMailSender po, long cost, Exception error); } } diff --git a/radiant/tiny-mail/src/main/java/pro/fessional/wings/tiny/mail/service/impl/TinyMailServiceImpl.java b/radiant/tiny-mail/src/main/java/pro/fessional/wings/tiny/mail/service/impl/TinyMailServiceImpl.java index fab530b60..90b3d4211 100644 --- a/radiant/tiny-mail/src/main/java/pro/fessional/wings/tiny/mail/service/impl/TinyMailServiceImpl.java +++ b/radiant/tiny-mail/src/main/java/pro/fessional/wings/tiny/mail/service/impl/TinyMailServiceImpl.java @@ -127,10 +127,12 @@ public long post(@NotNull TinyMail message, boolean retry) { return doSend(true, message, retry); } catch (MailRetryException e) { + // noinspection StringConcatenationArgumentToLogCall log.warn("fail to post tiny-mail, next-retry=" + e.getNextEpoch() + ", subject=" + message.getSubject(), e.getCause()); return e.getNextEpoch(); } catch (Exception e) { + // noinspection StringConcatenationArgumentToLogCall log.error("fail to post tiny-mail, retry=" + retry + ", subject=" + message.getSubject(), e); return ErrOther; } @@ -142,10 +144,12 @@ public long emit(@NotNull TinyMail message, boolean retry) { return doSend(false, message, retry); } catch (MailRetryException e) { + // noinspection StringConcatenationArgumentToLogCall log.warn("fail to emit tiny-mail, next-retry=" + e.getNextEpoch() + ", subject=" + message.getSubject(), e.getCause()); return e.getNextEpoch(); } catch (Exception e) { + // noinspection StringConcatenationArgumentToLogCall log.error("fail to emit tiny-mail, retry=" + retry + ", subject=" + message.getSubject(), e); return ErrOther; } @@ -162,10 +166,12 @@ public long post(long id, boolean retry, boolean check) { return doSend(true, id, retry, check); } catch (MailRetryException e) { + // noinspection StringConcatenationArgumentToLogCall log.warn("fail to post tiny-mail, next-retry=" + e.getNextEpoch() + ", id=" + id, e.getCause()); return e.getNextEpoch(); } catch (Exception e) { + // noinspection StringConcatenationArgumentToLogCall log.error("fail to post tiny-mail, retry=" + retry + ", id=" + id, e); return ErrOther; } @@ -177,10 +183,12 @@ public long emit(long id, boolean retry, boolean check) { return doSend(false, id, retry, check); } catch (MailRetryException e) { + // noinspection StringConcatenationArgumentToLogCall log.warn("fail to emit tiny-mail, next-retry=" + e.getNextEpoch() + ", id=" + id, e.getCause()); return e.getNextEpoch(); } catch (Exception e) { + // noinspection StringConcatenationArgumentToLogCall log.error("fail to emit tiny-mail, retry=" + retry + ", id=" + id, e); return ErrOther; } @@ -199,7 +207,7 @@ public void afterPropertiesSet() { taskScheduler = TaskSchedulerHelper.Ttl(builder); taskScheduler.initialize(); isShutdown = false; - log.info("tiny-mail taskScheduler, prefix=" + taskScheduler.getThreadNamePrefix()); + log.info("tiny-mail taskScheduler, prefix={}", taskScheduler.getThreadNamePrefix()); final long idle = tinyMailServiceProp.getBootScan().toMillis(); if (idle > 0) { @@ -579,7 +587,7 @@ protected long doSend(boolean sync, @NotNull TinyMail message, boolean retry) { protected long doSend(boolean sync, long id, boolean retry, boolean check) { if (isShutdown) { - log.warn("skip tiny-mail for shutdwon, id={}", id); + log.warn("doSend skip tiny-mail for shutdwon, id={}", id); return ErrOther; } @@ -602,13 +610,13 @@ protected long doSend(boolean sync, long id, boolean retry, boolean check) { /** * next if done lt max or exception and retry */ - protected long saveSendResult(@NotNull WinMailSender po, long cost, long exit, Exception exception, boolean retry) { + protected long saveSendResult(@NotNull WinMailSender po, long cost, long exit, Exception error, boolean retry) { long nextSend = -1; final Long id = po.getId(); try { final WinMailSenderTable t = winMailSenderDao.getTable(); final Map setter = new HashMap<>(); - if (exception == null) { + if (error == null) { setter.put(t.LastFail, null); setter.put(t.LastDone, DateLocaling.sysLdt(exit)); setter.put(t.LastCost, cost); @@ -627,7 +635,7 @@ protected long saveSendResult(@NotNull WinMailSender po, long cost, long exit, E setter.put(t.SumDone, t.SumDone.add(1)); } else { - setter.put(t.LastFail, ThrowableUtil.toString(exception)); + setter.put(t.LastFail, ThrowableUtil.toString(error)); setter.put(t.LastDone, EmptyValue.DATE_TIME); setter.put(t.LastCost, cost); @@ -637,26 +645,30 @@ protected long saveSendResult(@NotNull WinMailSender po, long cost, long exit, E log.debug("done tiny-mail by max-fail id={}, subject={}", id, po.getMailSubj()); } else if (retry) { - if (exception instanceof MailStopException) { - log.warn("stop tiny-mail by stop-exception, id=" + id, exception); + if (error instanceof MailStopException) { + // noinspection StringConcatenationArgumentToLogCall + log.warn("stop tiny-mail by stop-exception, id=" + id, error); } - else if (exception instanceof MailWaitException mwe) { + else if (error instanceof MailWaitException mwe) { if (mwe.isStopRetry()) { - log.error("stop tiny-mail by stop-retry, id=" + id, exception); + // noinspection StringConcatenationArgumentToLogCall + log.error("stop tiny-mail by stop-retry, id=" + id, error); } else { nextSend = mwe.getWaitEpoch(); } } - else if (exception instanceof MailParseException || exception instanceof MessagingException) { - log.error("stop tiny-mail by failed parse, id=" + id, exception); + else if (error instanceof MailParseException || error instanceof MessagingException) { + // noinspection StringConcatenationArgumentToLogCall + log.error("stop tiny-mail by failed parse, id=" + id, error); } else { nextSend = exit + tinyMailServiceProp.getTryNext().toMillis(); } } else { - log.error("stop tiny-mail by not-retry, id=" + id, exception); + // noinspection StringConcatenationArgumentToLogCall + log.error("stop tiny-mail by not-retry, id=" + id, error); } setter.put(t.SumSend, t.SumSend.add(1)); @@ -667,11 +679,12 @@ else if (exception instanceof MailParseException || exception instanceof Messagi for (StatusHook sh : findStatusHook()) { try { - if (sh.stop(po, cost, exception)) { + if (sh.stop(po, cost, error)) { hookStop = true; } } catch (Exception e) { + // noinspection StringConcatenationArgumentToLogCall log.error("should NOT throw in hook, hook-class=" + sh.getClass().getName(), e); } } @@ -699,6 +712,7 @@ else if (exception instanceof MailParseException || exception instanceof Messagi }); } catch (Exception e) { + // noinspection StringConcatenationArgumentToLogCall log.error("failed to save tiny-mail status, id=" + id + ", subject=" + po.getMailSubj(), e); nextSend = exit + tinyMailServiceProp.getTryNext().toMillis(); } @@ -768,7 +782,7 @@ protected void editLazyMail(@NotNull WinMailSender po, @NotNull @Param.Out TinyM private long doSyncSend(@NotNull WinMailSender po, @NotNull TinyMailMessage message, boolean retry, boolean check) { if (isShutdown) { - log.warn("skip tiny-mail for shutdwon, id={}", po.getId()); + log.warn("doSyncSend skip tiny-mail for shutdwon, id={}", po.getId()); return ErrOther; } @@ -789,43 +803,46 @@ private long doSyncSend(@NotNull WinMailSender po, @NotNull TinyMailMessage mess try { editLazyMail(po, message); } - catch (Exception e) { - log.error("stop tiny-mail for lazy-edit error, id=" + id, e); - saveSendResult(po, 0, start, e, false); // no retry is lazy fail + catch (Exception err) { + // noinspection StringConcatenationArgumentToLogCall + log.error("stop tiny-mail for lazy-edit error, id=" + id, err); + saveSendResult(po, 0, start, err, false); // no retry is lazy fail return ErrCheck; } - Exception exception = null; + Exception error = null; + final long next; try { mailSenderManager.singleSend(message); } catch (Exception e) { - exception = e; + error = e; } finally { final long end = ThreadNow.millis(); - long nxt = saveSendResult(po, end - start, end, exception, retry); - if (nxt > 0) { - planAsyncMail(new AsyncMail(id, nxt, retry, check, null, message)); - log.debug("plan tiny-mail next-send, err={}, id={}, subject={}", exception == null, id, po.getMailSubj()); - if (exception != null) throw new MailRetryException(nxt, exception); - } + next = saveSendResult(po, end - start, end, error, retry); } - if (exception == null) { - return Success; + if (next > 0) { + planAsyncMail(new AsyncMail(id, next, retry, check, null, message)); + log.debug("plan tiny-mail next-send, err={}, id={}, subject={}", error == null, id, po.getMailSubj()); + if (error != null) throw new MailRetryException(next, error); } - else if (exception instanceof RuntimeException re) { + + if (error == null) return Success; + + // noinspection ConstantValue + if (error instanceof RuntimeException re) { throw re; // rethrow exception } else { - throw new MailSendException("failed tiny-mail, id=" + id + ", subject=" + po.getMailSubj(), exception); + throw new MailSendException("failed tiny-mail, id=" + id + ", subject=" + po.getMailSubj(), error); } } private long doAsyncSend(@NotNull WinMailSender po, @NotNull TinyMailMessage message, boolean retry, boolean check) { if (isShutdown) { - log.warn("skip tiny-mail for shutdwon, id={}", po.getId()); + log.warn("doAsyncSend skip tiny-mail for shutdwon, id={}", po.getId()); return ErrOther; } @@ -837,9 +854,10 @@ private long doAsyncSend(@NotNull WinMailSender po, @NotNull TinyMailMessage mes try { editLazyMail(po, message); } - catch (Exception e) { - log.error("stop tiny-mail for lazy-edit error, id=" + id, e); - saveSendResult(po, 0, start, e, false); // no retry is lazy fail + catch (Exception err) { + // noinspection StringConcatenationArgumentToLogCall + log.error("stop tiny-mail for lazy-edit error, id=" + id, err); + saveSendResult(po, 0, start, err, false); // no retry is lazy fail return ErrCheck; } @@ -990,9 +1008,10 @@ private void sendAsyncMail() { editLazyMail(po, msg); messages.add(msg); } - catch (Exception e) { - log.error("stop tiny-mail for lazy-edit error, id=" + id, e); - saveSendResult(po, 0, start, e, false); // no retry is lazy fail + catch (Exception err) { + // noinspection StringConcatenationArgumentToLogCall + log.error("stop tiny-mail for lazy-edit error, id=" + id, err); + saveSendResult(po, 0, start, err, false); // no retry is lazy fail } } diff --git a/radiant/tiny-task/src/main/java/pro/fessional/wings/tiny/task/schedule/exec/NoticeExec.java b/radiant/tiny-task/src/main/java/pro/fessional/wings/tiny/task/schedule/exec/NoticeExec.java index 22016f0b4..e16e55f86 100644 --- a/radiant/tiny-task/src/main/java/pro/fessional/wings/tiny/task/schedule/exec/NoticeExec.java +++ b/radiant/tiny-task/src/main/java/pro/fessional/wings/tiny/task/schedule/exec/NoticeExec.java @@ -53,6 +53,7 @@ public void postNotice(String config, String subject, String content) { beanObject.post(conf, subject, content); } catch (Exception e) { + // noinspection StringConcatenationArgumentToLogCall log.warn("failed to post notice, subject=" + subject + ", content=" + content, e); } } diff --git a/radiant/tiny-task/src/main/java/pro/fessional/wings/tiny/task/service/impl/TinyTaskConfServiceImpl.java b/radiant/tiny-task/src/main/java/pro/fessional/wings/tiny/task/service/impl/TinyTaskConfServiceImpl.java index 09b6fc45f..cb5f0d4c2 100644 --- a/radiant/tiny-task/src/main/java/pro/fessional/wings/tiny/task/service/impl/TinyTaskConfServiceImpl.java +++ b/radiant/tiny-task/src/main/java/pro/fessional/wings/tiny/task/service/impl/TinyTaskConfServiceImpl.java @@ -316,6 +316,7 @@ private Conf config(@NotNull Class claz, @NotNull Object bean, @NotNull Metho return new NoticeExec<>(nb); } catch (ClassNotFoundException e) { + // noinspection StringConcatenationArgumentToLogCall log.error("failed to init notice bean=" + noticeBean, e); throw new IllegalArgumentException(e); } diff --git a/radiant/tiny-task/src/main/java/pro/fessional/wings/tiny/task/service/impl/TinyTaskExecServiceImpl.java b/radiant/tiny-task/src/main/java/pro/fessional/wings/tiny/task/service/impl/TinyTaskExecServiceImpl.java index 73f306230..bebb7d792 100644 --- a/radiant/tiny-task/src/main/java/pro/fessional/wings/tiny/task/service/impl/TinyTaskExecServiceImpl.java +++ b/radiant/tiny-task/src/main/java/pro/fessional/wings/tiny/task/service/impl/TinyTaskExecServiceImpl.java @@ -127,7 +127,7 @@ public boolean launch(long id) { @Override public boolean force(long id) { if (isShutdown) { - log.warn("skip tiny-task for shutdwon, id={}", id); + log.warn("skip tiny-task for shutdwon, force id={}", id); return false; } @@ -174,6 +174,7 @@ public boolean force(long id) { postNotice(notice, noticeConf, ntcWhen, taskerInfo, taskMsg, doneTms, WhenFeed, WhenDone); } catch (Exception e) { + // noinspection StringConcatenationArgumentToLogCall log.error("tiny-task force fail, id=" + id, e); failTms = ThreadNow.millis(); taskMsg = ThrowableUtil.toString(e); @@ -184,6 +185,7 @@ public boolean force(long id) { saveResult(id, td.getPropkey(), execTms, failTms, doneTms, taskMsg, td.getDurFail()); } catch (Exception e) { + // noinspection StringConcatenationArgumentToLogCall log.error("failed to save tiny-task result, id=" + id, e); } } @@ -219,7 +221,7 @@ public Set running() { private boolean relaunch(long id) { if (isShutdown) { - log.warn("skip tiny-task for shutdwon, id={}", id); + log.warn("skip tiny-task for shutdwon, relaunch id={}", id); return false; } @@ -233,7 +235,7 @@ private boolean relaunch(long id) { final WinTaskDefine td = winTaskDefineDao.fetchOneById(id); if (td == null) { - log.info("skip tiny-task for not found, id={}", id); + log.info("skip tiny-task for not found, relaunch id={}", id); return false; } @@ -308,6 +310,7 @@ private boolean relaunch(long id) { } catch (Exception e) { Throwable c = ThrowableUtil.cause(e, 1); + // noinspection StringConcatenationArgumentToLogCall log.error("tiny-task fail, id=" + id + ", prop=" + key, c); failTms = ThreadNow.millis(); exitMsg = ThrowableUtil.toString(c); @@ -319,6 +322,7 @@ private boolean relaunch(long id) { saveResult(id, key, execTms, failTms, doneTms, exitMsg, td.getDurFail()); } catch (Exception e) { + // noinspection StringConcatenationArgumentToLogCall log.error("failed to save tiny-task result, id=" + id + ", prop=" + key, e); } @@ -578,13 +582,12 @@ protected long calcNextExec(WinTaskDefine td, long now) { if (zeroMiss && n0 > 0 && now <= n0 + ((n1 - n0) * 25 / 100)) { log.info("launch tiny-task for miss=0, next={}, id={}, prop={}", next, id, td.getPropkey()); nextExec = n0; - break; } else { log.info("launch tiny-task for next={}, id={}, prop={}", next, id, td.getPropkey()); nextExec = n1; - break; } + break; } if (timingMiss > 0 && now <= n1 + timingMiss) { diff --git a/radiant/tiny-task/src/main/java/pro/fessional/wings/tiny/task/service/impl/TinyTaskServiceImpl.java b/radiant/tiny-task/src/main/java/pro/fessional/wings/tiny/task/service/impl/TinyTaskServiceImpl.java index 719f13470..8cf11013f 100644 --- a/radiant/tiny-task/src/main/java/pro/fessional/wings/tiny/task/service/impl/TinyTaskServiceImpl.java +++ b/radiant/tiny-task/src/main/java/pro/fessional/wings/tiny/task/service/impl/TinyTaskServiceImpl.java @@ -47,11 +47,11 @@ public Set schedule(@NotNull Object taskerBean) { for (Conf cnf : conf) { if (cnf.isEnabled() && cnf.isAutorun()) { final boolean cd = tinyTaskExecService.launch(cnf.getId()); - log.info("schedule tiny-task {}, scheduled={}", cnf, cd); + log.info("schedule bean tiny-task {}, scheduled={}", cnf, cd); rst.add(new Task(cnf.getId(), cnf.getKey(), cd)); } else { - log.info("skip tiny-task {}", cnf); + log.info("skip bean tiny-task {}", cnf); } } return rst; @@ -63,11 +63,11 @@ public Task schedule(@NotNull Object taskerBean, @NotNull Method taskerCall, @Nu final boolean cd; if (cnf.isEnabled()) { cd = tinyTaskExecService.launch(cnf.getId()); - log.info("schedule tiny-task {}, scheduled={}", cnf, cd); + log.info("schedule method tiny-task {}, scheduled={}", cnf, cd); } else { cd = false; - log.info("skip tiny-task {}", cnf); + log.info("skip method tiny-task {}", cnf); } return new Task(cnf.getId(), cnf.getKey(), cd); diff --git a/wings/faceless-flywave/src/main/java/pro/fessional/wings/faceless/flywave/RevisionFitness.java b/wings/faceless-flywave/src/main/java/pro/fessional/wings/faceless/flywave/RevisionFitness.java index 65cec63a0..d349fe2d8 100644 --- a/wings/faceless-flywave/src/main/java/pro/fessional/wings/faceless/flywave/RevisionFitness.java +++ b/wings/faceless-flywave/src/main/java/pro/fessional/wings/faceless/flywave/RevisionFitness.java @@ -228,7 +228,7 @@ private TreeMap> checkUnapply(SchemaRevisionManager manager) { throw new IllegalStateException("Wings Revision Diff Schemas Found:" + diffWarn); } else { - log.warn("Wings Revision Diff Schemas Found:" + diffWarn); + log.warn("Wings Revision Diff Schemas Found:{}", diffWarn); } } diff --git a/wings/faceless-flywave/src/main/java/pro/fessional/wings/faceless/util/FlywaveRevisionScanner.java b/wings/faceless-flywave/src/main/java/pro/fessional/wings/faceless/util/FlywaveRevisionScanner.java index 917d091d9..10d5d5759 100644 --- a/wings/faceless-flywave/src/main/java/pro/fessional/wings/faceless/util/FlywaveRevisionScanner.java +++ b/wings/faceless-flywave/src/main/java/pro/fessional/wings/faceless/util/FlywaveRevisionScanner.java @@ -235,7 +235,7 @@ public static void scan(SortedMap result, String path) { try { PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver(); Resource[] resources = resolver.getResources(path); - log.info("[FlywaveRevisionScanner]🐝 scanned " + resources.length + " resources in path=" + path); + log.info("[FlywaveRevisionScanner]🐝 scanned {} resources in path={}", resources.length, path); Pattern reviRegex = Pattern.compile("([-_0-9]{8,})([uv])([0-9]{2,})[^/]*\\.sql$", Pattern.CASE_INSENSITIVE); Charset utf8 = StandardCharsets.UTF_8; @@ -245,7 +245,7 @@ public static void scan(SortedMap result, String path) { file = res.getURL().getPath(); Matcher m = reviRegex.matcher(file); if (!m.find()) { - log.info("[FlywaveRevisionScanner]🐝 skip unsupported resource=" + file); + log.info("[FlywaveRevisionScanner]🐝 skip unsupported resource={}", file); continue; } boolean undo = "u".equalsIgnoreCase(m.group(2)); @@ -266,11 +266,11 @@ public static void scan(SortedMap result, String path) { if (undo) { final String ou = d.getUndoPath(); if (EmptySugar.asEmptyValue(ou)) { - log.info("[FlywaveRevisionScanner]🐝 scan " + revi + " undo↓ resource=" + file); + log.info("[FlywaveRevisionScanner]🐝 scan {} undo↓ resource={}", revi, file); } else { rplRevi.add(revi); - log.warn("[FlywaveRevisionScanner]🐝 replace " + revi + " undo↓ new=" + file + ", old=" + ou); + log.warn("[FlywaveRevisionScanner]🐝 replace {} undo↓ new={}, old={}", revi, file, ou); } d.setUndoPath(file); d.setUndoText(text); @@ -278,20 +278,20 @@ public static void scan(SortedMap result, String path) { else { final String ou = d.getUptoPath(); if (EmptySugar.asEmptyValue(ou)) { - log.info("[FlywaveRevisionScanner]🐝 scan " + revi + " upto↑ resource=" + file); + log.info("[FlywaveRevisionScanner]🐝 scan {} upto↑ resource={}", revi, file); } else { rplRevi.add(revi); - log.warn("[FlywaveRevisionScanner]🐝 replace " + revi + " upto↑ new=" + file + ", old=" + ou); + log.warn("[FlywaveRevisionScanner]🐝 replace {} upto↑ new={}, old={}", revi, file, ou); } d.setUptoPath(file); d.setUptoText(text); } } - log.info("[FlywaveRevisionScanner]🐝 scanned revisions new=" + newRevi.size() + ", replace=" + rplRevi.size()); + log.info("[FlywaveRevisionScanner]🐝 scanned revisions new={}, replace={}", newRevi.size(), rplRevi.size()); } catch (Exception e) { - throw new IllegalStateException("failed to scan path = " + path + ", file=" + file, e); + throw new IllegalStateException("failed to scan path=" + path + ", file=" + file, e); } } @@ -466,7 +466,7 @@ public Helper replace(long from, long to, Function mod) { modify("replace " + from + " to " + to + " with sql", to, it -> { it.setUptoText(mod.apply(it.getUptoText())); it.setUndoText(mod.apply(it.getUndoText())); - log.info("[FlywaveRevisionScanner]🐝 replace revi from=" + from + " to=" + to + " with sql text"); + log.info("[FlywaveRevisionScanner]🐝 replace revi from={}, to={} with sql text", from, to); }); } return this; @@ -621,12 +621,12 @@ public SortedMap scan() { final RevisionSql old = result.remove(ov); if (old == null) { - throw new IllegalStateException("failed to replace not-exist from=" + ov + " to=" + nv); + throw new IllegalStateException("failed to replace not-exist from=" + ov + ", to=" + nv); } final RevisionSql tor = result.put(nv, old); if (tor != null) { - log.info("[FlywaveRevisionScanner]🐝 replace revi from=" + ov + " to=" + nv + ", exist=" + tor); + log.info("[FlywaveRevisionScanner]🐝 replace revi from={}, to={}, exist={}", ov, nv, tor); } } @@ -637,15 +637,15 @@ public SortedMap scan() { if (ent.getKey().test(it.getKey())) { final String info = ent.getValue(); if (info != null && !info.isEmpty()) { - log.info("[FlywaveRevisionScanner]🐝 include " + it.getKey() + " by " + info); + log.info("[FlywaveRevisionScanner]🐝 include {} by {}", it.getKey(), info); } else { - log.info("[FlywaveRevisionScanner]🐝 include " + it.getKey()); + log.info("[FlywaveRevisionScanner]🐝 include {}", it.getKey()); } return false; } } - log.info("[FlywaveRevisionScanner]🐝 remove " + it.getKey() + " by include filter unmatched"); + log.info("[FlywaveRevisionScanner]🐝 remove {} by include filter unmatched", it.getKey()); return true; }); } @@ -657,10 +657,10 @@ public SortedMap scan() { if (ent.getKey().test(it.getKey())) { final String info = ent.getValue(); if (info == null || info.isEmpty()) { - log.info("[FlywaveRevisionScanner]🐝 remove " + it.getKey() + " by exclude filter matched"); + log.info("[FlywaveRevisionScanner]🐝 remove {} by exclude filter matched", it.getKey()); } else { - log.info("[FlywaveRevisionScanner]🐝 remove " + it.getKey() + " by " + info); + log.info("[FlywaveRevisionScanner]🐝 remove {} by {}", it.getKey(), info); } return true; } @@ -671,7 +671,7 @@ public SortedMap scan() { // modifier for (Map.Entry, String> mod : modifier.entrySet()) { - log.info("[FlywaveRevisionScanner]🐝 modify RevisionSql by " + mod.getValue()); + log.info("[FlywaveRevisionScanner]🐝 modify RevisionSql by {}", mod.getValue()); final BiConsumer fn = mod.getKey(); for (Map.Entry ent : result.entrySet()) { fn.accept(ent.getKey(), ent.getValue()); diff --git a/wings/faceless-jooq/src/main/java/pro/fessional/wings/faceless/database/jooq/listener/TableCudListener.java b/wings/faceless-jooq/src/main/java/pro/fessional/wings/faceless/database/jooq/listener/TableCudListener.java index 9a8e1970a..30207d704 100644 --- a/wings/faceless-jooq/src/main/java/pro/fessional/wings/faceless/database/jooq/listener/TableCudListener.java +++ b/wings/faceless-jooq/src/main/java/pro/fessional/wings/faceless/database/jooq/listener/TableCudListener.java @@ -82,8 +82,9 @@ public void clauseStart(VisitContext context) { final String clz = scn(context.queryPart()); final Clause clause = context.clause(); if (clause == Clause.INSERT || clause == Clause.UPDATE || clause == Clause.DELETE) { - log.warn(">>> clauseStart Clause=" + clause + ", Query=" + clz - , new DebugException("debug for call stack")); + // noinspection StringConcatenationArgumentToLogCall + log.warn(">>> clauseStart Clause=" + clause + ", Query=" + clz, + new DebugException("debug for call stack")); } else { log.warn(">>> clauseStart Clause={}, Query={}", clause, clz); @@ -135,7 +136,7 @@ public void clauseEnd(VisitContext context) { log.warn("<<< clauseEnd Clause={}, Query={}\n\n", clause, clz); } else { - log.warn(">>> clauseStart Clause={}, Query={}", clause, clz); + log.warn(">>> clauseEnd Clause={}, Query={}", clause, clz); } } diff --git a/wings/faceless-jooq/src/main/java/pro/fessional/wings/faceless/spring/prop/FacelessJooqCudProp.java b/wings/faceless-jooq/src/main/java/pro/fessional/wings/faceless/spring/prop/FacelessJooqCudProp.java index 9e561812b..b8da0bbef 100644 --- a/wings/faceless-jooq/src/main/java/pro/fessional/wings/faceless/spring/prop/FacelessJooqCudProp.java +++ b/wings/faceless-jooq/src/main/java/pro/fessional/wings/faceless/spring/prop/FacelessJooqCudProp.java @@ -78,7 +78,7 @@ public void setTable(@NotNull Map> table) { Map> temp = new LinkedHashMap<>(); for (Map.Entry> en : table.entrySet()) { if (en.getValue().contains(DisabledValue)) { - log.info("remove disable value for table={}", en.getKey()); + log.info("ignore disable value for table={}", en.getKey()); } else { temp.put(en.getKey(), en.getValue()); diff --git a/wings/faceless/src/main/java/pro/fessional/wings/faceless/database/manual/single/select/lightsequence/impl/LightSequenceSelectJdbc.java b/wings/faceless/src/main/java/pro/fessional/wings/faceless/database/manual/single/select/lightsequence/impl/LightSequenceSelectJdbc.java index 85c4f9a2c..31ad8256b 100644 --- a/wings/faceless/src/main/java/pro/fessional/wings/faceless/database/manual/single/select/lightsequence/impl/LightSequenceSelectJdbc.java +++ b/wings/faceless/src/main/java/pro/fessional/wings/faceless/database/manual/single/select/lightsequence/impl/LightSequenceSelectJdbc.java @@ -103,6 +103,7 @@ private NameNextStep checkTableAndAdjust(NextStep step, String name) { } } catch (Exception e) { + // noinspection StringConcatenationArgumentToLogCall log.warn("LightSequence failed to load dbMax, name=" + name, e); return Long.MIN_VALUE; } diff --git a/wings/faceless/src/main/java/pro/fessional/wings/faceless/service/journal/impl/DefaultJournalService.java b/wings/faceless/src/main/java/pro/fessional/wings/faceless/service/journal/impl/DefaultJournalService.java index 556c3215d..a3caca288 100644 --- a/wings/faceless/src/main/java/pro/fessional/wings/faceless/service/journal/impl/DefaultJournalService.java +++ b/wings/faceless/src/main/java/pro/fessional/wings/faceless/service/journal/impl/DefaultJournalService.java @@ -141,6 +141,7 @@ public long elapse(AtomicLong dummyId, @NotNull Journal journal) { journalModify.elapse(cost, journal.getId()); } catch (Exception e) { + // noinspection StringConcatenationArgumentToLogCall log.warn("fail to update elapse=" + cost + ", id=" + journal.getId(), e); } } diff --git a/wings/slardar-hazel-caching/src/main/java/pro/fessional/wings/slardar/cache/hazelcast/WingsHazelcastCacheCustomizer.java b/wings/slardar-hazel-caching/src/main/java/pro/fessional/wings/slardar/cache/hazelcast/WingsHazelcastCacheCustomizer.java index d4aa6b3c9..bc0733cbf 100644 --- a/wings/slardar-hazel-caching/src/main/java/pro/fessional/wings/slardar/cache/hazelcast/WingsHazelcastCacheCustomizer.java +++ b/wings/slardar-hazel-caching/src/main/java/pro/fessional/wings/slardar/cache/hazelcast/WingsHazelcastCacheCustomizer.java @@ -75,6 +75,7 @@ private void checkMapConf(Config config, Map mapCnf, String n } } catch (InvalidConfigurationException e) { + // noinspection StringConcatenationArgumentToLogCall log.error("failed to change MapConfig, name=" + name, e); } } diff --git a/wings/slardar-sprint/src/main/java/pro/fessional/wings/slardar/actuator/cache/SlardarCacheEndpoint.java b/wings/slardar-sprint/src/main/java/pro/fessional/wings/slardar/actuator/cache/SlardarCacheEndpoint.java index 1a706650c..8176ed1a8 100644 --- a/wings/slardar-sprint/src/main/java/pro/fessional/wings/slardar/actuator/cache/SlardarCacheEndpoint.java +++ b/wings/slardar-sprint/src/main/java/pro/fessional/wings/slardar/actuator/cache/SlardarCacheEndpoint.java @@ -45,10 +45,10 @@ public SlardarCacheEndpoint(Map cm) { final String k = en.getKey(); if (v instanceof State) { cacheManagers.put(k, v); - log.info("init CacheManager with State, bean=" + k); + log.info("init CacheManager with State, bean={}", k); } else { - log.info("skip CacheManager without State, bean=" + k); + log.info("skip CacheManager without State, bean={}", k); } } } diff --git a/wings/slardar-webmvc/src/main/java/pro/fessional/wings/slardar/concur/impl/RighterInterceptor.java b/wings/slardar-webmvc/src/main/java/pro/fessional/wings/slardar/concur/impl/RighterInterceptor.java index 20b0ade4b..3d17a89b0 100644 --- a/wings/slardar-webmvc/src/main/java/pro/fessional/wings/slardar/concur/impl/RighterInterceptor.java +++ b/wings/slardar-webmvc/src/main/java/pro/fessional/wings/slardar/concur/impl/RighterInterceptor.java @@ -110,6 +110,7 @@ public boolean preHandle(@NotNull HttpServletRequest request, return true; } catch (Exception e) { + // noinspection StringConcatenationArgumentToLogCall log.info("failed to deserialize. session=" + session + ", audit=" + audit, e); responseError(response); return false; diff --git a/wings/slardar-webmvc/src/main/java/pro/fessional/wings/slardar/domainx/DefaultDomainRequestMatcher.java b/wings/slardar-webmvc/src/main/java/pro/fessional/wings/slardar/domainx/DefaultDomainRequestMatcher.java index 89dc3f101..4ec2a8c25 100644 --- a/wings/slardar-webmvc/src/main/java/pro/fessional/wings/slardar/domainx/DefaultDomainRequestMatcher.java +++ b/wings/slardar-webmvc/src/main/java/pro/fessional/wings/slardar/domainx/DefaultDomainRequestMatcher.java @@ -86,6 +86,7 @@ public HttpServletRequest match(HttpServletRequest request, String domain) { } } catch (Exception e) { + // noinspection StringConcatenationArgumentToLogCall log.warn("failed to getHandler in HandlerMapping=" + hm.getClass(), e); } } diff --git a/wings/slardar-webmvc/src/main/java/pro/fessional/wings/slardar/servlet/cookie/CookieRequestWrapper.java b/wings/slardar-webmvc/src/main/java/pro/fessional/wings/slardar/servlet/cookie/CookieRequestWrapper.java index 0b1c3d66b..e5e07992d 100644 --- a/wings/slardar-webmvc/src/main/java/pro/fessional/wings/slardar/servlet/cookie/CookieRequestWrapper.java +++ b/wings/slardar-webmvc/src/main/java/pro/fessional/wings/slardar/servlet/cookie/CookieRequestWrapper.java @@ -38,6 +38,7 @@ public Cookie[] getCookies() { cookies[i] = reader.apply(ck); } catch (Exception e) { + // noinspection StringConcatenationArgumentToLogCall log.info("failed to wrap cookie=" + ck, e); } diff --git a/wings/slardar-webmvc/src/main/java/pro/fessional/wings/slardar/servlet/filter/WingsOverloadFilter.java b/wings/slardar-webmvc/src/main/java/pro/fessional/wings/slardar/servlet/filter/WingsOverloadFilter.java index c65be4a59..54becc244 100644 --- a/wings/slardar-webmvc/src/main/java/pro/fessional/wings/slardar/servlet/filter/WingsOverloadFilter.java +++ b/wings/slardar-webmvc/src/main/java/pro/fessional/wings/slardar/servlet/filter/WingsOverloadFilter.java @@ -273,13 +273,8 @@ private void checkAndStats(HttpServletRequest request, ServletResponse response, } } - log.info("wings-snap-response " - + ", total-resp=" + total - + ", p99=" + p99 - + ", p95=" + p95 - + ", p90=" + p90 - + ", process=" + requestProcess.get() - + ", capacity=" + requestCapacity.get()); + log.info("wings-snap-response, total-resp={}, p99={}, p95={}, p90={}, process={}, capacity={}", + total, p99, p95, p90, requestProcess.get(), requestCapacity.get()); lastInfoStat.set(end); } } diff --git a/wings/slardar-webmvc/src/main/java/pro/fessional/wings/slardar/servlet/request/ResourceHttpRequestUtil.java b/wings/slardar-webmvc/src/main/java/pro/fessional/wings/slardar/servlet/request/ResourceHttpRequestUtil.java index 28aa09a20..568f61f39 100644 --- a/wings/slardar-webmvc/src/main/java/pro/fessional/wings/slardar/servlet/request/ResourceHttpRequestUtil.java +++ b/wings/slardar-webmvc/src/main/java/pro/fessional/wings/slardar/servlet/request/ResourceHttpRequestUtil.java @@ -37,6 +37,7 @@ public static boolean existResource(ResourceHttpRequestHandler rh, HttpServletRe md.setAccessible(true); } catch (Exception e) { + // noinspection StringConcatenationArgumentToLogCall log.warn("failed to check resource=" + rq.getRequestURI(), e); } return md; diff --git a/wings/slardar/src/main/java/pro/fessional/wings/slardar/jackson/EmptyValuePropertyFilter.java b/wings/slardar/src/main/java/pro/fessional/wings/slardar/jackson/EmptyValuePropertyFilter.java index ab472ef25..1892839bf 100644 --- a/wings/slardar/src/main/java/pro/fessional/wings/slardar/jackson/EmptyValuePropertyFilter.java +++ b/wings/slardar/src/main/java/pro/fessional/wings/slardar/jackson/EmptyValuePropertyFilter.java @@ -83,6 +83,7 @@ public void serializeAsField(Object pojo, JsonGenerator gen, SerializerProvider } catch (Exception ex) { if (log.isDebugEnabled()) { + // noinspection StringConcatenationArgumentToLogCall log.debug("Skipping '" + writer.getFullName() + "' on '" + pojo.getClass().getName() + "' as an exception was thrown when retrieving its value", ex); } diff --git a/wings/slardar/src/main/java/pro/fessional/wings/slardar/monitor/MonitorTask.java b/wings/slardar/src/main/java/pro/fessional/wings/slardar/monitor/MonitorTask.java index 87da82237..28acd78f3 100644 --- a/wings/slardar/src/main/java/pro/fessional/wings/slardar/monitor/MonitorTask.java +++ b/wings/slardar/src/main/java/pro/fessional/wings/slardar/monitor/MonitorTask.java @@ -57,6 +57,7 @@ public void metric(Map> warns) { log.debug("check {} warns by {}", sz, nm); } catch (Exception e) { + // noinspection StringConcatenationArgumentToLogCall log.warn("failed to metric, name=" + nm, e); } } @@ -82,7 +83,7 @@ public void report(Map> warns) { for (WarnReport report : warnReports) { final String rpt = report.getClass().getName(); try { - log.debug("check {} warns by {}", warns.size(), rpt); + log.debug("report {} warns by {}", warns.size(), rpt); final WarnReport.Sts sts = report.report(app, jvm, warns); if (sts == WarnReport.Sts.Fail) { log.warn("failed to report={}", rpt); @@ -92,6 +93,7 @@ public void report(Map> warns) { } } catch (Exception e) { + // noinspection StringConcatenationArgumentToLogCall log.warn("failed to report, name=" + rpt, e); } } diff --git a/wings/testing-faceless/src/main/java/pro/fessional/wings/testing/faceless/database/TestingDatabaseHelper.java b/wings/testing-faceless/src/main/java/pro/fessional/wings/testing/faceless/database/TestingDatabaseHelper.java index d9dfe8d0d..d22db4cef 100644 --- a/wings/testing-faceless/src/main/java/pro/fessional/wings/testing/faceless/database/TestingDatabaseHelper.java +++ b/wings/testing-faceless/src/main/java/pro/fessional/wings/testing/faceless/database/TestingDatabaseHelper.java @@ -143,12 +143,12 @@ private Map> fetchAllColumn1(String sql) { public static void testcaseNotice(String... mes) { for (String s : mes) { - log.info(">>=>🦁🦁🦁 " + s + " 🦁🦁🦁<=<<"); + log.info(">>=>🦁🦁🦁 {} 🦁🦁🦁<=<<", s); } } public static void breakpointDebug(String... mes) { - Arrays.stream(mes).forEach(s -> log.debug(">>=>🐶🐶🐶 " + s + " 🐶🐶🐶<=<<")); + Arrays.stream(mes).forEach(s -> log.debug(">>=>🐶🐶🐶 {} 🐶🐶🐶<=<<", s)); } public static void execWingsSql(JdbcTemplate jdbcTemplate, String path) { diff --git a/wings/warlock-bond/src/main/java/pro/fessional/wings/warlock/service/perm/impl/WarlockRoleServiceImpl.java b/wings/warlock-bond/src/main/java/pro/fessional/wings/warlock/service/perm/impl/WarlockRoleServiceImpl.java index ec9ac5d3e..3f31d5491 100644 --- a/wings/warlock-bond/src/main/java/pro/fessional/wings/warlock/service/perm/impl/WarlockRoleServiceImpl.java +++ b/wings/warlock-bond/src/main/java/pro/fessional/wings/warlock/service/perm/impl/WarlockRoleServiceImpl.java @@ -132,6 +132,7 @@ public long create(@NotNull String name, String remark) { winRoleEntryDao.insert(po); } catch (Exception e) { + // noinspection StringConcatenationArgumentToLogCall log.error("failed to insert role entry. name=" + name + ", remark=" + remark, e); throw new CodeException(e, CommonErrorEnum.AssertState2, "role.name", name); } diff --git a/wings/warlock-bond/src/main/java/pro/fessional/wings/warlock/service/user/impl/WarlockUserAuthnServiceImpl.java b/wings/warlock-bond/src/main/java/pro/fessional/wings/warlock/service/user/impl/WarlockUserAuthnServiceImpl.java index 7e3a4b6d4..9be5fb0e4 100644 --- a/wings/warlock-bond/src/main/java/pro/fessional/wings/warlock/service/user/impl/WarlockUserAuthnServiceImpl.java +++ b/wings/warlock-bond/src/main/java/pro/fessional/wings/warlock/service/user/impl/WarlockUserAuthnServiceImpl.java @@ -109,6 +109,7 @@ public long create(long userId, @NotNull Authn authn) { winUserAuthnDao.insert(auth); } catch (Exception e) { + // noinspection StringConcatenationArgumentToLogCall log.error("failed to insert authn " + authn, e); // Possibly unique key or value is oversize throw new CodeException(e, CommonErrorEnum.DataExisted); From 3790207f29beda0e13c6a4848443c8f7f5c54d2a Mon Sep 17 00:00:00 2001 From: trydofor Date: Mon, 5 Aug 2024 19:54:40 +0800 Subject: [PATCH 39/51] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20executor=20shutdown?= =?UTF-8?q?=20quickly=20and=20now=20#283?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- observe/docs | 2 +- .../service/impl/TinyMailServiceImpl.java | 88 +++++----- .../wings-tinymail-service-79.properties | 4 +- .../mail/service/TinyMailServiceDbTest.java | 2 +- .../service/impl/TinyTaskExecServiceImpl.java | 81 ++++++--- .../service/impl/TinyTaskServiceImpl.java | 2 +- .../tiny/task/other/ExecutorServiceTest.java | 60 ++++--- .../slardar/async/TaskSchedulerHelper.java | 159 ++++++++++++++++-- 8 files changed, 271 insertions(+), 127 deletions(-) diff --git a/observe/docs b/observe/docs index b655b98bf..c137a343c 160000 --- a/observe/docs +++ b/observe/docs @@ -1 +1 @@ -Subproject commit b655b98bfadf5279196e39ed38f494ffe2e0bba0 +Subproject commit c137a343ce1eb51246f6c77ea845a3abd9bb5b2b diff --git a/radiant/tiny-mail/src/main/java/pro/fessional/wings/tiny/mail/service/impl/TinyMailServiceImpl.java b/radiant/tiny-mail/src/main/java/pro/fessional/wings/tiny/mail/service/impl/TinyMailServiceImpl.java index 90b3d4211..8b3c57161 100644 --- a/radiant/tiny-mail/src/main/java/pro/fessional/wings/tiny/mail/service/impl/TinyMailServiceImpl.java +++ b/radiant/tiny-mail/src/main/java/pro/fessional/wings/tiny/mail/service/impl/TinyMailServiceImpl.java @@ -2,19 +2,19 @@ import jakarta.mail.MessagingException; import lombok.Data; -import lombok.Getter; import lombok.Setter; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import org.springframework.beans.factory.DisposableBean; import org.springframework.beans.factory.InitializingBean; import org.springframework.beans.factory.ObjectProvider; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.autoconfigure.task.TaskSchedulingProperties; import org.springframework.boot.task.ThreadPoolTaskSchedulerBuilder; +import org.springframework.context.event.ContextClosedEvent; +import org.springframework.context.event.EventListener; import org.springframework.core.io.Resource; import org.springframework.core.io.ResourceLoader; import org.springframework.mail.MailParseException; @@ -69,8 +69,8 @@ import java.util.PriorityQueue; import java.util.Set; import java.util.TreeMap; +import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ScheduledFuture; -import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicLong; import java.util.concurrent.atomic.AtomicReference; @@ -84,7 +84,7 @@ @Service @ConditionalWingsEnabled @Slf4j -public class TinyMailServiceImpl implements TinyMailService, InitializingBean, DisposableBean { +public class TinyMailServiceImpl implements TinyMailService, InitializingBean { @Setter(onMethod_ = { @Value("${spring.application.name}") }) protected String appName; @@ -114,7 +114,7 @@ public class TinyMailServiceImpl implements TinyMailService, InitializingBean, D protected SingletonSupplier> statusHookHolder; protected final PriorityQueue asyncMailQueue = new PriorityQueue<>(); - protected final TreeMap> asyncMailSched = new TreeMap<>(); + protected final ConcurrentHashMap> asyncMailTask = new ConcurrentHashMap<>(); @Override public boolean send(@NotNull TinyMail message, boolean retry) { @@ -212,7 +212,8 @@ public void afterPropertiesSet() { final long idle = tinyMailServiceProp.getBootScan().toMillis(); if (idle > 0) { log.info("tiny-mail schedule boot-scan after={} ms", idle); - taskScheduler.schedule(this::scanIdle, Instant.ofEpochMilli(ThreadNow.millis() + idle)); + var task = taskScheduler.schedule(this::scanIdle, Instant.ofEpochMilli(ThreadNow.millis() + idle)); + idleScanTask.set(task); } statusHookHolder = SingletonSupplier.of(() -> statusHookProvider.orderedStream().toList()); @@ -228,12 +229,30 @@ public void afterPropertiesSet() { }); } - @Override + @EventListener(ContextClosedEvent.class) public void destroy() { isShutdown = true; + if (taskScheduler != null) { taskScheduler.shutdown(); } + + int size = 0; + for (ScheduledFuture task : asyncMailTask.values()) { + task.cancel(false); + size++; + } + + if (size > 0) { + asyncMailTask.clear(); + log.info("cancel async mail for shutdown, size={}", size); + } + + ScheduledFuture task = idleScanTask.get(); + if (task != null) { + task.cancel(false); + log.info("cancel async scan mail for shutdown"); + } } @Override @@ -331,10 +350,8 @@ public ArrayList listAsyncMailQueue() { } @NotNull - public TreeMap> listAsyncMailSched() { - synchronized (asyncMailSched) { - return new TreeMap(asyncMailSched); - } + public TreeMap> listAsyncMailTask() { + return new TreeMap(asyncMailTask); } protected final AtomicLong idleScanMills = new AtomicLong(-1); @@ -922,11 +939,16 @@ private void planAsyncMail(long next) { } final long nxt = (next / 1_000L + 1) * 1_000L; // ceiling to second - synchronized (asyncMailSched) { - asyncMailSched.computeIfAbsent(nxt, k -> - taskScheduler.schedule(this::sendAsyncMail, Instant.ofEpochMilli(nxt)) - ); - } + asyncMailTask.computeIfAbsent(nxt, k -> + taskScheduler.schedule(() -> { + try { + sendAsyncMail(); + } + finally { + asyncMailTask.remove(k); + } + }, Instant.ofEpochMilli(nxt)) + ); } private void sendAsyncMail() { @@ -1047,41 +1069,7 @@ private void sendAsyncMail() { log.debug("plan tiny-mail queue-size={}, idle={}", qs, tinyMailServiceProp.getTryNext()); } } - - trimAsyncMailSched(); - } - } - - private final AtomicInteger trimSchedConter = new AtomicInteger(0); - @Setter - @Getter - private int maxAsyncSched = 1; - - private void trimAsyncMailSched() { - synchronized (trimSchedConter) { - if (trimSchedConter.get() > maxAsyncSched) return; - trimSchedConter.incrementAndGet(); } - - taskScheduler.schedule(() -> { - trimSchedConter.decrementAndGet(); - - final int ts; - synchronized (asyncMailSched) { - asyncMailSched.entrySet().removeIf(it -> it.getValue().isDone()); - ts = asyncMailSched.size(); - } - - final int ws = tinyMailServiceProp.getWarnSize(); - if (ts > ws) { - log.warn("plan tiny-mail sched-size={}", ts); - } - else { - log.debug("plan tiny-mail sched-size={}", ts); - } - } - , Instant.ofEpochMilli(ThreadNow.millis() + 1_000) - ); } @Nullable diff --git a/radiant/tiny-mail/src/main/resources/wings-conf/wings-tinymail-service-79.properties b/radiant/tiny-mail/src/main/resources/wings-conf/wings-tinymail-service-79.properties index 872510e71..61797385c 100644 --- a/radiant/tiny-mail/src/main/resources/wings-conf/wings-tinymail-service-79.properties +++ b/radiant/tiny-mail/src/main/resources/wings-conf/wings-tinymail-service-79.properties @@ -21,6 +21,6 @@ wings.tiny.mail.service.only-run=true ## TaskSchedulingProperties wings.tiny.mail.service.scheduler.pool.size=2 -wings.tiny.mail.service.scheduler.shutdown.await-termination=true -wings.tiny.mail.service.scheduler.shutdown.await-termination-period=60s +wings.tiny.mail.service.scheduler.shutdown.await-termination=false +#wings.tiny.mail.service.scheduler.shutdown.await-termination-period=15s wings.tiny.mail.service.scheduler.thread-name-prefix=mail- diff --git a/radiant/tiny-mail/src/test/java/pro/fessional/wings/tiny/mail/service/TinyMailServiceDbTest.java b/radiant/tiny-mail/src/test/java/pro/fessional/wings/tiny/mail/service/TinyMailServiceDbTest.java index aebf259c7..b68d54feb 100644 --- a/radiant/tiny-mail/src/test/java/pro/fessional/wings/tiny/mail/service/TinyMailServiceDbTest.java +++ b/radiant/tiny-mail/src/test/java/pro/fessional/wings/tiny/mail/service/TinyMailServiceDbTest.java @@ -222,7 +222,7 @@ else if (txtNg.contains(id)) { Sleep.ignoreInterrupt(2_000L); ArrayList queue = tinyMailService.listAsyncMailQueue(); Assertions.assertTrue(queue.isEmpty()); - TreeMap> sched = tinyMailService.listAsyncMailSched(); + TreeMap> sched = tinyMailService.listAsyncMailTask(); Assertions.assertTrue(sched.isEmpty()); // retry as if it was fixed, but 1st send error diff --git a/radiant/tiny-task/src/main/java/pro/fessional/wings/tiny/task/service/impl/TinyTaskExecServiceImpl.java b/radiant/tiny-task/src/main/java/pro/fessional/wings/tiny/task/service/impl/TinyTaskExecServiceImpl.java index bebb7d792..7d6a73fc3 100644 --- a/radiant/tiny-task/src/main/java/pro/fessional/wings/tiny/task/service/impl/TinyTaskExecServiceImpl.java +++ b/radiant/tiny-task/src/main/java/pro/fessional/wings/tiny/task/service/impl/TinyTaskExecServiceImpl.java @@ -4,10 +4,11 @@ import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.jooq.Field; -import org.springframework.beans.factory.DisposableBean; import org.springframework.beans.factory.InitializingBean; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.event.ContextClosedEvent; +import org.springframework.context.event.EventListener; import org.springframework.scheduling.Trigger; import org.springframework.scheduling.support.CronTrigger; import org.springframework.scheduling.support.PeriodicTrigger; @@ -15,6 +16,7 @@ import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Propagation; import pro.fessional.mirana.cast.BoxedCastUtil; +import pro.fessional.mirana.data.U; import pro.fessional.mirana.lock.JvmStaticGlobalLock; import pro.fessional.mirana.pain.ThrowableUtil; import pro.fessional.mirana.stat.JvmStat; @@ -72,9 +74,9 @@ @Service @ConditionalWingsEnabled @Slf4j -public class TinyTaskExecServiceImpl implements TinyTaskExecService, InitializingBean, DisposableBean { +public class TinyTaskExecServiceImpl implements TinyTaskExecService, InitializingBean { - protected static final ConcurrentHashMap> Handle = new ConcurrentHashMap<>(); + protected static final ConcurrentHashMap, Long, String>> Handle = new ConcurrentHashMap<>(); protected static final ConcurrentHashMap Cancel = new ConcurrentHashMap<>(); protected static final ConcurrentHashMap Booted = new ConcurrentHashMap<>(); protected static final ConcurrentHashMap Untune = new ConcurrentHashMap<>(); @@ -99,23 +101,27 @@ public class TinyTaskExecServiceImpl implements TinyTaskExecService, Initializin @Setter(onMethod_ = { @Autowired }) protected TinyTaskExecProp execProp; - protected volatile boolean isShutdown = false; + protected volatile boolean isShutdownFast = false; + protected volatile boolean isShutdownSlow = false; @Override public void afterPropertiesSet() { - isShutdown = false; + isShutdownFast = false; + isShutdownSlow = false; } - @Override + @EventListener(ContextClosedEvent.class) public void destroy() { - isShutdown = true; + log.info("tiny-task shutdown for ContextClosedEvent"); + isShutdownFast = true; + isShutdownSlow = true; for (var en : Handle.entrySet()) { - var task = en.getValue(); - if (task.isDone()) continue; - - log.info("try to cancal tiny-task for shutdown, id={}", en.getKey()); + var tvl = en.getValue(); + var task = tvl.one(); + log.info("try to cancal tiny-task for shutdown, id={}, key={}, next_sys={}", en.getKey(), tvl.three(), DateLocaling.sysLdt(tvl.two())); task.cancel(false); } + Handle.clear(); } @Override @@ -126,19 +132,31 @@ public boolean launch(long id) { @Override public boolean force(long id) { - if (isShutdown) { - log.warn("skip tiny-task for shutdwon, force id={}", id); + if (isShutdownFast && isShutdownSlow) { + log.warn("cancel tiny-task for shutdown all on force, id={}", id); return false; } final WinTaskDefine td = winTaskDefineDao.fetchOneById(id); if (td == null) { - log.info("skip tiny-task for not found, id={}", id); + log.info("skip tiny-task for not found on force, id={}", id); return false; } final boolean fast = BoxedCastUtil.orTrue(td.getTaskerFast()); - final var scheduler = fast ? TaskSchedulerHelper.Fast() : TaskSchedulerHelper.Scheduled(); + if (fast && isShutdownFast || !fast && isShutdownSlow) { + log.warn("cancal tiny-task for shutdown on force, fast={}, id={}", fast, id); + return false; + } + + final var scheduler = TaskSchedulerHelper.Scheduler(fast); + if (scheduler.getScheduledExecutor().isShutdown()) { + log.warn("cancal tiny-task for Executor shutdown on force, fast={}, id={}", fast, id); + if (fast) isShutdownFast = true; + else isShutdownSlow = true; + return false; + } + scheduler.schedule(() -> { long execTms = ThreadNow.millis(); long doneTms = -1; @@ -190,22 +208,23 @@ public boolean force(long id) { } } }, Instant.ofEpochMilli(ThreadNow.millis())); + return true; } @Override public boolean cancel(long id) { Cancel.put(id, Boolean.TRUE); - final ScheduledFuture ft = Handle.get(id); - if (ft == null) { + final var tvl = Handle.get(id); + if (tvl == null) { log.info("cancel not found, id={}", id); return true; } - final boolean r = ft.cancel(false); + final boolean r = tvl.one().cancel(false); if (r) { Handle.remove(id); } - log.info("cancel success={}, id={}", r, id); + log.info("cancel success, id={}, key={}, next_sys={}", id, tvl.three(), DateLocaling.sysLdt(tvl.two())); return r; } @@ -220,8 +239,8 @@ public Set running() { } private boolean relaunch(long id) { - if (isShutdown) { - log.warn("skip tiny-task for shutdwon, relaunch id={}", id); + if (isShutdownFast && isShutdownSlow) { + log.warn("cancel tiny-task for shutdown all on relaunch, id={}", id); return false; } @@ -229,13 +248,13 @@ private boolean relaunch(long id) { try { lock.lock(); if (Handle.containsKey(id)) { - log.info("skip tiny-task for launching, id={}", id); + log.info("skip tiny-task on launching, id={}", id); return false; } final WinTaskDefine td = winTaskDefineDao.fetchOneById(id); if (td == null) { - log.info("skip tiny-task for not found, relaunch id={}", id); + log.info("skip tiny-task for not found on relaunch id={}", id); return false; } @@ -253,15 +272,21 @@ private boolean relaunch(long id) { saveNextExec(next, td); final boolean fast = BoxedCastUtil.orTrue(td.getTaskerFast()); - final var taskScheduler = fast ? TaskSchedulerHelper.Fast() : TaskSchedulerHelper.Scheduled(); + if (fast && isShutdownFast || !fast && isShutdownSlow) { + log.warn("cancal tiny-task for shutdown on relaunch, fast={}, id={}", fast, id); + return false; + } - if (taskScheduler.getScheduledExecutor().isShutdown()) { - log.error("TaskScheduler={} is shutdown, id={}, prop={}", fast, id, key); + final var scheduler = TaskSchedulerHelper.Scheduler(fast); + if (scheduler.getScheduledExecutor().isShutdown()) { + log.warn("cancal tiny-task for Executor shutdown on relaunch, fast={}, id={}, prop={}", fast, id, key); + if (fast) isShutdownFast = true; + else isShutdownSlow = true; return false; } log.info("prepare tiny-task id={}, prop={}", id, key); - final ScheduledFuture handle = taskScheduler.schedule(() -> { + final ScheduledFuture handle = scheduler.schedule(() -> { long execTms = ThreadNow.millis(); try { if (notNextLock(td, execTms)) { @@ -333,7 +358,7 @@ private boolean relaunch(long id) { }, Instant.ofEpochMilli(next)); // - Handle.put(id, handle); + Handle.put(id, U.of(handle, next, key)); return true; } finally { diff --git a/radiant/tiny-task/src/main/java/pro/fessional/wings/tiny/task/service/impl/TinyTaskServiceImpl.java b/radiant/tiny-task/src/main/java/pro/fessional/wings/tiny/task/service/impl/TinyTaskServiceImpl.java index 8cf11013f..23152963a 100644 --- a/radiant/tiny-task/src/main/java/pro/fessional/wings/tiny/task/service/impl/TinyTaskServiceImpl.java +++ b/radiant/tiny-task/src/main/java/pro/fessional/wings/tiny/task/service/impl/TinyTaskServiceImpl.java @@ -36,7 +36,7 @@ public class TinyTaskServiceImpl implements TinyTaskService { @Override @NotNull public ThreadPoolTaskScheduler referScheduler(boolean fast) { - return fast ? TaskSchedulerHelper.Fast() : TaskSchedulerHelper.Scheduled(); + return TaskSchedulerHelper.Scheduler(fast); } @Override diff --git a/radiant/tiny-task/src/test/java/pro/fessional/wings/tiny/task/other/ExecutorServiceTest.java b/radiant/tiny-task/src/test/java/pro/fessional/wings/tiny/task/other/ExecutorServiceTest.java index 9110285cd..2d1159140 100644 --- a/radiant/tiny-task/src/test/java/pro/fessional/wings/tiny/task/other/ExecutorServiceTest.java +++ b/radiant/tiny-task/src/test/java/pro/fessional/wings/tiny/task/other/ExecutorServiceTest.java @@ -2,14 +2,13 @@ import io.qameta.allure.TmsLink; import lombok.extern.slf4j.Slf4j; +import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler; import pro.fessional.mirana.time.Sleep; import pro.fessional.wings.slardar.async.TaskSchedulerHelper; import pro.fessional.wings.testing.silencer.TestingLoggerAssert; -import java.time.Instant; import java.util.concurrent.ScheduledFuture; /** @@ -17,8 +16,8 @@ * @since 2022-12-13 */ @SpringBootTest(properties = { - "logging.level.root=DEBUG", // AssertionLogger - "spring.task.scheduling.shutdown.await-termination-period=2s", + "logging.level.root=DEBUG", // AssertionLogger + "spring.task.scheduling.shutdown.await-termination-period=2s", }) @Slf4j class ExecutorServiceTest { @@ -38,54 +37,53 @@ void cancelSchedule() { al.rule(".. cancel", event -> event.getFormattedMessage().contains(".. cancel=true")); al.start(); - final ThreadPoolTaskScheduler scheduler = TaskSchedulerHelper.Scheduled(); - final ScheduledFuture f1 = scheduler.schedule(() -> log.info("-1 run={}", System.currentTimeMillis()), - Instant.ofEpochMilli(System.currentTimeMillis() - 1000)); + final ScheduledFuture f1 = TaskSchedulerHelper.Scheduled(-1000L, () -> log.info("-1 run={}", System.currentTimeMillis())); Sleep.ignoreInterrupt(500); log.info("-1 cancel={}", f1.cancel(false)); - final ScheduledFuture f2 = scheduler.schedule(() -> log.info("=0 run={}", System.currentTimeMillis()), - Instant.ofEpochMilli(System.currentTimeMillis())); + final ScheduledFuture f2 = TaskSchedulerHelper.Scheduled(0L, () -> log.info("=0 run={}", System.currentTimeMillis())); Sleep.ignoreInterrupt(500); log.info("=0 cancel={}", f2.cancel(false)); - final ScheduledFuture f3 = scheduler.schedule(() -> log.info("+1 run={}", System.currentTimeMillis()), - Instant.ofEpochMilli(System.currentTimeMillis() + 1000)); + final ScheduledFuture f3 = TaskSchedulerHelper.Scheduled(1000L, () -> log.info("+1 run={}", System.currentTimeMillis())); Sleep.ignoreInterrupt(500); log.info("+1 cancel={}", f3.cancel(false)); - final ScheduledFuture f4 = scheduler.schedule(() -> { - for (int i = 0; i < 10; i++) { - log.info("== run={}", i); - Sleep.ignoreInterrupt(100); - } - }, - Instant.ofEpochMilli(System.currentTimeMillis())); + final ScheduledFuture f4 = TaskSchedulerHelper.Scheduled(0L, () -> { + for (int i = 0; i < 10; i++) { + log.info("== run={}", i); + Sleep.ignoreInterrupt(100); + } + }); Sleep.ignoreInterrupt(500); log.info("== cancel={}", f4.cancel(false)); - final ScheduledFuture f5 = scheduler.schedule(() -> { - for (int i = 0; i < 10; i++) { - log.info(".. run={}", i); - try { - Thread.sleep(100); - } - catch (InterruptedException e) { - break; - } - } - }, - Instant.ofEpochMilli(System.currentTimeMillis())); + final ScheduledFuture f5 = TaskSchedulerHelper.Scheduled(0L, () -> { + for (int i = 0; i < 10; i++) { + log.info(".. run={}", i); + try { + Thread.sleep(100); + } + catch (InterruptedException e) { + break; + } + } + }); + + int size = TaskSchedulerHelper.runningSize(); + Assertions.assertTrue(size >= 1, "size=" + size); + Sleep.ignoreInterrupt(500); log.info(".. cancel={}", f5.cancel(true)); Sleep.ignoreInterrupt(2000); log.info("== done="); - al.stop(); al.assertCount(1); al.uninstall(); + + Assertions.assertEquals(0, TaskSchedulerHelper.runningSize()); } } diff --git a/wings/slardar/src/main/java/pro/fessional/wings/slardar/async/TaskSchedulerHelper.java b/wings/slardar/src/main/java/pro/fessional/wings/slardar/async/TaskSchedulerHelper.java index cea75834b..ede4d5a90 100644 --- a/wings/slardar/src/main/java/pro/fessional/wings/slardar/async/TaskSchedulerHelper.java +++ b/wings/slardar/src/main/java/pro/fessional/wings/slardar/async/TaskSchedulerHelper.java @@ -1,6 +1,7 @@ package pro.fessional.wings.slardar.async; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import org.springframework.beans.factory.DisposableBean; import org.springframework.boot.task.ThreadPoolTaskSchedulerBuilder; import org.springframework.scheduling.Trigger; @@ -9,7 +10,9 @@ import java.time.Instant; import java.util.Objects; +import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ScheduledFuture; +import java.util.concurrent.atomic.AtomicLong; /** * @author trydofor @@ -36,6 +39,10 @@ protected TaskSchedulerHelper(@NotNull ThreadPoolTaskScheduler fast, @NotNull Th @Override public void destroy() { helperPrepared = false; + for (var task : TaskRun.values()) { + task.cancel(false); + } + TaskRun.clear(); } /** @@ -52,9 +59,11 @@ public static TtlThreadPoolTaskScheduler Ttl(ThreadPoolTaskSchedulerBuilder buil return builder.configure(new TtlThreadPoolTaskScheduler()); } - /** - * @see org.springframework.scheduling.annotation.ScheduledAnnotationBeanPostProcessor#DEFAULT_TASK_SCHEDULER_BEAN_NAME - */ + @NotNull + public static ThreadPoolTaskScheduler Scheduler(boolean fast) { + return fast ? Fast() : Scheduled(); + } + @NotNull public static ThreadPoolTaskScheduler Fast() { if (FastScheduler == null) { @@ -64,7 +73,7 @@ public static ThreadPoolTaskScheduler Fast() { } /** - * see NamingSlardarConst#slardarHeavyScheduler + * @see org.springframework.scheduling.annotation.ScheduledAnnotationBeanPostProcessor#DEFAULT_TASK_SCHEDULER_BEAN_NAME */ @NotNull public static ThreadPoolTaskScheduler Scheduled() { @@ -78,7 +87,7 @@ public static ThreadPoolTaskScheduler Scheduled() { /** * just like default @Scheduled * - * @see org.springframework.scheduling.annotation.ScheduledAnnotationBeanPostProcessor.DEFAULT_TASK_SCHEDULER_BEAN_NAME + * @see org.springframework.scheduling.annotation.ScheduledAnnotationBeanPostProcessor#DEFAULT_TASK_SCHEDULER_BEAN_NAME */ public static void Scheduled(@NotNull Runnable task) { Scheduled().execute(task); @@ -87,28 +96,152 @@ public static void Scheduled(@NotNull Runnable task) { /** * just like default @Scheduled * - * @see org.springframework.scheduling.annotation.ScheduledAnnotationBeanPostProcessor.DEFAULT_TASK_SCHEDULER_BEAN_NAME + * @see org.springframework.scheduling.annotation.ScheduledAnnotationBeanPostProcessor#DEFAULT_TASK_SCHEDULER_BEAN_NAME + * @see ThreadPoolTaskScheduler#schedule(Runnable, Instant) */ + @NotNull public static ScheduledFuture Scheduled(long delayMs, @NotNull Runnable task) { - return Scheduled().schedule(task, Instant.ofEpochMilli(ThreadNow.millis() + delayMs)); + return Scheduled(Scheduled(), delayMs, task); } /** * just like default @Scheduled * - * @see org.springframework.scheduling.annotation.ScheduledAnnotationBeanPostProcessor.DEFAULT_TASK_SCHEDULER_BEAN_NAME + * @see org.springframework.scheduling.annotation.ScheduledAnnotationBeanPostProcessor#DEFAULT_TASK_SCHEDULER_BEAN_NAME + * @see ThreadPoolTaskScheduler#schedule(Runnable, Instant) */ - public static ScheduledFuture Scheduled(Instant start, @NotNull Runnable task) { - return Scheduled().schedule(task, start); + @NotNull + public static ScheduledFuture Scheduled(@NotNull Instant start, @NotNull Runnable task) { + return Scheduled(Scheduled(), start, task); } /** * just like default @Scheduled * - * @see org.springframework.scheduling.annotation.ScheduledAnnotationBeanPostProcessor.DEFAULT_TASK_SCHEDULER_BEAN_NAME + * @see org.springframework.scheduling.annotation.ScheduledAnnotationBeanPostProcessor#DEFAULT_TASK_SCHEDULER_BEAN_NAME + * @see ThreadPoolTaskScheduler#schedule(Runnable, Trigger) */ - public static ScheduledFuture Scheduled(Trigger trigger, @NotNull Runnable task) { - return Scheduled().schedule(task, trigger); + @Nullable + public static ScheduledFuture Scheduled(@NotNull Trigger trigger, @NotNull Runnable task) { + return Scheduled(Scheduled(), trigger, task); + } + + + /** + * just like default @Scheduled + * + * @see org.springframework.scheduling.annotation.ScheduledAnnotationBeanPostProcessor#DEFAULT_TASK_SCHEDULER_BEAN_NAME + */ + public static void Scheduled(boolean fast, @NotNull Runnable task) { + Scheduler(fast).execute(task); + } + + /** + * just like default @Scheduled + * + * @see org.springframework.scheduling.annotation.ScheduledAnnotationBeanPostProcessor#DEFAULT_TASK_SCHEDULER_BEAN_NAME + * @see ThreadPoolTaskScheduler#schedule(Runnable, Instant) + */ + @NotNull + public static ScheduledFuture Scheduled(boolean fast, long delayMs, @NotNull Runnable task) { + return Scheduled(Scheduler(fast), delayMs, task); + } + + /** + * just like default @Scheduled + * + * @see org.springframework.scheduling.annotation.ScheduledAnnotationBeanPostProcessor#DEFAULT_TASK_SCHEDULER_BEAN_NAME + * @see ThreadPoolTaskScheduler#schedule(Runnable, Instant) + */ + @NotNull + public static ScheduledFuture Scheduled(boolean fast, @NotNull Instant start, @NotNull Runnable task) { + return Scheduled(Scheduler(fast), start, task); + } + + /** + * just like default @Scheduled + * + * @see org.springframework.scheduling.annotation.ScheduledAnnotationBeanPostProcessor#DEFAULT_TASK_SCHEDULER_BEAN_NAME + * @see ThreadPoolTaskScheduler#schedule(Runnable, Trigger) + */ + @Nullable + public static ScheduledFuture Scheduled(boolean fast, @NotNull Trigger trigger, @NotNull Runnable task) { + return Scheduled(Scheduler(fast), trigger, task); + } + + /** + * just like default @Scheduled + * + * @see org.springframework.scheduling.annotation.ScheduledAnnotationBeanPostProcessor#DEFAULT_TASK_SCHEDULER_BEAN_NAME + * @see ThreadPoolTaskScheduler#schedule(Runnable, Instant) + */ + @NotNull + public static ScheduledFuture Scheduled(@NotNull ThreadPoolTaskScheduler scheduler, long delayMs, @NotNull Runnable task) { + return Scheduled(scheduler, Instant.ofEpochMilli(ThreadNow.millis() + delayMs), task); + } + + /** + * just like default @Scheduled + * + * @see org.springframework.scheduling.annotation.ScheduledAnnotationBeanPostProcessor#DEFAULT_TASK_SCHEDULER_BEAN_NAME + * @see ThreadPoolTaskScheduler#schedule(Runnable, Instant) + */ + @NotNull + public static ScheduledFuture Scheduled(@NotNull ThreadPoolTaskScheduler scheduler, @NotNull Instant start, @NotNull Runnable task) { + final Task tsk = new Task(task); + final var future = scheduler.schedule(tsk, start); + if (tsk.run) { + TaskRun.put(tsk.seq, future); + } + return future; + } + + /** + * just like default @Scheduled + * + * @see org.springframework.scheduling.annotation.ScheduledAnnotationBeanPostProcessor#DEFAULT_TASK_SCHEDULER_BEAN_NAME + * @see ThreadPoolTaskScheduler#schedule(Runnable, Trigger) + */ + @Nullable + public static ScheduledFuture Scheduled(@NotNull ThreadPoolTaskScheduler scheduler, @NotNull Trigger trigger, @NotNull Runnable task) { + final Task tsk = new Task(task); + final var future = scheduler.schedule(tsk, trigger); + if (future != null && tsk.run) { + TaskRun.put(tsk.seq, future); + } + return future; + } + + /** + * clean done task and get the running size + */ + public static int runningSize() { + TaskRun.entrySet().removeIf(en -> en.getValue().isDone()); + return TaskRun.size(); + } + + private static final ConcurrentHashMap> TaskRun = new ConcurrentHashMap<>(); + private static final AtomicLong TaskSeq = new AtomicLong(0); + + private static class Task implements Runnable { + private final Long seq = TaskSeq.incrementAndGet(); + private volatile boolean run = true; + private final Runnable runnable; + + public Task(Runnable run) { + runnable = run; + } + + @Override + public void run() { + try { + runnable.run(); + } + finally { + run = false; + TaskRun.remove(seq); + } + } } /** From 6d7d3f51c5fa1db59c1f70729d04b5e084f471c2 Mon Sep 17 00:00:00 2001 From: trydofor Date: Tue, 6 Aug 2024 16:58:11 +0800 Subject: [PATCH 40/51] =?UTF-8?q?=F0=9F=90=9B=20typo=20var=20of=20track=20?= =?UTF-8?q?addr=20#282?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../wings/tiny/grow/track/impl/TinyTrackPreparerTermImpl.java | 2 +- .../resources/wings-conf/wings-remote-resolver-79.properties | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/radiant/tiny-grow/src/main/java/pro/fessional/wings/tiny/grow/track/impl/TinyTrackPreparerTermImpl.java b/radiant/tiny-grow/src/main/java/pro/fessional/wings/tiny/grow/track/impl/TinyTrackPreparerTermImpl.java index f3a858ce3..7cd207e23 100644 --- a/radiant/tiny-grow/src/main/java/pro/fessional/wings/tiny/grow/track/impl/TinyTrackPreparerTermImpl.java +++ b/radiant/tiny-grow/src/main/java/pro/fessional/wings/tiny/grow/track/impl/TinyTrackPreparerTermImpl.java @@ -36,7 +36,7 @@ public void prepare(@NotNull TinyTracking tracking) { } String adr = ctx.getTerminal(TerminalAddr); - if (adr != null) tracking.addEnv("addr", id); + if (adr != null) tracking.addEnv("addr", adr); String agt = ctx.getTerminal(TerminalAgent); if (agt != null) tracking.addEnv("agent", agt); } diff --git a/wings/slardar-webmvc/src/main/resources/wings-conf/wings-remote-resolver-79.properties b/wings/slardar-webmvc/src/main/resources/wings-conf/wings-remote-resolver-79.properties index 9f1eca7b5..d2a062af3 100644 --- a/wings/slardar-webmvc/src/main/resources/wings-conf/wings-remote-resolver-79.properties +++ b/wings/slardar-webmvc/src/main/resources/wings-conf/wings-remote-resolver-79.properties @@ -2,6 +2,7 @@ wings.slardar.remote.inner-ip[local-127]=127. wings.slardar.remote.inner-ip[local-192]=192. wings.slardar.remote.inner-ip[local-0v6]=0:0:0:0:0:0 +wings.slardar.remote.inner-ip[local-ev6]=:: wings.slardar.remote.inner-ip[local-0v4]=0.0.0. ## which header to get the real ip when behind proxy. From 49493bdf9066805042d508bd5c655ed83d2410c9 Mon Sep 17 00:00:00 2001 From: trydofor Date: Wed, 7 Aug 2024 09:22:06 +0800 Subject: [PATCH 41/51] =?UTF-8?q?=E2=AC=86=EF=B8=8F=20bump=20boot=20to=203?= =?UTF-8?q?.2.8=20#285?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pom.xml | 68 ++--- radiant/devs-mvndeps/pom.xml | 121 ++++---- wings/faceless-shard/pom.xml | 13 +- .../FacelessShardingSphereConfiguration.java | 13 +- .../spring/help/SecurityConfigHelper.java | 12 +- .../DummyHttpServletRequest.java} | 4 +- .../servlet/dummy/DummyServletContext.java | 283 ++++++++++++++++++ .../WarlockSecurityConfConfiguration.java | 228 +++++++------- 8 files changed, 526 insertions(+), 216 deletions(-) rename wings/slardar-webmvc/src/main/java/pro/fessional/wings/slardar/servlet/{request/FakeHttpServletRequest.java => dummy/DummyHttpServletRequest.java} (98%) create mode 100644 wings/slardar-webmvc/src/main/java/pro/fessional/wings/slardar/servlet/dummy/DummyServletContext.java diff --git a/pom.xml b/pom.xml index c228dcc13..f20f40a33 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ org.springframework.boot spring-boot-starter-parent - 3.2.2 + 3.2.8 @@ -23,7 +23,7 @@ 3.2.130-SNAPSHOT - 3.2.2 + 3.2.8 ${revision} @@ -40,47 +40,47 @@ 1.5.5.Final 0.2.0 - 33.0.0-jre - 2.15.1 + 33.2.1-jre + 2.16.1 4.4 - 1.11.0 + 1.12.0 2.2.3 2.7.3-SNAPSHOT 1.5.1 2.3.3 - 2.0.51 + 2.0.52 ${fastjson2.version} 5.6.0 2.14.5 - 1.77 + 1.78.1 1.16.6 - 5.4.1 + 5.5.0 - 3.0.2 + 3.2.0 - 2.3.0 - 3.2.2 - 7.4.0 - 2.9.0 - 2.25.0 - 1.2.21 - 1.37 + 2.5.0 + 3.2.3 + 7.12.1 + 2.11.0 + 2.29.0 + 1.2.23 + 1.37 1.6.0 1.0 - 3.1.0 - 1.6.13 + 3.2.4 + 1.7.0 4.3.0 - 0.8.11 - 1.9.10 + 0.8.12 + 1.9.20 1.18.20.0 - 3.2.0 - 3.4.1 + 3.3.0 + 3.4.3 0.3.0 - 3.4.1 - 2.16.2 + 3.5.0 + 2.17.1 ${project.basedir}/src/main/java ${project.basedir}/src/main/java-gen @@ -322,8 +322,15 @@ org.apache.shardingsphere - shardingsphere-jdbc-core + shardingsphere-jdbc ${shardingsphere.version} + + + + org.apache.shardingsphere + shardingsphere-test-util + + org.apache.shardingsphere - shardingsphere-jdbc-core + shardingsphere-jdbc ${shardingsphere.version} @@ -155,9 +158,62 @@ druid-spring-boot-starter ${druid.version} + + org.openjdk.jmh + jmh-core + ${jmh.version} + + + org.codehaus.mojo + versions-maven-plugin + + ${dependency-updates-file} + 100 + false + false + + .*[.-]android.* + .*[.-]SNAPSHOT.* + .*[.-]alpha.* + .*[.-]Beta.* + .*[.-]RC.* + .*[.-]M.* + \d{8,}\.\d{6,} + .*-b.* + + + org.springframework.boot:spring-boot + org.jetbrains:annotations + org.mapstruct:mapstruct-processor + com.google.guava:guava + commons-io:commons-io + org.apache.commons:commons-collections4 + org.apache.commons:commons-text + org.joda:joda-convert + pro.fessional:mirana + pro.fessional:meepo + pro.fessional:kaptcha + com.alibaba.fastjson2:fastjson2 + com.alibaba:fastjson + com.esotericsoftware:kryo + com.alibaba:transmittable-thread-local + org.bouncycastle:bcpkix-jdk18on + me.zhyd.oauth:JustAuth + org.apache.shardingsphere:shardingsphere-jdbc + org.apache.servicecomb:java-chassis-core + org.springdoc:springdoc-openapi-starter-webmvc-ui + de.codecentric:spring-boot-admin-starter-client + io.sentry:sentry-spring-boot-starter-jakarta + com.squareup.retrofit2:retrofit + io.qameta.allure:allure-java-commons + com.alibaba:druid-spring-boot-starter + org.openjdk.jmh:jmh-core + + + org.codehaus.mojo flatten-maven-plugin @@ -178,6 +234,11 @@ nexus-staging-maven-plugin ${nexus-staging-plugin.version} + + org.codehaus.mojo + build-helper-maven-plugin + ${build-helper-maven-plugin.version} + org.eluder.coveralls coveralls-maven-plugin @@ -188,15 +249,20 @@ jacoco-maven-plugin ${jacoco-maven-plugin.version} + + org.projectlombok + lombok-maven-plugin + ${lombok-maven-plugin.version} + org.jetbrains.dokka dokka-maven-plugin ${dokka-maven-plugin.version} - org.projectlombok - lombok-maven-plugin - ${lombok-maven-plugin.version} + io.github.git-commit-id + git-commit-id-maven-plugin + ${git-commit-id-maven-plugin.version} org.codehaus.mojo @@ -208,56 +274,11 @@ jib-maven-plugin ${jib-maven-plugin.version} - org.apache.maven.plugins maven-enforcer-plugin ${maven-enforcer-plugin.version} - - org.codehaus.mojo - versions-maven-plugin - - ${dependency-updates-file} - 100 - false - false - - .*[.-]android.* - .*[.-]SNAPSHOT.* - .*[.-]Beta.* - \d{8,}\.\d{6,} - .*-b.* - - - org.springframework.boot:spring-boot - org.jetbrains:annotations - org.mapstruct:mapstruct-processor - com.google.guava:guava - commons-io:commons-io - org.apache.commons:commons-collections4 - org.apache.commons:commons-text - org.joda:joda-convert - pro.fessional:mirana - pro.fessional:meepo - pro.fessional:kaptcha - com.alibaba.fastjson2:fastjson2 - com.alibaba:fastjson - com.esotericsoftware:kryo - com.alibaba:transmittable-thread-local - org.bouncycastle:bcpkix-jdk18on - me.zhyd.oauth:JustAuth - org.apache.shardingsphere:shardingsphere-jdbc-core - org.apache.servicecomb:java-chassis-core - org.springdoc:springdoc-openapi-starter-webmvc-ui - de.codecentric:spring-boot-admin-starter-client - io.sentry:sentry-spring-boot-starter-jakarta - com.squareup.retrofit2:retrofit - io.qameta.allure:allure-java-commons - com.alibaba:druid-spring-boot-starter - - - diff --git a/wings/faceless-shard/pom.xml b/wings/faceless-shard/pom.xml index c0b8c984d..7479e9e42 100644 --- a/wings/faceless-shard/pom.xml +++ b/wings/faceless-shard/pom.xml @@ -21,21 +21,10 @@ pro.fessional.wings faceless - - - org.glassfish.jaxb - jaxb-runtime - 2.3.8 - - - org.yaml - snakeyaml - 1.33 - org.apache.shardingsphere - shardingsphere-jdbc-core + shardingsphere-jdbc diff --git a/wings/faceless-shard/src/main/java/pro/fessional/wings/faceless/spring/bean/FacelessShardingSphereConfiguration.java b/wings/faceless-shard/src/main/java/pro/fessional/wings/faceless/spring/bean/FacelessShardingSphereConfiguration.java index 160916f93..ecbfe00c5 100644 --- a/wings/faceless-shard/src/main/java/pro/fessional/wings/faceless/spring/bean/FacelessShardingSphereConfiguration.java +++ b/wings/faceless-shard/src/main/java/pro/fessional/wings/faceless/spring/bean/FacelessShardingSphereConfiguration.java @@ -2,7 +2,9 @@ import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; -import org.apache.shardingsphere.driver.jdbc.core.driver.ShardingSphereURLManager; +import org.apache.shardingsphere.driver.ShardingSphereDriver; +import org.apache.shardingsphere.infra.url.core.ShardingSphereURL; +import org.apache.shardingsphere.infra.url.core.ShardingSphereURLLoadEngine; import org.apache.shardingsphere.infra.util.yaml.YamlEngine; import org.apache.shardingsphere.infra.yaml.config.pojo.YamlRootConfiguration; import org.apache.shardingsphere.infra.yaml.config.swapper.resource.YamlDataSourceConfigurationSwapper; @@ -20,6 +22,7 @@ /** * Config sharding datasource to DataSourceContext * + * @see ShardingSphereDriver * @author trydofor */ @@ -31,12 +34,16 @@ public class FacelessShardingSphereConfiguration { @Bean @ConditionalWingsEnabled public DataSourceContext.Customizer shardingDataSourceContext(@Value("${spring.datasource.url}") String jdbcUrl) throws Exception { - if (!jdbcUrl.startsWith("jdbc:shardingsphere:")) { + String urlPrefix = "jdbc:shardingsphere:"; + if (!jdbcUrl.startsWith(urlPrefix)) { log.info("FacelessShard skip shardingSphereCustomizer jdbcUrl=" + jdbcUrl); return ignored -> false; } - final byte[] yamlBytes = ShardingSphereURLManager.getContent(jdbcUrl, "jdbc:shardingsphere:"); + ShardingSphereURL shardingUrl = ShardingSphereURL.parse(jdbcUrl.substring(urlPrefix.length())); + ShardingSphereURLLoadEngine engine = new ShardingSphereURLLoadEngine(shardingUrl); + + final byte[] yamlBytes = engine.loadContent(); YamlRootConfiguration rootConfig = YamlEngine.unmarshal(yamlBytes, YamlRootConfiguration.class); final YamlDataSourceConfigurationSwapper configurationSwapper = new YamlDataSourceConfigurationSwapper(); final Map dsMap = configurationSwapper.swapToDataSources(rootConfig.getDataSources()); diff --git a/wings/slardar-sprint/src/main/java/pro/fessional/wings/slardar/spring/help/SecurityConfigHelper.java b/wings/slardar-sprint/src/main/java/pro/fessional/wings/slardar/spring/help/SecurityConfigHelper.java index 0097dfe29..d81f80d40 100644 --- a/wings/slardar-sprint/src/main/java/pro/fessional/wings/slardar/spring/help/SecurityConfigHelper.java +++ b/wings/slardar-sprint/src/main/java/pro/fessional/wings/slardar/spring/help/SecurityConfigHelper.java @@ -8,7 +8,8 @@ import org.springframework.web.cors.CorsConfigurationSource; import org.springframework.web.util.pattern.PathPattern; import pro.fessional.wings.slardar.security.WingsUserDetailsService; -import pro.fessional.wings.slardar.servlet.request.FakeHttpServletRequest; +import pro.fessional.wings.slardar.servlet.dummy.DummyHttpServletRequest; +import pro.fessional.wings.slardar.servlet.dummy.DummyServletContext; import pro.fessional.wings.slardar.spring.conf.WingsBindAuthnConfigurer; import java.net.URLEncoder; @@ -73,9 +74,9 @@ public static String encodePathPattern(@NotNull String path) { * fake the HttpServletRequest to test matcher */ @NotNull - public static FakeHttpServletRequest fakeMatcherRequest(@NotNull String path) { + public static DummyHttpServletRequest dummyMatcherRequest(@NotNull String path) { path = encodePathPattern(path); - FakeHttpServletRequest request = new FakeHttpServletRequest(); + DummyHttpServletRequest request = new DummyHttpServletRequest(); request.setPathInfo(path); request.setRequestURI(path); return request; @@ -86,11 +87,12 @@ public static FakeHttpServletRequest fakeMatcherRequest(@NotNull String path) { * see Failed to find servlet xx in the servlet context */ @NotNull - public static FakeHttpServletRequest fakeMatcherRequest(@NotNull String path, String servletName) { + public static DummyHttpServletRequest dummyMatcherRequest(@NotNull String path, String servletName) { path = encodePathPattern(path); - FakeHttpServletRequest request = new FakeHttpServletRequest(); + DummyHttpServletRequest request = new DummyHttpServletRequest(); request.setPathInfo(path); request.setRequestURI(path); + request.setServletContext(new DummyServletContext()); if (servletName != null) { request.getHttpServletMapping().setServletName(servletName); } diff --git a/wings/slardar-webmvc/src/main/java/pro/fessional/wings/slardar/servlet/request/FakeHttpServletRequest.java b/wings/slardar-webmvc/src/main/java/pro/fessional/wings/slardar/servlet/dummy/DummyHttpServletRequest.java similarity index 98% rename from wings/slardar-webmvc/src/main/java/pro/fessional/wings/slardar/servlet/request/FakeHttpServletRequest.java rename to wings/slardar-webmvc/src/main/java/pro/fessional/wings/slardar/servlet/dummy/DummyHttpServletRequest.java index 8aad9698d..0f843139e 100644 --- a/wings/slardar-webmvc/src/main/java/pro/fessional/wings/slardar/servlet/request/FakeHttpServletRequest.java +++ b/wings/slardar-webmvc/src/main/java/pro/fessional/wings/slardar/servlet/dummy/DummyHttpServletRequest.java @@ -1,4 +1,4 @@ -package pro.fessional.wings.slardar.servlet.request; +package pro.fessional.wings.slardar.servlet.dummy; import jakarta.servlet.AsyncContext; import jakarta.servlet.DispatcherType; @@ -39,7 +39,7 @@ */ @Getter @Setter -public class FakeHttpServletRequest implements HttpServletRequest { +public class DummyHttpServletRequest implements HttpServletRequest { private String authType; private Cookie[] cookies; diff --git a/wings/slardar-webmvc/src/main/java/pro/fessional/wings/slardar/servlet/dummy/DummyServletContext.java b/wings/slardar-webmvc/src/main/java/pro/fessional/wings/slardar/servlet/dummy/DummyServletContext.java new file mode 100644 index 000000000..2360e4b55 --- /dev/null +++ b/wings/slardar-webmvc/src/main/java/pro/fessional/wings/slardar/servlet/dummy/DummyServletContext.java @@ -0,0 +1,283 @@ +package pro.fessional.wings.slardar.servlet.dummy; + +import jakarta.servlet.Filter; +import jakarta.servlet.FilterRegistration; +import jakarta.servlet.RequestDispatcher; +import jakarta.servlet.Servlet; +import jakarta.servlet.ServletContext; +import jakarta.servlet.ServletException; +import jakarta.servlet.ServletRegistration; +import jakarta.servlet.SessionCookieConfig; +import jakarta.servlet.SessionTrackingMode; +import jakarta.servlet.descriptor.JspConfigDescriptor; +import lombok.Getter; +import lombok.Setter; +import org.springframework.util.ClassUtils; + +import java.io.InputStream; +import java.net.URL; +import java.util.Collections; +import java.util.Enumeration; +import java.util.EventListener; +import java.util.Map; +import java.util.Set; + +/** + * @author trydofor + * @since 2024-08-06 + */ +@Setter +@Getter +public class DummyServletContext implements ServletContext { + + private String contextPath = ""; + private int majorVersion = 6; + private int minorVersion = 0; + private int effectiveMajorVersion = 6; + private int effectiveMinorVersion = 0; + private String mimeType = "text"; + private String servletContextName = ""; + + @Override + public ServletContext getContext(String uripath) { + return this; + } + + @Override + public String getMimeType(String file) { + return mimeType; + } + + @Override + public Set getResourcePaths(String path) { + return Collections.emptySet(); + } + + @Override + public URL getResource(String path) { + return null; + } + + @Override + public InputStream getResourceAsStream(String path) { + return null; + } + + @Override + public RequestDispatcher getRequestDispatcher(String path) { + return null; + } + + @Override + public RequestDispatcher getNamedDispatcher(String name) { + return null; + } + + @Override + public void log(String msg) { + } + + @Override + public void log(String message, Throwable throwable) { + } + + @Override + public String getRealPath(String path) { + return path; + } + + @Override + public String getServerInfo() { + return this.getClass().getSimpleName(); + } + + @Override + public String getInitParameter(String name) { + return ""; + } + + @Override + public Enumeration getInitParameterNames() { + return Collections.emptyEnumeration(); + } + + @Override + public boolean setInitParameter(String name, String value) { + return false; + } + + @Override + public Object getAttribute(String name) { + return null; + } + + @Override + public Enumeration getAttributeNames() { + return Collections.emptyEnumeration(); + } + + @Override + public void setAttribute(String name, Object object) { + + } + + @Override + public void removeAttribute(String name) { + + } + + @Override + public ServletRegistration.Dynamic addServlet(String servletName, String className) { + throw new UnsupportedOperationException(); + } + + @Override + public ServletRegistration.Dynamic addServlet(String servletName, Servlet servlet) { + throw new UnsupportedOperationException(); + } + + @Override + public ServletRegistration.Dynamic addServlet(String servletName, Class servletClass) { + throw new UnsupportedOperationException(); + } + + @Override + public ServletRegistration.Dynamic addJspFile(String servletName, String jspFile) { + throw new UnsupportedOperationException(); + } + + @Override + public T createServlet(Class clazz) throws ServletException { + throw new UnsupportedOperationException(); + } + + @Override + public ServletRegistration getServletRegistration(String servletName) { + return null; + } + + @Override + public Map getServletRegistrations() { + return Collections.emptyMap(); + } + + @Override + public FilterRegistration.Dynamic addFilter(String filterName, String className) { + throw new UnsupportedOperationException(); + } + + @Override + public FilterRegistration.Dynamic addFilter(String filterName, Filter filter) { + throw new UnsupportedOperationException(); + } + + @Override + public FilterRegistration.Dynamic addFilter(String filterName, Class filterClass) { + throw new UnsupportedOperationException(); + } + + @Override + public T createFilter(Class clazz) throws ServletException { + throw new UnsupportedOperationException(); + } + + @Override + public FilterRegistration getFilterRegistration(String filterName) { + return null; + } + + @Override + public Map getFilterRegistrations() { + return Collections.emptyMap(); + } + + @Override + public SessionCookieConfig getSessionCookieConfig() { + return null; + } + + @Override + public void setSessionTrackingModes(Set sessionTrackingModes) { + + } + + @Override + public Set getDefaultSessionTrackingModes() { + return Collections.emptySet(); + } + + @Override + public Set getEffectiveSessionTrackingModes() { + return Collections.emptySet(); + } + + @Override + public void addListener(String className) { + + } + + @Override + public void addListener(T t) { + + } + + @Override + public void addListener(Class listenerClass) { + + } + + @Override + public T createListener(Class clazz) throws ServletException { + throw new UnsupportedOperationException(); + } + + @Override + public JspConfigDescriptor getJspConfigDescriptor() { + throw new UnsupportedOperationException(); + } + + @Override + public ClassLoader getClassLoader() { + return ClassUtils.getDefaultClassLoader(); + } + + @Override + public void declareRoles(String... roleNames) { + + } + + @Override + public String getVirtualServerName() { + return "Dummy"; + } + + @Override + public int getSessionTimeout() { + return 0; + } + + @Override + public void setSessionTimeout(int sessionTimeout) { + + } + + @Override + public String getRequestCharacterEncoding() { + return "UTF8"; + } + + @Override + public void setRequestCharacterEncoding(String encoding) { + + } + + @Override + public String getResponseCharacterEncoding() { + return "UTF8"; + } + + @Override + public void setResponseCharacterEncoding(String encoding) { + + } +} diff --git a/wings/warlock-shadow/src/main/java/pro/fessional/wings/warlock/spring/bean/WarlockSecurityConfConfiguration.java b/wings/warlock-shadow/src/main/java/pro/fessional/wings/warlock/spring/bean/WarlockSecurityConfConfiguration.java index 1b3511a82..46f175c00 100644 --- a/wings/warlock-shadow/src/main/java/pro/fessional/wings/warlock/spring/bean/WarlockSecurityConfConfiguration.java +++ b/wings/warlock-shadow/src/main/java/pro/fessional/wings/warlock/spring/bean/WarlockSecurityConfConfiguration.java @@ -31,7 +31,7 @@ import pro.fessional.wings.silencer.spring.boot.ConditionalWingsEnabled; import pro.fessional.wings.silencer.support.PropHelper; import pro.fessional.wings.slardar.security.WingsAuthDetailsSource; -import pro.fessional.wings.slardar.servlet.request.FakeHttpServletRequest; +import pro.fessional.wings.slardar.servlet.dummy.DummyHttpServletRequest; import pro.fessional.wings.slardar.servlet.response.ResponseHelper; import pro.fessional.wings.slardar.spring.conf.WingsBindLoginConfigurer; import pro.fessional.wings.slardar.spring.help.SecurityConfigHelper; @@ -304,98 +304,135 @@ else if ("fullyAuthenticated".equalsIgnoreCase(str)) { public ApplicationRunnerOrdered securityCheckUrlRunner(WarlockSecurityProp securityProp, ApplicationContext ctx) { log.info("WarlockShadow spring-runs securityCheckUrlRunner"); return new ApplicationRunnerOrdered(WingsOrdered.Lv1Config, ignored -> { - log.info("WarlockShadow check security url config"); - - String servletName = "dispatcherServlet"; - for (ServletRegistrationBean srb : ctx.getBeanProvider(ServletRegistrationBean.class)) { - if (srb.getServlet() instanceof DispatcherServlet) { - servletName = srb.getServletName(); - break; - } + try { + secCheckUrl(securityProp, ctx); } + catch (RuntimeException e) { + log.error("set wings.enabled.warlock.sec-check-url=false to skip check", e); + throw e; + } + }); + } - Map matchers = new LinkedHashMap<>(); - Map requests = new LinkedHashMap<>(); + private static void secCheckUrl(WarlockSecurityProp securityProp, ApplicationContext ctx) { + log.info("WarlockShadow check security url config"); - for (var en : securityProp.getWebIgnore().entrySet()) { - String ptn = en.getValue(); - if (!StringUtils.hasText(ptn)) continue; - matchers.put("WebIgnore:" + en.getKey(), ptn); - requests.put(ptn, SecurityConfigHelper.fakeMatcherRequest(ptn, servletName)); + String servletName = "dispatcherServlet"; + for (ServletRegistrationBean srb : ctx.getBeanProvider(ServletRegistrationBean.class)) { + if (srb.getServlet() instanceof DispatcherServlet) { + servletName = srb.getServletName(); + break; } - for (var en : securityProp.getPermitAll().entrySet()) { - String ptn = en.getValue(); - if (!StringUtils.hasText(ptn)) continue; - matchers.put("PermitAll:" + en.getKey(), ptn); - requests.put(ptn, SecurityConfigHelper.fakeMatcherRequest(ptn, servletName)); - } - for (var en : securityProp.getAuthenticated().entrySet()) { - String ptn = en.getValue(); + } + + Map matchers = new LinkedHashMap<>(); + Map requests = new LinkedHashMap<>(); + + for (var en : securityProp.getWebIgnore().entrySet()) { + String ptn = en.getValue(); + if (!StringUtils.hasText(ptn)) continue; + matchers.put("WebIgnore:" + en.getKey(), ptn); + requests.put(ptn, SecurityConfigHelper.dummyMatcherRequest(ptn, servletName)); + } + for (var en : securityProp.getPermitAll().entrySet()) { + String ptn = en.getValue(); + if (!StringUtils.hasText(ptn)) continue; + matchers.put("PermitAll:" + en.getKey(), ptn); + requests.put(ptn, SecurityConfigHelper.dummyMatcherRequest(ptn, servletName)); + } + for (var en : securityProp.getAuthenticated().entrySet()) { + String ptn = en.getValue(); + if (!StringUtils.hasText(ptn)) continue; + matchers.put("Authenticated:" + en.getKey(), ptn); + requests.put(ptn, SecurityConfigHelper.dummyMatcherRequest(ptn, servletName)); + } + for (var en : securityProp.getAuthority().entrySet()) { + int c = 0; + String k = en.getKey(); + for (String ptn : en.getValue()) { if (!StringUtils.hasText(ptn)) continue; - matchers.put("Authenticated:" + en.getKey(), ptn); - requests.put(ptn, SecurityConfigHelper.fakeMatcherRequest(ptn, servletName)); + matchers.put("Authority:" + k + "[" + (c++) + "]", ptn); + requests.put(ptn, SecurityConfigHelper.dummyMatcherRequest(ptn, servletName)); } - for (var en : securityProp.getAuthority().entrySet()) { - int c = 0; - String k = en.getKey(); - for (String ptn : en.getValue()) { - if (!StringUtils.hasText(ptn)) continue; - matchers.put("Authority:" + k + "[" + (c++) + "]", ptn); - requests.put(ptn, SecurityConfigHelper.fakeMatcherRequest(ptn, servletName)); + } + final AtomicReference opt = new AtomicReference<>(); + MatcherHelper matcherHelper = MatcherHelper.of(ctx, opt); + + // check including + for (var en : matchers.entrySet()) { + String ptn = en.getValue(); + requests.remove(ptn); + if (requests.isEmpty()) break; + + matcherHelper.requestMatchers(ptn); + RequestMatcher mt = opt.get(); + for (var er : requests.entrySet()) { + try { + if (mt.matches(er.getValue())) { + log.warn(en.getKey() + "=" + ptn + " should not contain " + er.getKey()); + } + } + catch (RuntimeException e) { + log.error("failed to check " + en.getKey() + "=" + ptn + " should not contain " + er.getKey()); + throw e; } } - final AtomicReference opt = new AtomicReference<>(); - MatcherHelper matcherHelper = MatcherHelper.of(ctx, opt); + } + matchers.clear(); + requests.clear(); - // check including - for (var en : matchers.entrySet()) { - String ptn = en.getValue(); - requests.remove(ptn); - if (requests.isEmpty()) break; + // check auth url + String loginPage = securityProp.getLoginPage(); + if (StringUtils.hasText(loginPage)) { + requests.put(loginPage, SecurityConfigHelper.dummyMatcherRequest(loginPage, servletName)); + } + String logoutUrl = securityProp.getLogoutUrl(); + if (StringUtils.hasText(logoutUrl)) { + requests.put(logoutUrl, SecurityConfigHelper.dummyMatcherRequest(logoutUrl, servletName)); + } + String loginProcUrl = securityProp.getLoginProcUrl(); + if (StringUtils.hasText(loginProcUrl)) { + requests.put(loginProcUrl, SecurityConfigHelper.dummyMatcherRequest(loginProcUrl, servletName)); + } - matcherHelper.requestMatchers(ptn); - RequestMatcher mt = opt.get(); - for (var er : requests.entrySet()) { - try { - if (mt.matches(er.getValue())) { - log.warn(en.getKey() + "=" + ptn + " should not contain " + er.getKey()); - } - } - catch (RuntimeException e) { - log.error("failed to check " + en.getKey() + "=" + ptn + " should not contain " + er.getKey()); - throw e; + StringBuilder err = new StringBuilder(); + for (var en : securityProp.getWebIgnore().entrySet()) { + String ptn = en.getValue(); + if (!StringUtils.hasText(ptn)) continue; + if (requests.isEmpty()) break; + + matcherHelper.requestMatchers(ptn); + RequestMatcher mt = opt.get(); + for (var er : requests.entrySet()) { + try { + if (mt.matches(er.getValue())) { + err.append("\nWebIgnore:").append(en.getKey()).append(" should exclude ").append(er.getKey()); } } + catch (RuntimeException e) { + log.error("failed to check " + en.getKey() + "=" + ptn + " should not contain " + er.getKey()); + throw e; + } } - matchers.clear(); - requests.clear(); - - // check auth url - String loginPage = securityProp.getLoginPage(); - if (StringUtils.hasText(loginPage)) { - requests.put(loginPage, SecurityConfigHelper.fakeMatcherRequest(loginPage, servletName)); - } - String logoutUrl = securityProp.getLogoutUrl(); - if (StringUtils.hasText(logoutUrl)) { - requests.put(logoutUrl, SecurityConfigHelper.fakeMatcherRequest(logoutUrl, servletName)); - } - String loginProcUrl = securityProp.getLoginProcUrl(); - if (StringUtils.hasText(loginProcUrl)) { - requests.put(loginProcUrl, SecurityConfigHelper.fakeMatcherRequest(loginProcUrl, servletName)); - } + } - StringBuilder err = new StringBuilder(); - for (var en : securityProp.getWebIgnore().entrySet()) { + String anyRequest = securityProp.getAnyRequest(); + if (!StringUtils.hasText(anyRequest) + || "permitAll".equalsIgnoreCase(anyRequest) + || "anonymous".equalsIgnoreCase(anyRequest)) { + for (var en : securityProp.getPermitAll().entrySet()) { String ptn = en.getValue(); if (!StringUtils.hasText(ptn)) continue; if (requests.isEmpty()) break; matcherHelper.requestMatchers(ptn); RequestMatcher mt = opt.get(); - for (var er : requests.entrySet()) { + for (var it = requests.entrySet().iterator(); it.hasNext(); ) { + var er = it.next(); try { if (mt.matches(er.getValue())) { - err.append("\nWebIgnore:").append(en.getKey()).append(" should exclude ").append(er.getKey()); + log.debug("WarlockShadow security url permit all include " + er.getKey()); + it.remove(); } } catch (RuntimeException e) { @@ -404,45 +441,18 @@ public ApplicationRunnerOrdered securityCheckUrlRunner(WarlockSecurityProp secur } } } - - String anyRequest = securityProp.getAnyRequest(); - if (!StringUtils.hasText(anyRequest) - || "permitAll".equalsIgnoreCase(anyRequest) - || "anonymous".equalsIgnoreCase(anyRequest)) { - for (var en : securityProp.getPermitAll().entrySet()) { - String ptn = en.getValue(); - if (!StringUtils.hasText(ptn)) continue; - if (requests.isEmpty()) break; - - matcherHelper.requestMatchers(ptn); - RequestMatcher mt = opt.get(); - for (var it = requests.entrySet().iterator(); it.hasNext(); ) { - var er = it.next(); - try { - if (mt.matches(er.getValue())) { - log.debug("WarlockShadow security url permit all include " + er.getKey()); - it.remove(); - } - } - catch (RuntimeException e) { - log.error("failed to check " + en.getKey() + "=" + ptn + " should not contain " + er.getKey()); - throw e; - } - } - } - if (!requests.isEmpty()) { - err.append("\nPermitAll should include urls: ").append(String.join(", ", requests.keySet())); - } + if (!requests.isEmpty()) { + err.append("\nPermitAll should include urls: ").append(String.join(", ", requests.keySet())); } + } - if (!err.isEmpty()) { - String msg = err.toString(); - log.error(msg); - throw new IllegalStateException( - "\nWarlockSecurityConfConfiguration has security url conflict to fix." + - "\nor disable checking by `wings.enabled.warlock.sec-check-url=false`" + - msg); - } - }); + if (!err.isEmpty()) { + String msg = err.toString(); + log.error(msg); + throw new IllegalStateException( + "\nWarlockSecurityConfConfiguration has security url conflict to fix." + + "\nor disable checking by `wings.enabled.warlock.sec-check-url=false`" + + msg); + } } } From 6805f6a6d4461348e07f049c806aca1cd9394586 Mon Sep 17 00:00:00 2001 From: trydofor Date: Thu, 8 Aug 2024 12:03:31 +0800 Subject: [PATCH 42/51] =?UTF-8?q?=F0=9F=A7=91=E2=80=8D=F0=9F=92=BB=20optim?= =?UTF-8?q?ize=20starter/release=20shell=20#286?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- observe/scripts/wings-docker.sh | 16 +- observe/scripts/wings-mysql-dump.sh | 18 +- observe/scripts/wings-mysql-user.sh | 10 +- observe/scripts/wings-release.sh | 95 +++++++--- observe/scripts/wings-starter.sh | 264 ++++++++++++++++------------ observe/scripts/wings-testing.sh | 6 +- 6 files changed, 248 insertions(+), 161 deletions(-) diff --git a/observe/scripts/wings-docker.sh b/observe/scripts/wings-docker.sh index c10ac3054..c773a2077 100755 --- a/observe/scripts/wings-docker.sh +++ b/observe/scripts/wings-docker.sh @@ -37,14 +37,14 @@ $IMAGE_ENV_JAVA_ADD \ ####### function show_help() { - echo -e '\033[32m clean \033[m clean docker- build dir of boot-jar' - echo -e '\033[32m print \033[m print docker- Dockerfile of boot-jar' - echo -e '\033[32m unzip \033[m unzip docker- files of boot-jar' - echo -e '\033[32m build \033[m build docker- image of boot-jar' - echo -e '\033[32m help \033[m show this' - echo -e '\033[32m \033[m only dependencies + spring-boot-loader' - echo -e '\033[32m \033[m + napshot-dependencies + application' - echo -e '\033[32m \033[m + ' + echo -e '\033[32m clean \033[0m clean docker- build dir of boot-jar' + echo -e '\033[32m print \033[0m print docker- Dockerfile of boot-jar' + echo -e '\033[32m unzip \033[0m unzip docker- files of boot-jar' + echo -e '\033[32m build \033[0m build docker- image of boot-jar' + echo -e '\033[32m help \033[0m show this' + echo -e '\033[32m \033[0m only dependencies + spring-boot-loader' + echo -e '\033[32m \033[0m + napshot-dependencies + application' + echo -e '\033[32m \033[0m + ' } function docker_file() { diff --git a/observe/scripts/wings-mysql-dump.sh b/observe/scripts/wings-mysql-dump.sh index 992769e46..a63b60a85 100755 --- a/observe/scripts/wings-mysql-dump.sh +++ b/observe/scripts/wings-mysql-dump.sh @@ -26,10 +26,10 @@ dumpopts=${*:3} logxopts="--no-data" confopts=--defaults-extra-file=$extracnf if [[ -f "$extracnf" ]]; then - echo -e "\033[0;33mNOTE: defaults-extra-file \033[m" + echo -e "\033[0;33mNOTE: defaults-extra-file \033[0m" grep -E "^(host|port|user)" "$extracnf" else - echo -e "\033[0;31mERROR: should specific mysql config(at param-1), eg. ~/my.cnf\033[m" + echo -e "\033[0;31mERROR: should specific mysql config(at param-1), eg. ~/my.cnf\033[0m" cat << 'EOF' [client] protocol=tcp @@ -52,9 +52,9 @@ unalias mysql >/dev/null 2>&1 unalias mysqldump >/dev/null 2>&1 if [[ "$database" == "" ]]; then - echo -e "\033[0;31mWARN: need database(at param-2) to dump, eg.\033[m" + echo -e "\033[0;31mWARN: need database(at param-2) to dump, eg.\033[0m" echo "./wings-mysql-dump.sh wings-mysql-client.cnf database --no-data" - echo -e "\033[0;33mNOTE:current databases \033[m" + echo -e "\033[0;33mNOTE:current databases \033[0m" # shellcheck disable=SC2086 mysql $confopts -N -e "show databases;" exit @@ -81,7 +81,7 @@ if [[ $logs_cnt == 0 ]]; then echo "no logs tables to dump" echo "-- no logs tables to dump" > "$dump_logs_file" else - echo -e "\033[0;33mNOTE: dump logs tables without data, count=$logs_cnt\033[m" + echo -e "\033[0;33mNOTE: dump logs tables without data, count=$logs_cnt\033[0m" # shellcheck disable=SC2046,SC2086 if mysqldump $confopts $dumpopts $logxopts \ @@ -98,7 +98,7 @@ if [[ $main_cnt == 0 ]]; then echo "no main tables to dump" echo "-- no main tables to dump" > "$dump_main_file" else - echo -e "\033[0;33mNOTE: dump main tables with data, count=$main_cnt\033[m" + echo -e "\033[0;33mNOTE: dump main tables with data, count=$main_cnt\033[0m" # shellcheck disable=SC2046,SC2086 if mysqldump $confopts $dumpopts \ "$database" $(grep -vE '\$|__' "$dump_tbl_file") > "$dump_main_file"; then @@ -109,13 +109,13 @@ else fi fi -echo -e "\033[0;33mNOTE: dump file $dump_head\033[m" +echo -e "\033[0;33mNOTE: dump file $dump_head\033[0m" echo >> "$dump_tbl_file" # shellcheck disable=SC2010 ls -lsh |grep "$dump_head" | tee -a "$dump_tbl_file" -echo -e "\033[0;33mNOTE: tips for zip, scp, restore \033[m" +echo -e "\033[0;33mNOTE: tips for zip, scp, restore \033[0m" tee -a "$dump_tip_file" << EOF ## checksum md5sum -c $dump_md5_file # checksum @@ -153,7 +153,7 @@ cat $dump_logs_file $dump_main_file \\ ./reset-password.sh \$mycnf \$newdb; EOF -echo -e "\033[0;33mNOTE: tar files into $dump_tar_file \033[m" +echo -e "\033[0;33mNOTE: tar files into $dump_tar_file \033[0m" tar -czf "$dump_tar_file" "$dump_tip_file" "$dump_tbl_file" "$dump_logs_file" "$dump_main_file" \ && md5sum "$dump_tar_file" | tee "$dump_md5_file" \ && rm -f "$dump_tbl_file" "$dump_logs_file" "$dump_main_file" diff --git a/observe/scripts/wings-mysql-user.sh b/observe/scripts/wings-mysql-user.sh index b6677651e..51a3d2938 100755 --- a/observe/scripts/wings-mysql-user.sh +++ b/observe/scripts/wings-mysql-user.sh @@ -33,7 +33,7 @@ command="$2" option="$3" if [[ "$command" == "" || "$command" == "help" || ! -f "$userenv" ]]; then - echo -e '\033[37;42;1mNOTE: users env file\033[m' + echo -e '\033[37;42;1mNOTE: users env file\033[0m' # https://dev.mysql.com/doc/refman/8.0/en/account-management-statements.html cat <<'EOF' execute=false @@ -54,7 +54,7 @@ host_app=10.11.% host_dev=% host_dba=% EOF - echo -e '\033[37;42;1mNOTE: user manage\033[m' + echo -e '\033[37;42;1mNOTE: user manage\033[0m' cat <<'EOF' RENAME USER 'trydofor'@'%' TO 'trydofor'@'127.0.%'; DROP USER IF EXISTS 'trydofor'@'%'; @@ -91,7 +91,7 @@ fi [[ "$host_dev" == "" ]] && host_dev=% [[ "$host_dba" == "" ]] && host_dba=% -echo -e '\033[37;42;1mNOTE: users and passwd\033[m' +echo -e '\033[37;42;1mNOTE: users and passwd\033[0m' grep -v '^#' </dev/null 2>&1 if [[ "$command" == "create" ]]; then @@ -148,7 +148,7 @@ if [[ "$execute" == "true" ]]; then unalias mysql >/dev/null 2>&1 if [[ -f "$option" ]]; then - echo -e "\033[0;33mNOTE: current option file \033[m" + echo -e "\033[0;33mNOTE: current option file \033[0m" cat "$option" mysql --defaults-extra-file="$option" -vvv --force < "$temp_sql" else diff --git a/observe/scripts/wings-release.sh b/observe/scripts/wings-release.sh index 4e9b362d4..8e635e098 100755 --- a/observe/scripts/wings-release.sh +++ b/observe/scripts/wings-release.sh @@ -1,11 +1,14 @@ #!/bin/bash -e -THIS_VERSION=2024-03-05 +THIS_VERSION=2024-08-08 cat < /data/wings-script/wings-release.sh" +# my-release.env" # If PACK_JAR is directory, SUB_FLAT determines the overwrite behavior. ################################################# EOF @@ -81,8 +84,9 @@ function build_mvn() { echo '#Generated by Wings Release Script' >$_git_log git branch -v >>$_git_log git log --pretty=format:'%H - %an, %ad %d : %s' --graph -10 >>$_git_log + echo >>$_git_log find . -type d -name 'resources' | grep '/src/main/' | while read -r res; do - echo "$res" >>$_res_log + echo "$res/$_git_log" >>$_res_log cp $_git_log "$res/" done @@ -90,15 +94,20 @@ function build_mvn() { # shellcheck disable=SC2086 mvn $MVN_PACK - echo -e "\033[37;42;1m ==== GitLogs $WORK_DIR ==== \033[0m" + echo -e "\033[37;42;1m ==== Git $WORK_DIR ==== \033[0m" cat "$_git_log" - echo - echo -e "\033[32m ==== git-log into ==== \033[0m" + echo -e "\033[32m ==== $_git_log ==== \033[0m" cat "$_res_log" - echo -e "\033[32m ==== git status ==== \033[0m" + + while read -r res; do + [[ -f "$res" ]] && rm -f "$res" + done < "$_res_log" rm -f "$_git_log" "$_res_log" + + echo -e "\033[32m ==== status ==== \033[0m" git status - echo -e "\033[32m ==== mvn version ==== \033[0m" + + echo -e "\033[37;42;1m ==== Mvn version ==== \033[0m" mvn --version } @@ -122,7 +131,7 @@ function build_web() { fi # build - echo -e "\033[32m web pack $_cmd \033[m" + echo -e "\033[32m web pack $_cmd \033[0m" if [[ "$_cmd" == "pnpm" ]]; then pnpm install pnpm $WEB_PACK @@ -224,6 +233,45 @@ echo "work-dir=$WORK_DIR" # check arg case "$1" in + last) + check_cmd git + echo -e "\033[37;42;1m ==== GIT $WORK_DIR ==== \033[0m" + git status + git log --pretty=format:'%H - %an, %ad %d : %s' --graph -10 + echo -e "\033[37;42;1m ==== DST package ==== \033[0m" + _dst="" + for _jar in $PACK_JAR; do + if [[ -f "$_jar" || -d "$_jar" ]]; then + ls -l "$_jar" + _dst=$(realpath "$_jar") + else + _tmp=$(find . -type f -name "$_jar") + if [[ -f "$_tmp" ]]; then + ls -l "$_tmp" + _dst=$(realpath "$_tmp") + fi + fi + done + + echo -e "\033[37;42;1m ==== DST build info ==== \033[0m" + if [[ -d "$_dst" ]]; then + find "$_jar" -maxdepth 1 -name 'index.html' | while read -r _idx; do + echo "$_dst/index.html" + grep 'WingsGitHash' "$_idx" | sed -n 's/.*\(\).*/\1/p' + break + done + elif [[ -f "$_dst" && $_dst == *.jar ]]; then + giti=$(jar tf "$_dst" 2>/dev/null | grep git.properties ) + if [[ "$giti" != "" ]]; then + tmp="./tmp-$BOOT_MD5" + mkdir -p "$tmp" + (cd "$tmp" && jar xf "$_dst" "$giti") + echo "$_dst" + grep -vE '=$' "$tmp/$giti" + rm -rf "$tmp" + fi + fi + ;; pull) check_cmd git @@ -250,23 +298,23 @@ case "$1" in _tmp=$(find . -type f -name "$_jar") if [[ ! -f "$_tmp" ]]; then echo -e "\033[31mERROR: not file. $_jar \033[0m" - _jar_info="$_jar_info skip \033[31m $_jar \033[m => not find\n" + _jar_info="$_jar_info skip \033[31m $_jar \033[0m => not find\n" continue fi fi _rp=$(realpath "$_tmp") if [[ "$_yna" != "a" ]]; then - echo -e "[y/n/a]? \033[32m $_jar \033[m => $_rp" + echo -e "[y/n/a]? \033[32m $_jar \033[0m => $_rp" read -r _yna /data/wings-script/wings-starter.sh" + echo -e "# my-starter.env" + echo -e "# only one boot.jar run on one host, rename it to run more copies." + echo -e "# 'BOOT_ARG|JAVA_ARG|JDK8_ARG|JDK9_ARG' can be lazily evaluated" + echo -e "# in evaluation, ' for delayed, \" for immediate." + echo -e "#################################################" + echo -e '\033[32m docker \033[0m start in docker with console log' + echo -e '\033[32m start \033[0m start the {boot-jar} and tail the log' + echo -e '\033[32m starts \033[0m start but Not wait log' + echo -e '\033[32m stop [snd=30]\033[0m stop the {boot-jar} gracefully in {snd} seconds' + echo -e '\033[32m stops [snd=30]\033[0m stop but Not confirm' + echo -e '\033[32m status \033[0m show the {boot-jar} runtime status' + echo -e '\033[32m warn \033[0m monitor the {boot-jar} and log' + echo -e '\033[32m live \033[0m monitor the {boot-jar} and auto restart if lost pid' + echo -e '\033[32m clean [days=30] [y] \033[0m clean up boot out/log/jar {days} ago but newest' + echo -e '\033[32m clean-out [days=30] [y] \033[0m clean up boot-out {days} ago but newest' + echo -e '\033[32m clean-log [days=30] [y] \033[0m clean up boot-log {days} ago but newest' + echo -e '\033[32m clean-jar [days=30] [y] \033[0m clean up boot-jar {days} ago but newest' + echo -e '\033[32m config \033[0m print config envs' + echo -e '\033[32m tail \033[0m tail boot log or out' + echo -e '\033[32m less \033[0m less boot log or out' echo - echo -e '\033[32m docker \033[m start in docker with console log' - echo -e '\033[32m start \033[m start the {boot-jar} and tail the log' - echo -e '\033[32m starts \033[m start but Not wait log' - echo -e '\033[32m stop [snd=30]\033[m stop the {boot-jar} gracefully in {snd} seconds' - echo -e '\033[32m stops [snd=30]\033[m stop but Not confirm' - echo -e '\033[32m status \033[m show the {boot-jar} runtime status' - echo -e '\033[32m warn \033[m monitor the {boot-jar} and log' - echo -e '\033[32m live \033[m monitor the {boot-jar} and auto restart if lost pid' - echo -e '\033[32m clean [days=30] [y] \033[m clean up log-file {days} ago but newest' - echo -e '\033[32m clean-jar [days=30] [y] \033[m clean up boot-jar {days} ago but newest' - echo -e '\033[32m config \033[m print config envs' - echo -e '\033[32m tail \033[m tail boot log or out' - echo - echo -e '\033[32m cron \033[m show the {boot-jar} crontab usage' - echo -e '\033[32m free \033[m check memory free' - echo -e '\033[32m check \033[m check shell command' - echo -e '\033[32m help \033[m print help message' + echo -e '\033[32m cron \033[0m show the {boot-jar} crontab usage' + echo -e '\033[32m free \033[0m check memory free' + echo -e '\033[32m check \033[0m check shell command' + echo -e '\033[32m help \033[0m print help message' echo - echo -e 'default is \033[37;43;1m start \033[m, for example' + echo -e 'default is \033[37;43;1m start \033[0m, for example' echo -e './wings-starter.sh' echo -e './wings-starter.sh status' echo -e './wings-starter.sh boot.jar start' @@ -158,9 +163,9 @@ function print_args() { function check_cmd() { cmd=$(printf "%-10s" "$1") if info=$(which "$1") >/dev/null 2>&1; then - echo -e "\033[32m $cmd \033[m $info" + echo -e "\033[32m $cmd \033[0m $info" else - echo -e "\033[31m $cmd not found \033[m" + echo -e "\033[31m $cmd not found \033[0m" fi } @@ -175,6 +180,7 @@ function check_user() { function check_java() { echo -e "\033[37;42;1mINFO: ==== java version ==== \033[0m" + echo -e "JAVA_HOME=\033[32m$JAVA_HOME\033[0m" if ! java -version; then echo -e "\033[37;41;1mERROR: can not found 'java' in the $PATH \033[0m" exit @@ -245,7 +251,6 @@ if [[ -L "$this_file" ]]; then link_file=$(realpath "$this_file") link_envs=${link_file%.*}.env if [[ -f "$link_envs" ]]; then - echo -e "\033[37;42;1mINFO: link-envs=$link_envs \033[0m" # shellcheck disable=SC1090 source "$link_envs" fi @@ -253,7 +258,6 @@ fi this_envs=${this_file%.*}.env if [[ -f "$this_envs" ]]; then - echo -e "\033[37;42;1mINFO: this-envs=$this_envs \033[0m" # shellcheck disable=SC1090 source "$this_envs" else @@ -261,7 +265,6 @@ else fi if [[ -f "$BOOT_ENVF" ]]; then - echo -e "\033[37;42;1mINFO: boot-envs=$BOOT_ENVF \033[0m" # shellcheck disable=SC1090 source "$BOOT_ENVF" fi @@ -290,11 +293,11 @@ case "$ARGS_RUN" in cron) this_path=$(realpath -s "$this_file") echo -e "\033[37;43;1mNOTE: ==== crontab usage ==== \033[0m" - echo -e "\033[32m crontab -e -u $USER_RUN \033[m" - echo -e "\033[32m crontab -l -u $USER_RUN \033[m" - echo -e "\033[32m */5 * * * * $this_path warn \033[m" - echo -e "\033[32m */5 * * * * $this_path live >> $this_path.cron \033[m" - echo -e "\033[32m 0 0 * * * $this_path clean 30 y \033[m" + echo -e "\033[32m crontab -e -u $USER_RUN \033[0m" + echo -e "\033[32m crontab -l -u $USER_RUN \033[0m" + echo -e "\033[32m */5 * * * * $this_path warn \033[0m" + echo -e "\033[32m */5 * * * * $this_path live >> $this_path.cron \033[0m" + echo -e "\033[32m 0 0 * * * $this_path clean 30 y \033[0m" exit ;; free) @@ -349,9 +352,8 @@ case "$ARGS_RUN" in exit ;; help) - echo -e '\033[37;42;1mNOTE: help info, use the following\033[m' + echo -e '\033[37;42;1mNOTE: help info, use the following\033[0m' print_help - print_envs exit ;; esac @@ -389,7 +391,6 @@ fi if [[ "$JDK_HOME" != "" && "$JDK_HOME" != "$JAVA_HOME" ]]; then PATH=$JDK_HOME/bin:$PATH JAVA_HOME=$JDK_HOME - echo -e "\033[37;42;1mINFO: JAVA_HOME=$JAVA_HOME \033[0m" fi # lazy env eval @@ -430,7 +431,7 @@ case "$ARGS_RUN" in pgrep -alf "$grep_key" fi ;; - start*) + start | starts) print_envs check_java @@ -499,7 +500,7 @@ case "$ARGS_RUN" in tail -f "$tail_log" fi ;; - stop*) + stop | stops) if [[ $count -eq 0 ]]; then echo -e "\033[37;43;1mNOTE: not running $BOOT_JAR \033[0m" exit @@ -558,14 +559,14 @@ case "$ARGS_RUN" in ;; status) print_envs + check_java + print_args + if [[ $count -eq 0 ]]; then echo -e "\033[37;41;1mERROR: not running $BOOT_JAR \033[0m" exit fi - check_java - print_args - pid=$(awk '{print $1}' "$BOOT_PID") cid=$(pgrep -f "$grep_key") echo -e "\033[37;42;1mINFO: boot.pid=$pid \033[0m" @@ -597,18 +598,18 @@ case "$ARGS_RUN" in if id | grep -q '(sudo)'; then if which jhsdb &> /dev/null; then _jhsdb=$(which jhsdb) - echo -e "\033[37;42;1mINFO: sudo $_jhsdb jmap --heap --pid $cid \033[m" + echo -e "\033[37;42;1mINFO: sudo $_jhsdb jmap --heap --pid $cid \033[0m" sudo "$_jhsdb" jmap --heap --pid "$cid" else _jmap=$(which jmap) - echo -e "\033[37;42;1mINFO: sudo $_jmap -heap $cid \033[m" + echo -e "\033[37;42;1mINFO: sudo $_jmap -heap $cid \033[0m" sudo "$_jmap" -heap "$cid" fi else if which jhsdb &> /dev/null; then - echo -e "\033[37;43;1mNOTE: sudo $(which jhsdb) jmap --heap --pid $cid \033[m" + echo -e "\033[37;43;1mNOTE: sudo $(which jhsdb) jmap --heap --pid $cid \033[0m" else - echo -e "\033[37;43;1mNOTE: sudo $(which jmap) -heap $cid \033[m" + echo -e "\033[37;43;1mNOTE: sudo $(which jmap) -heap $cid \033[0m" fi fi @@ -623,10 +624,10 @@ case "$ARGS_RUN" in fi echo -e "\033[37;42;1mINFO: ==== useful tool ==== \033[0m" - echo -e "\033[32m profiler.sh -d 30 -f profile.svg $cid \033[m https://github.com/jvm-profiling-tools/async-profiler" - echo -e "\033[32m $(which java) -jar arthas-boot.jar $cid \033[m https://github.com/alibaba/arthas" + echo -e "\033[32m profiler.sh -d 30 -f profile.svg $cid \033[0m https://github.com/jvm-profiling-tools/async-profiler" + echo -e "\033[32m $(which java) -jar arthas-boot.jar $cid \033[0m https://github.com/alibaba/arthas" ;; - tail) + tail | less) file_log=$BOOT_LOG if [[ ! -f "$file_log" ]]; then file_log=$BOOT_OUT @@ -635,9 +636,14 @@ case "$ARGS_RUN" in echo -e "\033[37;41;1mERROR: no log found \033[0m" exit fi - tail_num=20 - echo -e "\033[37;42;1mINFO: tail -f -n $tail_num $file_log \033[0m" - tail -f -n $tail_num "$file_log" + if [[ "$ARGS_RUN" == "tail" ]]; then + tail_num=20 + echo -e "\033[37;42;1mINFO: tail -f -n $tail_num $file_log \033[0m" + tail -f -n $tail_num "$file_log" + else + echo -e "\033[37;42;1mINFO: less $file_log \033[0m" + less "$file_log" + fi ;; warn) warn_got='' @@ -684,75 +690,105 @@ case "$ARGS_RUN" in check_user safe_start ;; - clean) + clean | clean-out | clean-log | clean-jar) dys="$2" if [[ "$dys" == "" ]]; then dys=30 fi nwt=5 - echo -e "\033[32m top log ${nwt}-newest ${JAR_NAME} \033[m" - # shellcheck disable=SC2012 - ls -lt "./${JAR_NAME}"-* | head -n $nwt - echo -e "\033[32m find $(pwd) -name \"${JAR_NAME}-*\" -type f -mtime +$dys \033[m" - old=$(find . -name "${JAR_NAME}-*" -type f -mtime +$dys | wc -l) - if [[ $old -gt 10 ]]; then - exs="newest-log-${JAR_NAME}.tmp" - # shellcheck disable=SC2012 - ls -t "./${JAR_NAME}"-* | head -n $nwt >"$exs" - - find . -name "${JAR_NAME}-*" -type f -mtime +$dys -print0 | grep -zvFf "$exs" | xargs -0 ls -lt - echo -e "\033[37;43;1mNOTE: ==== clear ${dys}-days ago log file ==== \033[0m" - check_user - yon="$3" - if [[ "$3" == "" ]]; then - echo -e "\033[31mWARN: press to rm them all, pwd=${WORK_DIR} \033[0m" - read -r yon - fi - if [[ "$yon" == "y" ]]; then - find . -name "${JAR_NAME}-*" -type f -mtime +$dys -print0 | grep -zvFf "$exs" | xargs -0 rm -f - fi - rm -f "$exs" - else - echo -e "\033[37;42;1mNOTE: few ${dys}-days ago logs, pwd=${WORK_DIR} \033[0m" - fi - ;; - clean-jar) - dys="$2" - if [[ "$dys" == "" ]]; then - dys=30 - fi - jrt=$(dirname "$BOOT_JAR") - nwt=5 - echo -e "\033[32m top jar ${nwt}-newest ${JAR_NAME} \033[m" - # shellcheck disable=SC2012 - ls -lt "${jrt}/${JAR_NAME}"[_-]* | head -n $nwt - echo -e "\033[32m find $jrt -name \"${JAR_NAME}[_-]*\" -type f -mtime +$dys \033[m" - old=$(find "$jrt" -name "${JAR_NAME}[_-]*" -type f -mtime +$dys | wc -l) - if [[ $old -gt 10 ]]; then - exs="newest-jar-${JAR_NAME}.tmp" + case "$ARGS_RUN" in clean | clean-out) + echo -e "\033[32m top out ${nwt}-newest of ${JAR_NAME} \033[0m" # shellcheck disable=SC2012 - ls -t "${jrt}/${JAR_NAME}"[_-]* | head -n $nwt >"$exs" - - find "$jrt" -name "${JAR_NAME}[_-]*" -type f -mtime +$dys -print0 | grep -zvFf "$exs" | xargs -0 ls -lt - echo -e "\033[37;43;1mNOTE: ==== clear ${dys}-days ago jar, exclude top ${nwt}-newest ==== \033[0m" - check_user + ls -lt "./${JAR_NAME}"-* | head -n $nwt + echo -e "\033[32m find $(pwd) -name \"${JAR_NAME}-*\" -type f -mtime +$dys \033[0m" + old=$(find . -name "${JAR_NAME}-*" -type f -mtime +$dys | wc -l) + if [[ $old -gt 10 ]]; then + exs="newest-out-${JAR_NAME}.tmp" + # shellcheck disable=SC2012 + ls -t "./${JAR_NAME}"-* | head -n $nwt >"$exs" + + find . -name "${JAR_NAME}-*" -type f -mtime +$dys -print0 | grep -zvFf "$exs" | xargs -0 ls -lt + echo -e "\033[37;43;1mNOTE: ==== clear ${dys}-days ago out file ==== \033[0m" + check_user + + yon="$3" + if [[ "$3" == "" ]]; then + echo -e "\033[31mWARN: press to rm them all, pwd=${WORK_DIR} \033[0m" + read -r yon + fi + if [[ "$yon" == "y" ]]; then + find . -name "${JAR_NAME}-*" -type f -mtime +$dys -print0 | grep -zvFf "$exs" | xargs -0 rm -f + fi + rm -f "$exs" + else + echo -e "\033[37;42;1mNOTE: few ${dys}-days ago outs, pwd=${WORK_DIR} \033[0m" + fi + esac - yon="$3" - if [[ "$3" == "" ]]; then - echo -e "\033[31mWARN: press to rm them all, pwd=$jrt \033[0m" - read -r yon + case "$ARGS_RUN" in clean | clean-log) + echo -e "\033[32m top log ${nwt}-newest of ${JAR_NAME} \033[0m" + jrt=$(dirname "$BOOT_LOG") + jnm=$(basename "$BOOT_LOG") + # shellcheck disable=SC2012 + ls -lt "${BOOT_LOG}".* | head -n $nwt + echo -e "\033[32m find $jrt -name \"${jnm}.*\" -type f -mtime +$dys \033[0m" + old=$(find "$jrt" -name "${jnm}-*" -type f -mtime +$dys | wc -l) + if [[ $old -gt 10 ]]; then + exs="newest-log-${JAR_NAME}.tmp" + # shellcheck disable=SC2012 + ls -t "${BOOT_LOG}".* | head -n $nwt >"$exs" + + find "$jrt" -name "${jnm}.*" -type f -mtime +$dys -print0 | grep -zvFf "$exs" | xargs -0 ls -lt + echo -e "\033[37;43;1mNOTE: ==== clear ${dys}-days ago log file ==== \033[0m" + check_user + + yon="$3" + if [[ "$3" == "" ]]; then + echo -e "\033[31mWARN: press to rm them all, pwd=$jrt \033[0m" + read -r yon + fi + if [[ "$yon" == "y" ]]; then + find "$jrt" -name "${jnm}.*" -type f -mtime +$dys -print0 | grep -zvFf "$exs" | xargs -0 rm -f + fi + rm -f "$exs" + else + echo -e "\033[37;42;1mNOTE: few ${dys}-days ago logs, pwd=${jrt} \033[0m" fi - if [[ "$yon" == "y" ]]; then - find "$jrt" -name "${JAR_NAME}[_-]*" -type f -mtime +$dys -print0 | grep -zvFf "$exs" | xargs -0 rm -f + esac + + case "$ARGS_RUN" in clean | clean-jar) + echo -e "\033[32m top jar ${nwt}-newest of ${JAR_NAME} \033[0m" + jrt=$(dirname "$BOOT_JAR") + # shellcheck disable=SC2012 + ls -lt "${jrt}/${JAR_NAME}"[_-]* | head -n $nwt + echo -e "\033[32m find $jrt -name \"${JAR_NAME}[_-]*\" -type f -mtime +$dys \033[0m" + old=$(find "$jrt" -name "${JAR_NAME}[_-]*" -type f -mtime +$dys | wc -l) + if [[ $old -gt 10 ]]; then + exs="newest-jar-${JAR_NAME}.tmp" + # shellcheck disable=SC2012 + ls -t "${jrt}/${JAR_NAME}"[_-]* | head -n $nwt >"$exs" + + find "$jrt" -name "${JAR_NAME}[_-]*" -type f -mtime +$dys -print0 | grep -zvFf "$exs" | xargs -0 ls -lt + echo -e "\033[37;43;1mNOTE: ==== clear ${dys}-days ago jar, exclude top ${nwt}-newest ==== \033[0m" + check_user + + yon="$3" + if [[ "$3" == "" ]]; then + echo -e "\033[31mWARN: press to rm them all, pwd=$jrt \033[0m" + read -r yon + fi + if [[ "$yon" == "y" ]]; then + find "$jrt" -name "${JAR_NAME}[_-]*" -type f -mtime +$dys -print0 | grep -zvFf "$exs" | xargs -0 rm -f + fi + rm -f "$exs" + else + echo -e "\033[37;42;1mNOTE: few ${dys}-days ago jars, pwd=$jrt \033[0m" fi - rm -f "$exs" - else - echo -e "\033[37;42;1mNOTE: few ${dys}-days ago jars, pwd=$jrt \033[0m" - fi + esac ;; config) - echo -e '\033[37;42;1mNOTE: ==== conf env ==== \033[m' + echo -e '\033[37;42;1mNOTE: ==== conf env ==== \033[0m' echo "WORK_DIR=$WORK_DIR" echo "TAIL_LOG=$TAIL_LOG" echo "USER_RUN=$USER_RUN" @@ -776,8 +812,10 @@ case "$ARGS_RUN" in echo "WARN_RUN=$WARN_RUN" ;; *) - echo -e '\033[37;41;1mERROR: unsupported command, use the following\033[m' + echo -e "\033[37;41;1mERROR: unknown $ARGS_RUN, see the following\033[0m" print_help print_envs + check_java + print_args ;; esac diff --git a/observe/scripts/wings-testing.sh b/observe/scripts/wings-testing.sh index 86c85301e..f706b4c3e 100644 --- a/observe/scripts/wings-testing.sh +++ b/observe/scripts/wings-testing.sh @@ -23,7 +23,7 @@ if [[ "$MAVEN_OPTS" == "" ]]; then fi if [[ "$LOG_LEVEL" == "" ]]; then - echo -e "\033[32m log level (INFO)? [INFO|DEBUG|WARN|ERROR]\033[m" + echo -e "\033[32m log level (INFO)? [INFO|DEBUG|WARN|ERROR]\033[0m" read -r _ans Date: Fri, 9 Aug 2024 10:05:56 +0800 Subject: [PATCH 43/51] =?UTF-8?q?=F0=9F=94=8A=20suppress=20warn=20of=20com?= =?UTF-8?q?mon=20task=20#287?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- observe/docs | 2 +- observe/mirana | 2 +- .../tiny/task/schedule/exec/ExecHolder.java | 17 ++++++- .../task/service/TinyTaskConfService.java | 8 ++- .../service/impl/TinyTaskBeatServiceImpl.java | 6 --- .../service/impl/TinyTaskConfServiceImpl.java | 50 +++++++++++++++---- .../service/impl/TinyTaskExecServiceImpl.java | 6 ++- .../service/impl/TinyTaskServiceImpl.java | 2 +- .../okhttp/OkHttpTweakLogInterceptor.java | 22 +++++++- .../bean/SlardarTweakConfiguration.java | 9 +++- .../spring/prop/SlardarOkhttpProp.java | 11 ++++ .../wings-conf/wings-okhttp-79.properties | 3 ++ 12 files changed, 108 insertions(+), 30 deletions(-) diff --git a/observe/docs b/observe/docs index c137a343c..96de5f351 160000 --- a/observe/docs +++ b/observe/docs @@ -1 +1 @@ -Subproject commit c137a343ce1eb51246f6c77ea845a3abd9bb5b2b +Subproject commit 96de5f3516d8a63745329bc5d9552c3dafb6ff53 diff --git a/observe/mirana b/observe/mirana index 9587e8bf9..cacdfa276 160000 --- a/observe/mirana +++ b/observe/mirana @@ -1 +1 @@ -Subproject commit 9587e8bf9c062b1426410b4779c07eeced2703f6 +Subproject commit cacdfa276d38b9efa5fcfcfc4ad6ca52fa8b8be0 diff --git a/radiant/tiny-task/src/main/java/pro/fessional/wings/tiny/task/schedule/exec/ExecHolder.java b/radiant/tiny-task/src/main/java/pro/fessional/wings/tiny/task/schedule/exec/ExecHolder.java index 5fb158387..4deff97bf 100644 --- a/radiant/tiny-task/src/main/java/pro/fessional/wings/tiny/task/schedule/exec/ExecHolder.java +++ b/radiant/tiny-task/src/main/java/pro/fessional/wings/tiny/task/schedule/exec/ExecHolder.java @@ -3,6 +3,7 @@ import org.apache.commons.lang3.StringUtils; import org.jetbrains.annotations.Contract; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import java.util.concurrent.ConcurrentHashMap; import java.util.function.Function; @@ -22,7 +23,7 @@ public static NoticeExec getNotice(@NotNull String bean, @NotNull Function!null") - public static NoticeExec getNotice(String bean, boolean nonnull) { + public static NoticeExec getNotice(@Nullable String bean, boolean nonnull) { final NoticeExec exec = StringUtils.isEmpty(bean) ? null : Notice.get(bean); if (nonnull && exec == null) { throw new IllegalStateException("notice not found, bean=" + bean); @@ -30,17 +31,29 @@ public static NoticeExec getNotice(String bean, boolean nonnull) { return exec; } + @Nullable + public static NoticeExec delNotice(@NotNull String bean) { + return Notice.remove(bean); + } + + @NotNull public static TaskerExec getTasker(@NotNull String prop, @NotNull Function exec) { return Tasker.computeIfAbsent(prop, exec); } @Contract("_,true->!null") - public static TaskerExec getTasker(String prop, boolean nonnull) { + public static TaskerExec getTasker(@Nullable String prop, boolean nonnull) { final TaskerExec exec = StringUtils.isEmpty(prop) ? null : Tasker.get(prop); if (nonnull && exec == null) { throw new IllegalStateException("tasker not found, prop=" + prop); } return exec; } + + @Nullable + public static TaskerExec delTasker(@NotNull String prop) { + return Tasker.remove(prop); + } + } diff --git a/radiant/tiny-task/src/main/java/pro/fessional/wings/tiny/task/service/TinyTaskConfService.java b/radiant/tiny-task/src/main/java/pro/fessional/wings/tiny/task/service/TinyTaskConfService.java index 0be41b3b8..6517a82cf 100644 --- a/radiant/tiny-task/src/main/java/pro/fessional/wings/tiny/task/service/TinyTaskConfService.java +++ b/radiant/tiny-task/src/main/java/pro/fessional/wings/tiny/task/service/TinyTaskConfService.java @@ -25,8 +25,8 @@ public interface TinyTaskConfService { *
      * Configure the TinyTasker annotated and enabled method , return the taskId.
      * - throw exception if property not exist
-     * - save to database if not exist in database
-     * - save to database, if exist in database, but higher version
+     * - insert to database if not exist in database
+     * - update to database, if exist and matched and lower version
      * - otherwise no operation
      * 
*/ @@ -72,5 +72,9 @@ class Conf { private final String key; private final boolean enabled; private final boolean autorun; + /** + * matched app and run + */ + private final boolean matched; } } diff --git a/radiant/tiny-task/src/main/java/pro/fessional/wings/tiny/task/service/impl/TinyTaskBeatServiceImpl.java b/radiant/tiny-task/src/main/java/pro/fessional/wings/tiny/task/service/impl/TinyTaskBeatServiceImpl.java index 1bc8292c8..1c3cc0572 100644 --- a/radiant/tiny-task/src/main/java/pro/fessional/wings/tiny/task/service/impl/TinyTaskBeatServiceImpl.java +++ b/radiant/tiny-task/src/main/java/pro/fessional/wings/tiny/task/service/impl/TinyTaskBeatServiceImpl.java @@ -13,7 +13,6 @@ import pro.fessional.mirana.time.DateLocaling; import pro.fessional.mirana.time.ThreadNow; import pro.fessional.wings.faceless.convention.EmptySugar; -import pro.fessional.wings.silencer.modulate.RuntimeMode; import pro.fessional.wings.silencer.spring.boot.ConditionalWingsEnabled; import pro.fessional.wings.tiny.task.database.autogen.tables.WinTaskDefineTable; import pro.fessional.wings.tiny.task.database.autogen.tables.WinTaskResultTable; @@ -114,11 +113,6 @@ public String checkHealth() { for (WinTaskDefine r : tks) { log.debug("check health tiny-task id={}, name={}", r.getId(), r.getTaskerName()); - final String runs = r.getTaskerRuns(); - if (StringUtils.isNotBlank(runs) && !RuntimeMode.voteRunMode(runs)) { - continue; - } - // coordinate to system timezone long beat = calcBeatMills(r, now); if (beat <= 0) continue; diff --git a/radiant/tiny-task/src/main/java/pro/fessional/wings/tiny/task/service/impl/TinyTaskConfServiceImpl.java b/radiant/tiny-task/src/main/java/pro/fessional/wings/tiny/task/service/impl/TinyTaskConfServiceImpl.java index cb5f0d4c2..f002d9abc 100644 --- a/radiant/tiny-task/src/main/java/pro/fessional/wings/tiny/task/service/impl/TinyTaskConfServiceImpl.java +++ b/radiant/tiny-task/src/main/java/pro/fessional/wings/tiny/task/service/impl/TinyTaskConfServiceImpl.java @@ -3,6 +3,7 @@ import lombok.Setter; import lombok.SneakyThrows; import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; import org.jetbrains.annotations.Contract; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -21,6 +22,8 @@ import pro.fessional.mirana.data.Diff; import pro.fessional.wings.faceless.service.journal.JournalService; import pro.fessional.wings.faceless.service.lightid.LightIdService; +import pro.fessional.wings.silencer.modulate.RunMode; +import pro.fessional.wings.silencer.modulate.RuntimeMode; import pro.fessional.wings.silencer.notice.SmallNotice; import pro.fessional.wings.silencer.spring.boot.ConditionalWingsEnabled; import pro.fessional.wings.tiny.task.database.autogen.tables.WinTaskDefineTable; @@ -47,6 +50,7 @@ import static org.apache.commons.lang3.StringUtils.isEmpty; import static org.springframework.core.MethodIntrospector.selectMethods; import static org.springframework.core.annotation.AnnotatedElementUtils.findMergedAnnotation; +import static pro.fessional.wings.silencer.support.PropHelper.commaArray; /** * @author trydofor @@ -264,12 +268,14 @@ private Conf config(@NotNull Class claz, @NotNull Object bean, @NotNull Metho final long id; final boolean enabled; final boolean autorun; + final boolean matched; final String noticeBean; final WinTaskDefine po = fetchProp(WinTaskDefine.class, t -> t.TaskerBean.eq(entry)); if (po == null) { id = insertProp(prop, key); enabled = prop.isEnabled(); autorun = prop.isAutorun(); + matched = true; noticeBean = prop.getNoticeBean(); log.info("insert prop to database, version={}, id={}", prop.getVersion(), id); } @@ -277,8 +283,10 @@ private Conf config(@NotNull Class claz, @NotNull Object bean, @NotNull Metho id = po.getId(); enabled = BoxedCastUtil.orTrue(po.getEnabled()); autorun = BoxedCastUtil.orTrue(po.getAutorun()); + matched = hasApps(po.getTaskerApps()) && hasRuns(po.getTaskerRuns()); noticeBean = po.getNoticeBean(); - log.debug("find database config, version={}, id={}", prop.getVersion(), id); + log.debug("find database config, version={}, id={}, matched={}", prop.getVersion(), id, matched); + // diff final LinkedHashMap> df = diff(po, prop); if (!df.isEmpty()) { @@ -290,12 +298,18 @@ private Conf config(@NotNull Class claz, @NotNull Object bean, @NotNull Metho sb.append(", pp=").append(en.getValue().getV2()); sb.append('\n'); } - if (po.getVersion() <= prop.getVersion()) { + + if (matched && po.getVersion() <= prop.getVersion()) { updateProp(prop, key, id); - log.info("update prop to database, prop={}, diff={}", key, sb); + log.warn("update prop to database(low-ver), prop={}, diff={}", key, sb); } else { - log.warn("diff from prop and database, prop={}, diff={}", key, sb); + if (matched) { + log.warn("diff from prop(low-ver) and database, prop={}, diff={}", key, sb); + } + else { + log.info("diff from prop and database but not matched, prop={}, diff={}", key, sb); + } } } } @@ -308,7 +322,8 @@ private Conf config(@NotNull Class claz, @NotNull Object bean, @NotNull Metho ", entry2=" + poKey.getTaskerBean()); } - if (noticeBean != null && !noticeBean.isEmpty()) { + // keep bean and notice even if not matched to launch task bewteen the cluster + if (StringUtils.isNotEmpty(noticeBean)) { ExecHolder.getNotice(noticeBean, k -> { try { final Class> cz = (Class>) ClassUtils.forName(noticeBean, null); @@ -323,14 +338,27 @@ private Conf config(@NotNull Class claz, @NotNull Object bean, @NotNull Metho }); } - return new Conf(id, key, enabled, autorun); + return new Conf(id, key, enabled, autorun, matched); + } + + private boolean hasApps(String apps) { + if (StringUtils.isEmpty(apps)) return true; + for (String s : commaArray(apps)) { + if (s.trim().equals(appName)) return true; + } + return false; + } + + private boolean hasRuns(String runs) { + if (StringUtils.isEmpty(runs)) return true; + return !RuntimeMode.isRunMode(RunMode.Nothing) && RuntimeMode.voteRunMode(runs); } private long insertProp(TaskerProp prop, String key) { return journalService.submit(Jane.Insert, journal -> { final WinTaskDefineTable t = winTaskDefineDao.getTable(); final long id = lightIdService.getId(t); - final WinTaskDefine po = genWinTaskDefine(prop, key); + final WinTaskDefine po = genWinTaskDefine(prop, key, appName); po.setId(id); po.setNextLock(0); journal.create(po); @@ -341,7 +369,7 @@ private long insertProp(TaskerProp prop, String key) { private boolean updateProp(TaskerProp prop, String key, long id) { return journalService.submit(Jane.Update, journal -> { - WinTaskDefine po = genWinTaskDefine(prop, key); + WinTaskDefine po = genWinTaskDefine(prop, key, null); po.setId(id); journal.modify(po); final int rc = winTaskDefineDao.update(po, true); @@ -350,7 +378,7 @@ private boolean updateProp(TaskerProp prop, String key, long id) { } @NotNull - private WinTaskDefine genWinTaskDefine(TaskerProp prop, String key) { + private WinTaskDefine genWinTaskDefine(TaskerProp prop, String key, String apps) { WinTaskDefine wtd = new WinTaskDefine(); wtd.setEnabled(prop.isEnabled()); @@ -363,8 +391,8 @@ private WinTaskDefine genWinTaskDefine(TaskerProp prop, String key) { wtd.setTaskerName(prop.getTaskerName()); wtd.setTaskerFast(prop.isTaskerFast()); - final String apps = prop.getTaskerApps(); - wtd.setTaskerApps(isEmpty(apps) ? appName : apps); + final String ta = prop.getTaskerApps(); + wtd.setTaskerApps(isEmpty(ta) ? apps : ta); wtd.setTaskerRuns(prop.getTaskerRuns()); wtd.setNoticeBean(prop.getNoticeBean()); diff --git a/radiant/tiny-task/src/main/java/pro/fessional/wings/tiny/task/service/impl/TinyTaskExecServiceImpl.java b/radiant/tiny-task/src/main/java/pro/fessional/wings/tiny/task/service/impl/TinyTaskExecServiceImpl.java index 7d6a73fc3..bf1440533 100644 --- a/radiant/tiny-task/src/main/java/pro/fessional/wings/tiny/task/service/impl/TinyTaskExecServiceImpl.java +++ b/radiant/tiny-task/src/main/java/pro/fessional/wings/tiny/task/service/impl/TinyTaskExecServiceImpl.java @@ -381,6 +381,7 @@ private boolean notApps(String apps, long id, String key) { for (String s : commaArray(apps)) { if (s.trim().equals(appName)) return false; } + log.info("skip tiny-task for not apps={}, cur={}, id={}, prop={}", apps, appName, id, key); return true; } @@ -398,8 +399,9 @@ private boolean notRuns(String runs, long id, String key) { log.info("skip tiny-task for not runs={}, cur={}, id={}, prop={}", runs, rmd, id, key); return true; } - - return false; + else { + return false; + } } private Set noticeWhen(String nw) { diff --git a/radiant/tiny-task/src/main/java/pro/fessional/wings/tiny/task/service/impl/TinyTaskServiceImpl.java b/radiant/tiny-task/src/main/java/pro/fessional/wings/tiny/task/service/impl/TinyTaskServiceImpl.java index 23152963a..673a68d30 100644 --- a/radiant/tiny-task/src/main/java/pro/fessional/wings/tiny/task/service/impl/TinyTaskServiceImpl.java +++ b/radiant/tiny-task/src/main/java/pro/fessional/wings/tiny/task/service/impl/TinyTaskServiceImpl.java @@ -45,7 +45,7 @@ public Set schedule(@NotNull Object taskerBean) { final Set conf = tinyTaskConfService.config(taskerBean); final Set rst = new HashSet<>(); for (Conf cnf : conf) { - if (cnf.isEnabled() && cnf.isAutorun()) { + if (cnf.isEnabled() && cnf.isAutorun() && cnf.isMatched()) { final boolean cd = tinyTaskExecService.launch(cnf.getId()); log.info("schedule bean tiny-task {}, scheduled={}", cnf, cd); rst.add(new Task(cnf.getId(), cnf.getKey(), cd)); diff --git a/wings/slardar/src/main/java/pro/fessional/wings/slardar/httprest/okhttp/OkHttpTweakLogInterceptor.java b/wings/slardar/src/main/java/pro/fessional/wings/slardar/httprest/okhttp/OkHttpTweakLogInterceptor.java index 5625f4362..b88e51f30 100644 --- a/wings/slardar/src/main/java/pro/fessional/wings/slardar/httprest/okhttp/OkHttpTweakLogInterceptor.java +++ b/wings/slardar/src/main/java/pro/fessional/wings/slardar/httprest/okhttp/OkHttpTweakLogInterceptor.java @@ -6,6 +6,7 @@ import okhttp3.Response; import okhttp3.logging.HttpLoggingInterceptor; import okhttp3.logging.HttpLoggingInterceptor.Level; +import org.apache.commons.lang3.StringUtils; import org.jetbrains.annotations.NotNull; import org.springframework.boot.logging.LogLevel; import pro.fessional.mirana.time.StopWatch; @@ -13,7 +14,10 @@ import pro.fessional.wings.silencer.watch.Watches; import java.io.IOException; +import java.util.Collection; import java.util.EnumMap; +import java.util.HashSet; +import java.util.Set; import static org.springframework.boot.logging.LogLevel.DEBUG; import static org.springframework.boot.logging.LogLevel.ERROR; @@ -43,10 +47,12 @@ public class OkHttpTweakLogInterceptor implements OkHttpInterceptor { public static final HttpLoggingInterceptor.Logger LoggerWarn = log::warn; private final EnumMap mapping = new EnumMap<>(LogLevel.class); + private final Set nopUrlToken = new HashSet<>(); - public OkHttpTweakLogInterceptor() { + public OkHttpTweakLogInterceptor(Collection nop) { resetMapping(); TweakLogger.asCoreLevel(log.getName()); + nopUrlToken.addAll(nop); } /** @@ -93,7 +99,19 @@ public void resetMapping() { @NotNull @Override public Response intercept(@NotNull Interceptor.Chain chain) throws IOException { - final LogLevel lvl = TweakLogger.currentLevel(log.getName()); + boolean off = false; + if (!nopUrlToken.isEmpty()) { + String url = chain.request().url().toString(); + for (String tkn : nopUrlToken) { + if (StringUtils.containsIgnoreCase(url, tkn)) { + log.debug("exclude intercept, token={}, url={}", tkn, url); + off = true; + break; + } + } + } + + final LogLevel lvl = off ? LogLevel.OFF : TweakLogger.currentLevel(log.getName()); final HttpLoggingInterceptor itc = mapping.get(lvl); final StopWatch current = Watches.current(); diff --git a/wings/slardar/src/main/java/pro/fessional/wings/slardar/spring/bean/SlardarTweakConfiguration.java b/wings/slardar/src/main/java/pro/fessional/wings/slardar/spring/bean/SlardarTweakConfiguration.java index 655a6c51b..4b738313d 100644 --- a/wings/slardar/src/main/java/pro/fessional/wings/slardar/spring/bean/SlardarTweakConfiguration.java +++ b/wings/slardar/src/main/java/pro/fessional/wings/slardar/spring/bean/SlardarTweakConfiguration.java @@ -5,8 +5,12 @@ import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import pro.fessional.wings.silencer.spring.boot.ConditionalWingsEnabled; +import pro.fessional.wings.silencer.support.PropHelper; import pro.fessional.wings.slardar.event.tweak.TweakEventListener; import pro.fessional.wings.slardar.httprest.okhttp.OkHttpTweakLogInterceptor; +import pro.fessional.wings.slardar.spring.prop.SlardarOkhttpProp; + +import java.util.Collection; /** * @author trydofor @@ -20,9 +24,10 @@ public class SlardarTweakConfiguration { @Bean @ConditionalWingsEnabled - public OkHttpTweakLogInterceptor okhttpTweakLogInterceptor() { + public OkHttpTweakLogInterceptor okhttpTweakLogInterceptor(SlardarOkhttpProp prop) { log.info("Slardar spring-bean okhttpTweakLogInterceptor"); - return new OkHttpTweakLogInterceptor(); + Collection nop = PropHelper.onlyValid(prop.getInterceptNop()).values(); + return new OkHttpTweakLogInterceptor(nop); } @Bean diff --git a/wings/slardar/src/main/java/pro/fessional/wings/slardar/spring/prop/SlardarOkhttpProp.java b/wings/slardar/src/main/java/pro/fessional/wings/slardar/spring/prop/SlardarOkhttpProp.java index 528fe5bc8..3e8fb843e 100644 --- a/wings/slardar/src/main/java/pro/fessional/wings/slardar/spring/prop/SlardarOkhttpProp.java +++ b/wings/slardar/src/main/java/pro/fessional/wings/slardar/spring/prop/SlardarOkhttpProp.java @@ -4,6 +4,8 @@ import org.springframework.boot.context.properties.ConfigurationProperties; import java.io.File; +import java.util.Collections; +import java.util.Map; /** * okhttp as one word in string/config @@ -130,4 +132,13 @@ public class SlardarOkhttpProp { */ private boolean redirectNop = false; public static final String Key$redirectNop = Key + ".redirect-nop"; + + /** + * do NOT intercept if the token contained in URL + * + * @see #Key$interceptNop + */ + private Map interceptNop = Collections.emptyMap(); + public static final String Key$interceptNop = Key + ".intercept-nop"; + } diff --git a/wings/slardar/src/main/resources/wings-conf/wings-okhttp-79.properties b/wings/slardar/src/main/resources/wings-conf/wings-okhttp-79.properties index d7fd146b0..03a91016e 100644 --- a/wings/slardar/src/main/resources/wings-conf/wings-okhttp-79.properties +++ b/wings/slardar/src/main/resources/wings-conf/wings-okhttp-79.properties @@ -37,3 +37,6 @@ wings.slardar.okhttp.host-cookie = true ## whether to temporarily do nothing when follow-redirect. wings.slardar.okhttp.redirect-nop = false + +## do NOT intercept if the token contained in URL +wings.slardar.okhttp.intercept-nop[ding-talk] = oapi.dingtalk.com \ No newline at end of file From de675a9a317fda34e612a38062decb7c044adb46 Mon Sep 17 00:00:00 2001 From: trydofor Date: Sat, 10 Aug 2024 09:15:11 +0800 Subject: [PATCH 44/51] =?UTF-8?q?=F0=9F=93=88=20opt=20task/cron=20time=20#?= =?UTF-8?q?288?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- observe/docs | 2 +- .../wings-conf/wings-tinytask-beat-79.properties | 8 ++++---- .../fessional/wings/slardar/monitor/metric/JvmMetric.java | 4 ++-- .../wings/slardar/spring/prop/SlardarMonitorProp.java | 4 ++-- .../main/resources/wings-conf/wings-monitor-79.properties | 8 ++++---- 5 files changed, 13 insertions(+), 13 deletions(-) diff --git a/observe/docs b/observe/docs index 96de5f351..8877a3c63 160000 --- a/observe/docs +++ b/observe/docs @@ -1 +1 @@ -Subproject commit 96de5f3516d8a63745329bc5d9552c3dafb6ff53 +Subproject commit 8877a3c632da267030957f0cf4e5ed33f80e9183 diff --git a/radiant/tiny-task/src/main/resources/wings-conf/wings-tinytask-beat-79.properties b/radiant/tiny-task/src/main/resources/wings-conf/wings-tinytask-beat-79.properties index 6d2c783c2..f96b980f7 100644 --- a/radiant/tiny-task/src/main/resources/wings-conf/wings-tinytask-beat-79.properties +++ b/radiant/tiny-task/src/main/resources/wings-conf/wings-tinytask-beat-79.properties @@ -1,5 +1,5 @@ -## Clean the result at system timezone 02:01:00 -wings.tiny.task.define[TinyTaskCleanResult].timing-cron=0 1 2 * * * -## Check health status every 300 seconds of idle time. -wings.tiny.task.define[TinyTaskCheckHealth].timing-idle=300 +## Clean the result at system timezone 13:11:07 +wings.tiny.task.define[TinyTaskCleanResult].timing-cron=7 11 13 * * * +## Check health status every 347 seconds of idle time. +wings.tiny.task.define[TinyTaskCheckHealth].timing-idle=347 wings.tiny.task.define[TinyTaskCheckHealth].notice-when=fail,feed diff --git a/wings/slardar/src/main/java/pro/fessional/wings/slardar/monitor/metric/JvmMetric.java b/wings/slardar/src/main/java/pro/fessional/wings/slardar/monitor/metric/JvmMetric.java index 85b0b3f75..c064e679c 100644 --- a/wings/slardar/src/main/java/pro/fessional/wings/slardar/monitor/metric/JvmMetric.java +++ b/wings/slardar/src/main/java/pro/fessional/wings/slardar/monitor/metric/JvmMetric.java @@ -101,9 +101,9 @@ public static class Rule { public static final String Key$processCent = Key + ".process-cent"; /** - * process Cpu Load without percentage, range `[0, 100*cores]` + * process Cpu Load without percentage, range `[0, 100*cores]`, default=80x4 */ - private int processLoad = 150; + private int processLoad = 320; public static final String Key$processLoad = Key + ".process-load"; /** diff --git a/wings/slardar/src/main/java/pro/fessional/wings/slardar/spring/prop/SlardarMonitorProp.java b/wings/slardar/src/main/java/pro/fessional/wings/slardar/spring/prop/SlardarMonitorProp.java index 0a4dfbaf8..09a504b9a 100644 --- a/wings/slardar/src/main/java/pro/fessional/wings/slardar/spring/prop/SlardarMonitorProp.java +++ b/wings/slardar/src/main/java/pro/fessional/wings/slardar/spring/prop/SlardarMonitorProp.java @@ -23,12 +23,12 @@ public class SlardarMonitorProp { public static final String Key = "wings.slardar.monitor"; /** - * Monitor its own cron, `-` means stop this cron, default 10 minutes. + * Monitor its own cron, `-` means stop this cron, default 17 minutes. * * @see #Key$cron */ public static final String Key$cron = Key + ".cron"; - private String cron = "0 */10 * * * ?"; + private String cron = "17 */17 * * * ?"; /** * whether to send notice for the start and stop of its own jvm hook diff --git a/wings/slardar/src/main/resources/wings-conf/wings-monitor-79.properties b/wings/slardar/src/main/resources/wings-conf/wings-monitor-79.properties index 328e3b8e6..e32257d69 100644 --- a/wings/slardar/src/main/resources/wings-conf/wings-monitor-79.properties +++ b/wings/slardar/src/main/resources/wings-conf/wings-monitor-79.properties @@ -1,7 +1,7 @@ ## Setting of app builtin simple monitoring, `-1` in the threshold value means ignore. -## Monitor its own cron, `-` means stop this cron, default 10 minutes. -wings.slardar.monitor.cron=0 */10 * * * ? +## Monitor its own cron, `-` means stop this cron, default 17 minutes. +wings.slardar.monitor.cron=17 */17 * * * ? ## whether to send notice for the start and stop of its own jvm hook wings.slardar.monitor.hook=true @@ -15,8 +15,8 @@ wings.slardar.monitor.jvm.system-load=-1 ## process system Cpu Load with percentage to ## the entire system with all cores, range `[0, 100]` wings.slardar.monitor.jvm.process-cent=-1 -## process Cpu Load without percentage, range `[0, 100*cores]` -wings.slardar.monitor.jvm.process-load=150 +## process Cpu Load without percentage, range `[0, 100*cores]`, default=80x4 +wings.slardar.monitor.jvm.process-load=320 ## process Mem Load, range `[0,100]` wings.slardar.monitor.jvm.memory-load=85 ## total threads in jvm. From bfb95be71ebd3ba9012f5c9bc8977e7719a40d7c Mon Sep 17 00:00:00 2001 From: trydofor Date: Mon, 12 Aug 2024 22:18:15 +0800 Subject: [PATCH 45/51] =?UTF-8?q?=F0=9F=A9=BA=20health=20check=20with=20ru?= =?UTF-8?q?n-mode=20#284?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- observe/docs | 2 +- .../tiny/task/service/impl/TinyTaskBeatServiceImpl.java | 9 ++++++++- .../wings/silencer/modulate/RuntimeModeTest.java | 1 + 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/observe/docs b/observe/docs index 8877a3c63..452ba76a5 160000 --- a/observe/docs +++ b/observe/docs @@ -1 +1 @@ -Subproject commit 8877a3c632da267030957f0cf4e5ed33f80e9183 +Subproject commit 452ba76a5f29f0177f594b33ca38683a0b37f9c1 diff --git a/radiant/tiny-task/src/main/java/pro/fessional/wings/tiny/task/service/impl/TinyTaskBeatServiceImpl.java b/radiant/tiny-task/src/main/java/pro/fessional/wings/tiny/task/service/impl/TinyTaskBeatServiceImpl.java index 1c3cc0572..18cfb7d35 100644 --- a/radiant/tiny-task/src/main/java/pro/fessional/wings/tiny/task/service/impl/TinyTaskBeatServiceImpl.java +++ b/radiant/tiny-task/src/main/java/pro/fessional/wings/tiny/task/service/impl/TinyTaskBeatServiceImpl.java @@ -13,6 +13,7 @@ import pro.fessional.mirana.time.DateLocaling; import pro.fessional.mirana.time.ThreadNow; import pro.fessional.wings.faceless.convention.EmptySugar; +import pro.fessional.wings.silencer.modulate.RuntimeMode; import pro.fessional.wings.silencer.spring.boot.ConditionalWingsEnabled; import pro.fessional.wings.tiny.task.database.autogen.tables.WinTaskDefineTable; import pro.fessional.wings.tiny.task.database.autogen.tables.WinTaskResultTable; @@ -102,7 +103,7 @@ public String checkHealth() { final WinTaskDefineTable td = winTaskDefineDao.getTable(); List tks = winTaskDefineDao .ctx() - .select(td.Id, td.TaskerName, td.LastExec, + .select(td.Id, td.TaskerName, td.LastExec, td.TaskerRuns, td.TimingBeat, td.TimingRate, td.TimingIdle, td.TimingTune, td.TimingCron, td.TimingZone) .from(td) .where(td.Enabled.eq(Boolean.TRUE)) @@ -113,6 +114,12 @@ public String checkHealth() { for (WinTaskDefine r : tks) { log.debug("check health tiny-task id={}, name={}", r.getId(), r.getTaskerName()); + // check runs, same database must be same run mode + final String runs = r.getTaskerRuns(); + if (StringUtils.isNotBlank(runs) && !RuntimeMode.voteRunMode(runs)) { + continue; + } + // coordinate to system timezone long beat = calcBeatMills(r, now); if (beat <= 0) continue; diff --git a/wings/silencer-curse/src/test/java/pro/fessional/wings/silencer/modulate/RuntimeModeTest.java b/wings/silencer-curse/src/test/java/pro/fessional/wings/silencer/modulate/RuntimeModeTest.java index 1aa96b871..152c03795 100644 --- a/wings/silencer-curse/src/test/java/pro/fessional/wings/silencer/modulate/RuntimeModeTest.java +++ b/wings/silencer-curse/src/test/java/pro/fessional/wings/silencer/modulate/RuntimeModeTest.java @@ -44,6 +44,7 @@ void isRunMode() { Assertions.assertTrue(RuntimeMode.voteRunMode(" !local, ")); Assertions.assertFalse(RuntimeMode.voteRunMode(" !develop, !test, ")); Assertions.assertFalse(RuntimeMode.voteRunMode(" !test, ")); + Assertions.assertFalse(RuntimeMode.voteRunMode("!test")); } @Test From fc0c41f170df603ae5f7db19b7885b4a6ce45db9 Mon Sep 17 00:00:00 2001 From: trydofor Date: Tue, 13 Aug 2024 15:10:42 +0800 Subject: [PATCH 46/51] =?UTF-8?q?=F0=9F=A7=91=E2=80=8D=F0=9F=92=BB=20start?= =?UTF-8?q?er.sh=20status=20wings=20git=20info=20#286?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- observe/scripts/wings-starter.sh | 27 ++++++++++++++----- .../util/FlywaveRevisionScannerTest.java | 4 +-- .../main/java/pro/fessional/wings/WhoAmI.java | 2 +- .../warlock/security/GuestSessionTest.java | 2 +- 4 files changed, 25 insertions(+), 10 deletions(-) diff --git a/observe/scripts/wings-starter.sh b/observe/scripts/wings-starter.sh index 1c4995583..87fbe4582 100755 --- a/observe/scripts/wings-starter.sh +++ b/observe/scripts/wings-starter.sh @@ -148,15 +148,30 @@ function print_args() { git_jar="${BOOT_JAR}" fi if [[ -f "$git_jar" ]]; then - giti=$(jar tf "$git_jar" 2>/dev/null | grep git.properties ) + tmp="./tmp-$BOOT_MD5" + jls="$tmp/jar-list.txt" + mkdir -p "$tmp" + jar tf "$git_jar" > "$jls" + + giti=$(grep 'git.properties' "$jls") if [[ "$giti" != "" ]]; then - tmp="./tmp-$BOOT_MD5" - mkdir -p "$tmp" (cd "$tmp" && jar xf "$git_jar" "$giti") - echo -e "\033[37;42;1mINFO: ==== git build info ==== \033[0m" - grep -vE '=$' "$tmp/$giti" - rm -rf "$tmp" + if [[ -f "$tmp/$giti" ]]; then + echo -e "\033[37;42;1mINFO: ==== git build info ==== \033[0m" + grep -vE '=$' "$tmp/$giti" + fi + fi + + wngi=$(grep -E 'silencer-[1-9].*.jar' "$jls") + if [[ "$wngi" != "" ]]; then + (cd "$tmp" && jar xf "$git_jar" "$wngi" && jar xf "$wngi" git.properties) + if [[ -f "$tmp/git.properties" ]]; then + echo -e "\033[37;42;1mINFO: ==== git wings info ==== \033[0m" + grep -vE '=$' "$tmp/git.properties" + fi fi + + rm -rf "$tmp" fi } diff --git a/wings/faceless-flywave/src/test/java/pro/fessional/wings/faceless/util/FlywaveRevisionScannerTest.java b/wings/faceless-flywave/src/test/java/pro/fessional/wings/faceless/util/FlywaveRevisionScannerTest.java index c950b936a..084dce0a1 100644 --- a/wings/faceless-flywave/src/test/java/pro/fessional/wings/faceless/util/FlywaveRevisionScannerTest.java +++ b/wings/faceless-flywave/src/test/java/pro/fessional/wings/faceless/util/FlywaveRevisionScannerTest.java @@ -37,8 +37,8 @@ public void flywaveBranchPath() { @TmsLink("C12029") public void flywaveCommentInfo() { assertEquals("master/2022-0601_01-test.sql", FlywaveRevisionScanner.commentInfo( - "/Users/trydofor/Workspace/github.com/pro.fessional.wings/wings/faceless/src/test/resources/wings-flywave/master/2022-0601u01-test.sql", - "/Users/trydofor/Workspace/github.com/pro.fessional.wings/wings/faceless/src/test/resources/wings-flywave/master/2022-0601v01-test.sql" + "github.com/professional-wings/wings/faceless/src/test/resources/wings-flywave/master/2022-0601u01-test.sql", + "github.com/professional-wings/wings/faceless/src/test/resources/wings-flywave/master/2022-0601v01-test.sql" )); } diff --git a/wings/silencer/src/main/java/pro/fessional/wings/WhoAmI.java b/wings/silencer/src/main/java/pro/fessional/wings/WhoAmI.java index c6d7726bd..f3f1624b9 100644 --- a/wings/silencer/src/main/java/pro/fessional/wings/WhoAmI.java +++ b/wings/silencer/src/main/java/pro/fessional/wings/WhoAmI.java @@ -43,7 +43,7 @@ public static void main(String[] args) throws Exception { buff.append("\n\n## Detailed Description\n"); buff.append("\n\n## Possible Solution\n"); - String url = "https://github.com/trydofor/pro.fessional.wings/issues/new?body=" + + String url = "https://github.com/trydofor/professional-wings/issues/new?body=" + URLEncoder.encode(buff.toString(), StandardCharsets.UTF_8) .replace("+", "%20") .replace("*", "%2A"); diff --git a/wings/warlock-shadow/src/test/java/pro/fessional/wings/warlock/security/GuestSessionTest.java b/wings/warlock-shadow/src/test/java/pro/fessional/wings/warlock/security/GuestSessionTest.java index cfc97fbb1..f5522ff1f 100644 --- a/wings/warlock-shadow/src/test/java/pro/fessional/wings/warlock/security/GuestSessionTest.java +++ b/wings/warlock-shadow/src/test/java/pro/fessional/wings/warlock/security/GuestSessionTest.java @@ -15,7 +15,7 @@ import pro.fessional.wings.slardar.httprest.okhttp.OkHttpClientHelper; /** - * Principal required + * Principal required * * @author trydofor * @since 2021-03-09 From 0c75d23891a0101e7a3a0f199ddab15e734d7aa9 Mon Sep 17 00:00:00 2001 From: trydofor Date: Fri, 16 Aug 2024 13:44:51 +0800 Subject: [PATCH 47/51] =?UTF-8?q?=F0=9F=A9=BA=20log=20monitor=20support=20?= =?UTF-8?q?error=20section?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- observe/docs | 2 +- observe/mirana | 2 +- .../wings/slardar/monitor/metric/LogMetric.java | 9 ++++++++- .../resources/wings-conf/wings-monitor-79.properties | 2 ++ 4 files changed, 12 insertions(+), 3 deletions(-) diff --git a/observe/docs b/observe/docs index 452ba76a5..357ba1613 160000 --- a/observe/docs +++ b/observe/docs @@ -1 +1 @@ -Subproject commit 452ba76a5f29f0177f594b33ca38683a0b37f9c1 +Subproject commit 357ba1613d40455c54bce65fae39c15d54f05776 diff --git a/observe/mirana b/observe/mirana index cacdfa276..b092cea69 160000 --- a/observe/mirana +++ b/observe/mirana @@ -1 +1 @@ -Subproject commit cacdfa276d38b9efa5fcfcfc4ad6ca52fa8b8be0 +Subproject commit b092cea6903b7c2412e1cb7dd9de26c1bdc54084 diff --git a/wings/slardar/src/main/java/pro/fessional/wings/slardar/monitor/metric/LogMetric.java b/wings/slardar/src/main/java/pro/fessional/wings/slardar/monitor/metric/LogMetric.java index 4fca8da99..924f5223c 100644 --- a/wings/slardar/src/main/java/pro/fessional/wings/slardar/monitor/metric/LogMetric.java +++ b/wings/slardar/src/main/java/pro/fessional/wings/slardar/monitor/metric/LogMetric.java @@ -62,7 +62,7 @@ public String getKey() { } final long from = readLastForm(); - final LogStat.Stat stat = LogStat.stat(rule.file, from, rule.getPreview(), rule.getRuntimeKeys()); + final LogStat.Stat stat = LogStat.stat(rule.file, from, rule.getPreview(), rule.getSection(), rule.getRuntimeKeys()); log.debug("LogStat-{}, stat={}", key, stat); writeLastFrom(stat); @@ -224,6 +224,13 @@ public static class Rule { private int preview = 10; public static final String Key$preview = Key + ".preview"; + /** + * section size of intended lines + * @see #Key$section + */ + private int section = 50; + public static final String Key$section = Key + ".section"; + /** * log charset */ diff --git a/wings/slardar/src/main/resources/wings-conf/wings-monitor-79.properties b/wings/slardar/src/main/resources/wings-conf/wings-monitor-79.properties index e32257d69..c15954352 100644 --- a/wings/slardar/src/main/resources/wings-conf/wings-monitor-79.properties +++ b/wings/slardar/src/main/resources/wings-conf/wings-monitor-79.properties @@ -49,6 +49,8 @@ wings.slardar.monitor.log.default.level=' WARN ',' ERROR ' wings.slardar.monitor.log.default.keyword= ## preview lines after found keyword wings.slardar.monitor.log.default.preview=10 +## section size of intended lines +wings.slardar.monitor.log.default.section=50 ## log charset wings.slardar.monitor.log.default.charset=UTF8 ## delete scanned files older than N days, `-1` means no cleaning From 828298a9b5998cf506eb33f4ddcaf24259b45bf8 Mon Sep 17 00:00:00 2001 From: trydofor Date: Fri, 16 Aug 2024 17:38:30 +0800 Subject: [PATCH 48/51] =?UTF-8?q?=F0=9F=A7=91=E2=80=8D=F0=9F=92=BB=20relea?= =?UTF-8?q?se.sh=20use=20pull=20--force=20#286?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- observe/scripts/wings-release.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/observe/scripts/wings-release.sh b/observe/scripts/wings-release.sh index 8e635e098..c1acded3b 100755 --- a/observe/scripts/wings-release.sh +++ b/observe/scripts/wings-release.sh @@ -276,7 +276,7 @@ case "$1" in check_cmd git echo -e "\033[37;42;1m ==== PULL $WORK_DIR ==== \033[0m" - git pull + git pull --force echo -e "\033[37;42;1m ==== DONE $WORK_DIR ==== \033[0m" git status git log --pretty=format:'%H - %an, %ad %d : %s' --graph -10 From 24e6a778a757b640230b51deab49236640e1d35c Mon Sep 17 00:00:00 2001 From: trydofor Date: Tue, 27 Aug 2024 17:26:30 +0800 Subject: [PATCH 49/51] =?UTF-8?q?=E2=9C=A8=20Watching=20collect=20to=20mai?= =?UTF-8?q?l=20#289?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- observe/docs | 2 +- .../wings/silencer/watch/Watches.java | 44 ++++++++++++++++--- .../okhttp/OkHttpTweakLogInterceptor.java | 6 +-- .../warlock/other/WarlockWatchingTest.java | 32 +++++++++----- 4 files changed, 63 insertions(+), 21 deletions(-) diff --git a/observe/docs b/observe/docs index 357ba1613..3994bc754 160000 --- a/observe/docs +++ b/observe/docs @@ -1 +1 @@ -Subproject commit 357ba1613d40455c54bce65fae39c15d54f05776 +Subproject commit 3994bc7543de12ccf2901da881268cc0fa731384 diff --git a/wings/silencer-curse/src/main/java/pro/fessional/wings/silencer/watch/Watches.java b/wings/silencer-curse/src/main/java/pro/fessional/wings/silencer/watch/Watches.java index bfd5b4e48..3047b7313 100644 --- a/wings/silencer-curse/src/main/java/pro/fessional/wings/silencer/watch/Watches.java +++ b/wings/silencer-curse/src/main/java/pro/fessional/wings/silencer/watch/Watches.java @@ -5,8 +5,11 @@ import org.jetbrains.annotations.Nullable; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import pro.fessional.mirana.best.DummyBlock; import pro.fessional.mirana.time.StopWatch; +import java.util.function.BiConsumer; + /** * Performance Monitoring * @@ -57,16 +60,38 @@ public static StopWatch.Watch current(String name) { /** * Release the current timer and returns whether all timers have finished. - * When all timings are finished, clear the log if clean, write to log if token != null. + * When all timings are finished, clear the watches if clean. + */ + public static boolean release(boolean clean) { + return release(clean, null, WatchHandler); + } + + /** + * Release the current timer and returns whether all timers have finished. + * When all timings are finished, handle the StopWatch if token is not null, clear the watches if clean. */ - public static boolean release(boolean clean, String token) { + public static boolean release(boolean clean, @Nullable String token) { + return release(clean, token, WatchHandler); + } + + /** + * Release the current timer and returns whether all timers have finished. + * When all timings are finished, handle the StopWatch if token is not null, clear the watches if clean. + */ + public static boolean release(boolean clean, @Nullable String token, @NotNull BiConsumer handle) { StopWatch watch = StopWatches.get(); if (watch == null || watch.isRunning()) return false; StopWatches.remove(); if (token != null) { - logging(token, watch); + try { + handle.accept(token, watch); + } + catch (Exception e) { + DummyBlock.ignore(e); + } } + if (clean) { watch.clear(); } @@ -74,9 +99,16 @@ public static boolean release(boolean clean, String token) { } /** - * output info to the log with token at Warn level + * to handle the StopWatch when timings are finished and token is not null. + * should handle the StopWatch before its clean. + * + * @param handler token and StopWatch are not null */ - public static void logging(String token, StopWatch watch) { - log.warn("Watching {} {}", token, watch); + public static void setWatchHandler(BiConsumer handler) { + WatchHandler = handler; } + + private static volatile BiConsumer WatchHandler = (token, watch) -> { + log.warn("Watching {} {}", token, watch); + }; } diff --git a/wings/slardar/src/main/java/pro/fessional/wings/slardar/httprest/okhttp/OkHttpTweakLogInterceptor.java b/wings/slardar/src/main/java/pro/fessional/wings/slardar/httprest/okhttp/OkHttpTweakLogInterceptor.java index b88e51f30..9a26de0c8 100644 --- a/wings/slardar/src/main/java/pro/fessional/wings/slardar/httprest/okhttp/OkHttpTweakLogInterceptor.java +++ b/wings/slardar/src/main/java/pro/fessional/wings/slardar/httprest/okhttp/OkHttpTweakLogInterceptor.java @@ -119,14 +119,14 @@ public Response intercept(@NotNull Interceptor.Chain chain) throws IOException { return itc.intercept(chain); } - // + // watch if the caller thread has watching final Request request = chain.request(); final String name = "OkHttp " + request.method() + " " + request.url(); - try (StopWatch.Watch watch = current.start(name)) { + try (StopWatch.Watch ignore = current.start(name)) { return itc.intercept(chain); } finally { - Watches.release(true, null); + Watches.release(true); } } diff --git a/wings/warlock-shadow/src/test/java/pro/fessional/wings/warlock/other/WarlockWatchingTest.java b/wings/warlock-shadow/src/test/java/pro/fessional/wings/warlock/other/WarlockWatchingTest.java index 939ba0376..257d92f0e 100644 --- a/wings/warlock-shadow/src/test/java/pro/fessional/wings/warlock/other/WarlockWatchingTest.java +++ b/wings/warlock-shadow/src/test/java/pro/fessional/wings/warlock/other/WarlockWatchingTest.java @@ -17,33 +17,40 @@ import pro.fessional.wings.slardar.httprest.okhttp.OkHttpClientHelper; import pro.fessional.wings.warlock.app.service.TestWatchingService; +import java.util.concurrent.atomic.AtomicReference; + /** * @author trydofor * @since 2022-11-22 */ @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, - properties = { - "spring.wings.warlock.enabled.watching=true", - "wings.warlock.watching.jooq-threshold=0", - "wings.warlock.watching.service-threshold=0", - "wings.warlock.watching.controller-threshold=0", - }) + properties = { + "spring.wings.warlock.enabled.watching=true", + "wings.warlock.watching.jooq-threshold=0", + "wings.warlock.watching.service-threshold=0", + "wings.warlock.watching.controller-threshold=0", + }) @Slf4j @DependsOnDatabaseInitialization public class WarlockWatchingTest { - @Setter(onMethod_ = {@Value("http://localhost:${local.server.port}")}) + @Setter(onMethod_ = { @Value("http://localhost:${local.server.port}") }) private String host; - @Setter(onMethod_ = {@Autowired}) + @Setter(onMethod_ = { @Autowired }) private OkHttpClient okHttpClient; - /** - * Check the log - */ @Test @TmsLink("C14037") public void testWatching() { + final AtomicReference tkn = new AtomicReference<>(); + final AtomicReference wtc = new AtomicReference<>(); + + Watches.setWatchHandler((t, w) -> { + tkn.set(t); + wtc.set(w.toString()); + }); + final StopWatch.Watch watch = Watches.acquire("testWatching"); final Request.Builder body = new Request.Builder().url(host + "/test/watching.json"); final Response r1 = OkHttpClientHelper.execute(okHttpClient, body, false); @@ -55,5 +62,8 @@ public void testWatching() { // async in async task pool Assertions.assertTrue(2 <= TestWatchingService.AsyncWatch.size()); Assertions.assertTrue(TestWatchingService.WatchOwner.getWatches().isEmpty()); + + Assertions.assertEquals("testWatching", tkn.get()); + Assertions.assertTrue(wtc.get().contains("testWatching"), wtc.get()); } } From 9a364cec661521beb7cb8124fdd6e4fe746a88b8 Mon Sep 17 00:00:00 2001 From: trydofor Date: Wed, 28 Aug 2024 19:10:47 +0800 Subject: [PATCH 50/51] =?UTF-8?q?=F0=9F=9A=B8=20LogView=20ignore=20preview?= =?UTF-8?q?=20if=20no=20keywords=20#241?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../slardar/monitor/metric/LogMetric.java | 47 ++++++++++++------- .../slardar/monitor/viewer/LogViewer.java | 27 +++++++++-- .../spring/prop/SlardarMonitorProp.java | 12 +++++ .../slardar/monitor/viewer/LogViewerTest.java | 30 ++++++++++-- .../warlock/controller/api/WebLogViewer.java | 2 +- 5 files changed, 93 insertions(+), 25 deletions(-) diff --git a/wings/slardar/src/main/java/pro/fessional/wings/slardar/monitor/metric/LogMetric.java b/wings/slardar/src/main/java/pro/fessional/wings/slardar/monitor/metric/LogMetric.java index 924f5223c..69805c9e7 100644 --- a/wings/slardar/src/main/java/pro/fessional/wings/slardar/monitor/metric/LogMetric.java +++ b/wings/slardar/src/main/java/pro/fessional/wings/slardar/monitor/metric/LogMetric.java @@ -62,7 +62,7 @@ public String getKey() { } final long from = readLastForm(); - final LogStat.Stat stat = LogStat.stat(rule.file, from, rule.getPreview(), rule.getSection(), rule.getRuntimeKeys()); + final LogStat.Stat stat = LogStat.stat(rule.file, from, rule.getPreview(), rule.getSection(), rule.genStatKey()); log.debug("LogStat-{}, stat={}", key, stat); writeLastFrom(stat); @@ -226,6 +226,7 @@ public static class Rule { /** * section size of intended lines + * * @see #Key$section */ private int section = 50; @@ -280,26 +281,38 @@ public String maskKey(String kw) { * Auto remove a pair of quotes, construct bytes by charset */ @SneakyThrows - public List getRuntimeKeys() { + public List genStatKey() { List rst = new ArrayList<>(); - if (level != null) { - for (String s : level) { - String kw = trimKey(s, false); - if (kw.isEmpty()) continue; - LogStat.Word wd = new LogStat.Word(); - wd.range2 = bound; - wd.bytes = kw.getBytes(charset); - rst.add(wd); + for (String kw : genRuleKey()) { + LogStat.Word wd = new LogStat.Word(); + wd.range2 = bound; + wd.bytes = kw.getBytes(charset); + rst.add(wd); + } + return rst; + } + + /** + * Auto remove a pair of quotes, merge level and its keyword + */ + public List genRuleKey() { + List rst = new ArrayList<>(); + if (level == null) return rst; + + for (String s : level) { + String kw = trimKey(s, false); + if (!kw.isEmpty()) { + rst.add(kw); } - for (String s : keyword) { - String kw = trimKey(s, false); - if (kw.isEmpty()) continue; - LogStat.Word wd = new LogStat.Word(); - wd.range1 = bound; - wd.bytes = kw.getBytes(charset); - rst.add(wd); + } + + for (String s : keyword) { + String kw = trimKey(s, false); + if (kw.isEmpty()) { + rst.add(kw); } } + return rst; } } diff --git a/wings/slardar/src/main/java/pro/fessional/wings/slardar/monitor/viewer/LogViewer.java b/wings/slardar/src/main/java/pro/fessional/wings/slardar/monitor/viewer/LogViewer.java index 91220a28c..5a9300e75 100644 --- a/wings/slardar/src/main/java/pro/fessional/wings/slardar/monitor/viewer/LogViewer.java +++ b/wings/slardar/src/main/java/pro/fessional/wings/slardar/monitor/viewer/LogViewer.java @@ -4,6 +4,7 @@ import lombok.extern.slf4j.Slf4j; import org.apache.commons.io.IOUtils; import org.cache2k.Cache; +import org.jetbrains.annotations.NotNull; import pro.fessional.mirana.id.Ulid; import pro.fessional.wings.slardar.cache.cache2k.WingsCache2k; import pro.fessional.wings.slardar.monitor.WarnFilter; @@ -17,9 +18,11 @@ import java.io.OutputStream; import java.util.ArrayList; import java.util.Collection; +import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; +import java.util.Set; import java.util.regex.Pattern; /** @@ -31,11 +34,13 @@ public class LogViewer implements WarnFilter { @Getter private final LogConf conf; + private final Set keys = new HashSet<>(); private final Cache cache; - public LogViewer(LogConf conf) { + public LogViewer(@NotNull LogConf conf, @NotNull Collection keys) { this.conf = conf; this.cache = WingsCache2k.builder(LogViewer.class, "cache", 2_000, conf.getAlive(), null, String.class, String.class).build(); + this.keys.addAll(keys); } public void view(String id, OutputStream output) throws IOException { @@ -101,15 +106,15 @@ protected boolean canIgnoreHead(String out) { final File file = new File(out); if (file.length() > max || !file.canRead()) return false; - final Pattern head = conf.getHeader(); try (BufferedReader reader = new BufferedReader(new FileReader(file))) { String line; int tol = 0; int cnt = 0; + final Pattern head = conf.getHeader(); while ((line = reader.readLine()) != null && max > 0) { max -= line.length() + 1; // loose calculation - if (line.isEmpty() || (head != null && !head.matcher(line).find())) { + if (ignoreLine(line, head)) { continue; } @@ -125,7 +130,23 @@ protected boolean canIgnoreHead(String out) { return tol == cnt; } catch (Exception e) { + return false; + } + } + + private boolean ignoreLine(String line, Pattern head) { + if (line.isEmpty()) return true; + + if (head != null && !head.matcher(line).find()) { return true; } + + for (String key : keys) { + if (line.contains(key)) { + return false; + } + } + + return true; } } diff --git a/wings/slardar/src/main/java/pro/fessional/wings/slardar/spring/prop/SlardarMonitorProp.java b/wings/slardar/src/main/java/pro/fessional/wings/slardar/spring/prop/SlardarMonitorProp.java index 09a504b9a..cc3bfe3e2 100644 --- a/wings/slardar/src/main/java/pro/fessional/wings/slardar/spring/prop/SlardarMonitorProp.java +++ b/wings/slardar/src/main/java/pro/fessional/wings/slardar/spring/prop/SlardarMonitorProp.java @@ -7,6 +7,7 @@ import pro.fessional.wings.slardar.monitor.viewer.LogConf; import java.util.HashMap; +import java.util.LinkedHashSet; import java.util.Map; /** @@ -70,4 +71,15 @@ public class SlardarMonitorProp { */ private String dingNotice = "monitor"; public static final String Key$dingNotice = Key + ".ding-notice"; + + /** + * generate all log's rule keys + */ + public LinkedHashSet genRuleKey() { + LinkedHashSet rst = new LinkedHashSet<>(); + for (LogMetric.Rule rl : log.values()) { + rst.addAll(rl.genRuleKey()); + } + return rst; + } } diff --git a/wings/slardar/src/test/java/pro/fessional/wings/slardar/monitor/viewer/LogViewerTest.java b/wings/slardar/src/test/java/pro/fessional/wings/slardar/monitor/viewer/LogViewerTest.java index 5c9a501b2..7ae9e7131 100644 --- a/wings/slardar/src/test/java/pro/fessional/wings/slardar/monitor/viewer/LogViewerTest.java +++ b/wings/slardar/src/test/java/pro/fessional/wings/slardar/monitor/viewer/LogViewerTest.java @@ -24,15 +24,37 @@ class LogViewerTest { @TmsLink("13128") @Test void canIgnoreHead() throws Exception { - final LogViewer lv = new LogViewer(slardarMonitorProp.getView()); + final LogViewer lv = new LogViewer(slardarMonitorProp.getView(), slardarMonitorProp.genRuleKey()); final Path tmp0 = Files.createTempFile("test-", null); tmp0.toFile().deleteOnExit(); Files.writeString(tmp0, """ - 2024-07-21 22:05:22.957 ERROR 10884 --- [kite-front] [XNIO-1 I/O-4] io.undertow.request : UT005071: Undertow request failed HttpServerExchange{ CONNECT api.ipify.org:443} - + ######### #1 KEYWORD: ERROR ######### + 2024-08-28 07:01:54.441 ERROR 3306238 --- [admin-test] [XNIO-1 I/O-2] io.undertow.request : UT005071: Undertow request failed HttpServerExchange{ CONNECT eth0.me:443} + java.lang.IllegalArgumentException: UT000068: Servlet path match failed - at io.undertow.servlet.handlers.ServletPathMatchesData.getServletHandlerByPath(ServletPathMatchesData.java:83) ~[undertow-servlet-2.3.10.Final.jar!/:2.3.10.Final] + at io.undertow.servlet.handlers.ServletPathMatchesData.getServletHandlerByPath(ServletPathMatchesData.java:83) ~[undertow-servlet-2.3.13.Final.jar!/:2.3.13.Final] + at io.undertow.servlet.handlers.ServletPathMatches.getServletHandlerByPath(ServletPathMatches.java:133) ~[undertow-servlet-2.3.13.Final.jar!/:2.3.13.Final] + at io.undertow.servlet.handlers.ServletInitialHandler.handleRequest(ServletInitialHandler.java:148) ~[undertow-servlet-2.3.13.Final.jar!/:2.3.13.Final] + at io.undertow.server.handlers.HttpContinueReadHandler.handleRequest(HttpContinueReadHandler.java:69) ~[undertow-core-2.3.13.Final.jar!/:2.3.13.Final] + at org.springframework.boot.web.embedded.undertow.DeploymentManagerHttpHandlerFactory$DeploymentManagerHandler.handleRequest(DeploymentManagerHttpHandlerFactory.java:74) ~[spring-boot-3.2.8.jar!/:3.2.8] + at io.undertow.server.handlers.GracefulShutdownHandler.handleRequest(GracefulShutdownHandler.java:94) ~[undertow-core-2.3.13.Final.jar!/:2.3.13.Final] + at io.undertow.server.Connectors.executeRootHandler(Connectors.java:393) ~[undertow-core-2.3.13.Final.jar!/:2.3.13.Final] + at io.undertow.server.protocol.http.HttpReadListener.handleEventWithNoRunningRequest(HttpReadListener.java:265) ~[undertow-core-2.3.13.Final.jar!/:2.3.13.Final] + at io.undertow.server.protocol.http.HttpReadListener.handleEvent(HttpReadListener.java:136) ~[undertow-core-2.3.13.Final.jar!/:2.3.13.Final] + at io.undertow.server.protocol.http.HttpReadListener.handleEvent(HttpReadListener.java:59) ~[undertow-core-2.3.13.Final.jar!/:2.3.13.Final] + at org.xnio.ChannelListeners.invokeChannelListener(ChannelListeners.java:92) ~[xnio-api-3.8.8.Final.jar!/:3.8.8.Final] + at org.xnio.conduits.ReadReadyHandler$ChannelListenerHandler.readReady(ReadReadyHandler.java:66) ~[xnio-api-3.8.8.Final.jar!/:3.8.8.Final] + at org.xnio.nio.NioSocketConduit.handleReady(NioSocketConduit.java:89) ~[xnio-nio-3.8.8.Final.jar!/:3.8.8.Final] + at org.xnio.nio.WorkerThread.run(WorkerThread.java:591) ~[xnio-nio-3.8.8.Final.jar!/:3.8.8.Final] + + 2024-08-28 07:02:13.000 DEBUG 3306238 --- [admin-test] [task-7] org.jooq.tools.LoggerListener : Executing query : update `win_task_define` set `next_lock` = (`next_lock` + ?), `last_exec` = ? where (`id` = ? and `next_lock` = ?) + 2024-08-28 07:02:13.000 DEBUG 3306238 --- [admin-test] [task-7] org.jooq.tools.LoggerListener : -> with bind values : update `win_task_define` set `next_lock` = (`next_lock` + 1), `last_exec` = {ts '2024-08-28 07:02:13.0'} where (`id` = 1107 and `next_lock` = 89552) + 2024-08-28 07:02:13.005 DEBUG 3306238 --- [admin-test] [task-7] org.jooq.tools.LoggerListener : Affected row(s) : 1 + 2024-08-28 07:02:13.005 INFO 3306238 --- [admin-test] [task-7] p.f.w.t.t.s.i.TinyTaskExecServiceImpl : tiny-task exec, id=1107, prop=bill-expire + 2024-08-28 07:02:13.006 INFO 3306238 --- [admin-test] [task-7] p.f.w.t.t.s.i.TinyTaskExecServiceImpl : tiny-task done, id=1107, prop=bill-expire + 2024-08-28 07:02:13.007 DEBUG 3306238 --- [admin-test] [light-id-buffered-provider-2] o.s.jdbc.core.JdbcTemplate : Executing prepared SQL query + 2024-08-28 07:02:13.007 DEBUG 3306238 --- [admin-test] [light-id-buffered-provider-2] o.s.jdbc.core.JdbcTemplate : Executing prepared SQL statement [SELECT next_val, step_val FROM sys_light_sequence WHERE block_id=? AND seq_name=? FOR UPDATE] """.stripIndent()); diff --git a/wings/warlock-shadow/src/main/java/pro/fessional/wings/warlock/controller/api/WebLogViewer.java b/wings/warlock-shadow/src/main/java/pro/fessional/wings/warlock/controller/api/WebLogViewer.java index 89e90d2d9..33cabd839 100644 --- a/wings/warlock-shadow/src/main/java/pro/fessional/wings/warlock/controller/api/WebLogViewer.java +++ b/wings/warlock-shadow/src/main/java/pro/fessional/wings/warlock/controller/api/WebLogViewer.java @@ -25,7 +25,7 @@ public class WebLogViewer extends LogViewer { @Autowired public WebLogViewer(SlardarMonitorProp prop) { - super(prop.getView()); + super(prop.getView(), prop.genRuleKey()); } @Operation(summary = "Alarm logs can be viewed in conjunction with alarm notifications when self-monitoring is enabled.", description = """ From a5144e34424e66b4ad59209fd1fde9b1637ae877 Mon Sep 17 00:00:00 2001 From: trydofor Date: Sat, 31 Aug 2024 12:41:28 +0800 Subject: [PATCH 51/51] =?UTF-8?q?=F0=9F=94=96=203.2.130?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/release-notes.yml | 2 ++ observe/docs | 2 +- observe/mirana | 2 +- pom.xml | 2 +- 4 files changed, 5 insertions(+), 3 deletions(-) diff --git a/.github/workflows/release-notes.yml b/.github/workflows/release-notes.yml index 746fc8d79..e20118b3a 100644 --- a/.github/workflows/release-notes.yml +++ b/.github/workflows/release-notes.yml @@ -62,6 +62,8 @@ jobs: labels: [ "feature" ] - title: "🐞 Bug Fixes" labels: [ "bug" ] + - title: "💥 Breaking Change" + labels: [ "break" ] - title: "💎 Enhancements" labels: [ "better", "devops", "quality" ] - title: "📝 Documentation" diff --git a/observe/docs b/observe/docs index 3994bc754..14ebccb0d 160000 --- a/observe/docs +++ b/observe/docs @@ -1 +1 @@ -Subproject commit 3994bc7543de12ccf2901da881268cc0fa731384 +Subproject commit 14ebccb0d5142c697c8e1c26714477f1e205282c diff --git a/observe/mirana b/observe/mirana index b092cea69..532d397fc 160000 --- a/observe/mirana +++ b/observe/mirana @@ -1 +1 @@ -Subproject commit b092cea6903b7c2412e1cb7dd9de26c1bdc54084 +Subproject commit 532d397fc5284f4817a4a82c870b3f9e35050637 diff --git a/pom.xml b/pom.xml index f20f40a33..f997377af 100644 --- a/pom.xml +++ b/pom.xml @@ -46,7 +46,7 @@ 1.12.0 2.2.3 - 2.7.3-SNAPSHOT + 2.7.3 1.5.1 2.3.3 2.0.52