Browse Source

Merge pull request #14976 from thingsboard/feature/java25

Migration to Java 25
pull/15084/head
Viacheslav Klimov 7 months ago
committed by GitHub
parent
commit
fa1f4ff9bf
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 2
      .github/workflows/license-header-format.yml
  2. 36
      application/src/main/data/json/edge/instructions/install/centos/instructions.md
  3. 12
      application/src/main/data/json/edge/instructions/install/ubuntu/instructions.md
  4. 9
      application/src/test/java/org/thingsboard/server/service/script/TbelInvokeDocsIoTest.java
  5. 134
      common/script/script-api/src/test/java/org/thingsboard/script/api/tbel/TbDateTest.java
  6. 4
      common/util/src/main/java/org/thingsboard/common/util/ThingsBoardThreadFactory.java
  7. 36
      dao/src/main/java/org/thingsboard/server/dao/sql/alarm/AlarmRepository.java
  8. 12
      dao/src/main/java/org/thingsboard/server/dao/sql/audit/AuditLogRepository.java
  9. 13
      msa/tb/docker-cassandra/Dockerfile
  10. 8
      msa/tb/docker-postgres/Dockerfile
  11. 56
      packaging/java/build.gradle
  12. 8
      packaging/java/scripts/windows/install.bat
  13. 39
      packaging/js/build.gradle
  14. 28
      pom.xml

2
.github/workflows/license-header-format.yml

@ -35,7 +35,7 @@ jobs:
uses: actions/setup-java@v4 uses: actions/setup-java@v4
with: with:
distribution: 'corretto' # https://github.com/actions/setup-java?tab=readme-ov-file#supported-distributions distribution: 'corretto' # https://github.com/actions/setup-java?tab=readme-ov-file#supported-distributions
java-version: '21' java-version: '25'
cache: 'maven' # https://github.com/actions/setup-java?tab=readme-ov-file#caching-sbt-dependencies cache: 'maven' # https://github.com/actions/setup-java?tab=readme-ov-file#caching-sbt-dependencies
- name: License header format - name: License header format

36
application/src/main/data/json/edge/instructions/install/centos/instructions.md

@ -1,22 +1,24 @@
Here is the list of commands that can be used to quickly install ThingsBoard Edge on RHEL/CentOS 7/8 and connect to the server. Here is the list of commands that can be used to quickly install ThingsBoard Edge on RHEL/CentOS 9/10 and connect to the server.
**Note:** OpenJDK 25 requires RHEL/CentOS 9+ or RHEL/CentOS 10+. Earlier versions (RHEL/CentOS 7, 8) are not supported.
#### Prerequisites #### Prerequisites
Before continuing to installation, execute the following commands to install the necessary tools: Before continuing to installation, execute the following commands to install the necessary tools:
```bash ```bash
sudo yum install -y nano wget && sudo yum install -y https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm sudo dnf install -y nano wget
{:copy-code} {:copy-code}
``` ```
#### Step 1. Install Java 17 (OpenJDK) #### Step 1. Install Java 25 (OpenJDK)
ThingsBoard service is running on Java 17. To install OpenJDK 17, follow these instructions: ThingsBoard service is running on Java 25. To install OpenJDK 25, follow these instructions:
```bash ```bash
sudo dnf install java-17-openjdk sudo dnf install -y java-25-openjdk
{:copy-code} {:copy-code}
``` ```
Configure your operating system to use OpenJDK 17 by default. You can configure the default version by running the following command: Configure your operating system to use OpenJDK 25 by default. You can configure the default version by running the following command:
```bash ```bash
sudo update-alternatives --config java sudo update-alternatives --config java
@ -33,7 +35,7 @@ java -version
The expected result is: The expected result is:
```text ```text
openjdk version "17.x.xx" openjdk version "25.x.xx"
OpenJDK Runtime Environment (...) OpenJDK Runtime Environment (...)
OpenJDK 64-Bit Server VM (build ...) OpenJDK 64-Bit Server VM (build ...)
``` ```
@ -41,7 +43,7 @@ OpenJDK 64-Bit Server VM (build ...)
#### Step 2. Configure ThingsBoard Edge Database #### Step 2. Configure ThingsBoard Edge Database
ThingsBoard Edge supports **SQL** and **hybrid** database configurations. ThingsBoard Edge supports **SQL** and **hybrid** database configurations.
In this guide, we’ll use an **SQL** database. In this guide, we'll use an **SQL** database.
For more details about the hybrid setup, please refer to the official installation instructions on the <a href="https://thingsboard.io/docs/user-guide/install/edge/rhel/#step-2-configure-thingsboard-database" target="_blank">ThingsBoard documentation site</a>. For more details about the hybrid setup, please refer to the official installation instructions on the <a href="https://thingsboard.io/docs/user-guide/install/edge/rhel/#step-2-configure-thingsboard-database" target="_blank">ThingsBoard documentation site</a>.
To install the PostgreSQL database, run these commands: To install the PostgreSQL database, run these commands:
@ -54,19 +56,19 @@ sudo dnf update
Install the repository RPM: Install the repository RPM:
* **For CentOS/RHEL 8:** * **For RHEL/CentOS 9:**
```bash ```bash
# Install the repository RPM (For CentOS/RHEL 8): # Install the repository RPM (for RHEL/CentOS 9):
sudo sudo dnf -y install https://download.postgresql.org/pub/repos/yum/reporpms/EL-8-x86_64/pgdg-redhat-repo-latest.noarch.rpm sudo dnf -y install https://download.postgresql.org/pub/repos/yum/reporpms/EL-9-x86_64/pgdg-redhat-repo-latest.noarch.rpm
{:copy-code} {:copy-code}
``` ```
* **For CentOS/RHEL 9:** * **For RHEL/CentOS 10:**
```bash ```bash
# Install the repository RPM (for CentOS 9): # Install the repository RPM (for RHEL/CentOS 10):
sudo dnf -y install https://download.postgresql.org/pub/repos/yum/reporpms/EL-9-x86_64/pgdg-redhat-repo-latest.noarch.rpm sudo dnf -y install https://download.postgresql.org/pub/repos/yum/reporpms/EL-10-x86_64/pgdg-redhat-repo-latest.noarch.rpm
{:copy-code} {:copy-code}
``` ```
@ -91,8 +93,8 @@ sudo -u postgres psql -c "\password"
Then, enter and confirm the password. Then, enter and confirm the password.
Since ThingsBoard Edge uses the PostgreSQL database for local storage, configuring MD5 authentication ensures that only authenticated users or Since ThingsBoard Edge uses the PostgreSQL database for local storage, configuring MD5 authentication ensures that only authenticated users or
applications can access the database, thus protecting your data. After configuring the password, applications can access the database, thus protecting your data. After configuring the password,
edit the pg_hba.conf file to use MD5 hashing for authentication instead of the default method (ident) for local IPv4 connections. edit the pg_hba.conf file to use MD5 hashing for authentication instead of the default method (ident) for local IPv4 connections.
To replace ident with md5, run the following command: To replace ident with md5, run the following command:
@ -102,7 +104,7 @@ sudo sed -i 's/^host\s\+all\s\+all\s\+127\.0\.0\.1\/32\s\+ident/host all
{:copy-code} {:copy-code}
``` ```
Then run the command that will restart the PostgreSQL service to apply configuration changes, connect to the database as a postgres user, Then run the command that will restart the PostgreSQL service to apply configuration changes, connect to the database as a postgres user,
and create the ThingsBoard Edge database (tb_edge). To connect to the PostgreSQL database, enter the PostgreSQL password. and create the ThingsBoard Edge database (tb_edge). To connect to the PostgreSQL database, enter the PostgreSQL password.
```bash ```bash

12
application/src/main/data/json/edge/instructions/install/ubuntu/instructions.md

@ -1,14 +1,16 @@
Here is the list of commands that can be used to quickly install ThingsBoard Edge on Ubuntu Server and connect to the server. Here is the list of commands that can be used to quickly install ThingsBoard Edge on Ubuntu Server and connect to the server.
#### Step 1. Install Java 17 (OpenJDK) **Note:** OpenJDK 25 requires Ubuntu 22.04 LTS or newer. Earlier versions (20.04 and below) are not supported.
ThingsBoard service is running on Java 17. To install OpenJDK 17, follow these instructions:
#### Step 1. Install Java 25 (OpenJDK)
ThingsBoard service is running on Java 25. To install OpenJDK 25, follow these instructions:
```bash ```bash
sudo apt update && sudo apt install openjdk-17-jdk sudo apt update && sudo apt install openjdk-25-jdk
{:copy-code} {:copy-code}
``` ```
Configure your operating system to use OpenJDK 17 by default. You can configure the default version by running the following command: Configure your operating system to use OpenJDK 25 by default. You can configure the default version by running the following command:
```bash ```bash
sudo update-alternatives --config java sudo update-alternatives --config java
@ -25,7 +27,7 @@ java -version
The expected result is: The expected result is:
```text ```text
openjdk version "17.x.xx" openjdk version "25.x.xx"
OpenJDK Runtime Environment (...) OpenJDK Runtime Environment (...)
OpenJDK 64-Bit Server VM (build ...) OpenJDK 64-Bit Server VM (build ...)
``` ```

9
application/src/test/java/org/thingsboard/server/service/script/TbelInvokeDocsIoTest.java

@ -2355,7 +2355,8 @@ class TbelInvokeDocsIoTest extends AbstractTbelInvokeTest {
expected.put("date_1", d1.toString()); expected.put("date_1", d1.toString());
TbDate d2 = new TbDate(2023, 8, 6, 4, 4, 5, "Europe/Berlin"); TbDate d2 = new TbDate(2023, 8, 6, 4, 4, 5, "Europe/Berlin");
expected.put("dLocal_2", d2.toLocaleString()); expected.put("dLocal_2", d2.toLocaleString());
expected.put("dLocal_2_us", "8/5/23, 10:04:05 PM"); // Java 21+ uses narrow no-break space (U+202F) before AM/PM per CLDR 42+
expected.put("dLocal_2_us", Runtime.version().feature() >= 21 ? "8/5/23, 10:04:05\u202FPM" : "8/5/23, 10:04:05 PM");
expected.put("dIso_2", d2.toISOString()); expected.put("dIso_2", d2.toISOString());
expected.put("date_2", d2.toString()); expected.put("date_2", d2.toString());
Object actual = invokeScript(evalScript(decoderStr), msgStr); Object actual = invokeScript(evalScript(decoderStr), msgStr);
@ -2387,7 +2388,8 @@ class TbelInvokeDocsIoTest extends AbstractTbelInvokeTest {
""", s2); """, s2);
LinkedHashMap<String, Object> expected = new LinkedHashMap<>(); LinkedHashMap<String, Object> expected = new LinkedHashMap<>();
TbDate d1 = new TbDate(2023, 8, 6, 4, 4, 5); TbDate d1 = new TbDate(2023, 8, 6, 4, 4, 5);
expected.put("dLocal_1_us", "8/6/23, 4:04:05 AM"); // Java 21+ uses narrow no-break space (U+202F) before AM/PM per CLDR 42+
expected.put("dLocal_1_us", Runtime.version().feature() >= 21 ? "8/6/23, 4:04:05\u202FAM" : "8/6/23, 4:04:05 AM");
expected.put("dIso_1", d1.toISOString()); expected.put("dIso_1", d1.toISOString());
expected.put("d1", d1.toString()); expected.put("d1", d1.toString());
TbDate d2 = new TbDate(s2); TbDate d2 = new TbDate(s2);
@ -2419,7 +2421,8 @@ class TbelInvokeDocsIoTest extends AbstractTbelInvokeTest {
TbDate d = new TbDate(2023, 8, 6, 4, 4, 5, "Europe/Berlin"); TbDate d = new TbDate(2023, 8, 6, 4, 4, 5, "Europe/Berlin");
expected.put("dIso", d.toISOString()); expected.put("dIso", d.toISOString());
expected.put("dLocal_utc", d.toLocaleString("UTC")); expected.put("dLocal_utc", d.toLocaleString("UTC"));
expected.put("dLocal_us", "8/5/23, 10:04:05 PM"); // Java 21+ uses narrow no-break space (U+202F) before AM/PM per CLDR 42+
expected.put("dLocal_us", Runtime.version().feature() >= 21 ? "8/5/23, 10:04:05\u202FPM" : "8/5/23, 10:04:05 PM");
expected.put("dLocal_de", "06.08.23, 04:04:05"); expected.put("dLocal_de", "06.08.23, 04:04:05");
Object actual = invokeScript(evalScript(decoderStr), msgStr); Object actual = invokeScript(evalScript(decoderStr), msgStr);
assertEquals(expected, actual); assertEquals(expected, actual);

134
common/script/script-api/src/test/java/org/thingsboard/script/api/tbel/TbDateTest.java

@ -209,7 +209,9 @@ class TbDateTest {
.put("timeZone", "America/New_York") .put("timeZone", "America/New_York")
.put("dateStyle", "full") .put("dateStyle", "full")
.toString())); .toString()));
Assertions.assertEquals("середа, 6 вересня 2023 р.", d.toLocaleDateString("uk-UA", JacksonUtil.newObjectNode() // Java 21+ uses narrow no-break space (U+202F) before "р." per CLDR 42+
String expectedDate_ukUA = Runtime.version().feature() >= 21 ? "середа, 6 вересня 2023\u202Fр." : "середа, 6 вересня 2023 р.";
Assertions.assertEquals(expectedDate_ukUA, d.toLocaleDateString("uk-UA", JacksonUtil.newObjectNode()
.put("timeZone", "Europe/Kiev") .put("timeZone", "Europe/Kiev")
.put("dateStyle", "full") .put("dateStyle", "full")
.toString())); .toString()));
@ -244,12 +246,18 @@ class TbDateTest {
Assertions.assertNotNull(d.toLocaleTimeString()); Assertions.assertNotNull(d.toLocaleTimeString());
Assertions.assertNotNull(d.toLocaleTimeString("en-US")); Assertions.assertNotNull(d.toLocaleTimeString("en-US"));
Assertions.assertEquals("9:04:05 PM", d.toLocaleTimeString("en-US", "America/New_York")); // Java 21+ uses narrow no-break space (U+202F) before AM/PM per CLDR 42+
String expectedTime_enUS = Runtime.version().feature() >= 21 ? "9:04:05\u202FPM" : "9:04:05 PM";
Assertions.assertEquals(expectedTime_enUS, d.toLocaleTimeString("en-US", "America/New_York"));
Assertions.assertEquals("오후 9:04:05", d.toLocaleTimeString("ko-KR", "America/New_York")); Assertions.assertEquals("오후 9:04:05", d.toLocaleTimeString("ko-KR", "America/New_York"));
Assertions.assertEquals("04:04:05", d.toLocaleTimeString( "uk-UA", "Europe/Kiev")); Assertions.assertEquals("04:04:05", d.toLocaleTimeString( "uk-UA", "Europe/Kiev"));
Assertions.assertEquals("9:04:05 م", d.toLocaleTimeString( "ar-EG", "America/New_York")); Assertions.assertEquals("9:04:05 م", d.toLocaleTimeString( "ar-EG", "America/New_York"));
Assertions.assertEquals("9:04:05 PM Eastern Daylight Time", d.toLocaleTimeString("en-US", JacksonUtil.newObjectNode() // Java 21+ uses narrow no-break space (U+202F) before AM/PM per CLDR 42+
String expectedFullTime_enUS = Runtime.version().feature() >= 21
? "9:04:05\u202FPM Eastern Daylight Time"
: "9:04:05 PM Eastern Daylight Time";
Assertions.assertEquals(expectedFullTime_enUS, d.toLocaleTimeString("en-US", JacksonUtil.newObjectNode()
.put("timeZone", "America/New_York") .put("timeZone", "America/New_York")
.put("timeStyle", "full") .put("timeStyle", "full")
.toString())); .toString()));
@ -292,14 +300,27 @@ class TbDateTest {
Assertions.assertNotNull(d.toLocaleString()); Assertions.assertNotNull(d.toLocaleString());
Assertions.assertNotNull(d.toLocaleString("en-US")); Assertions.assertNotNull(d.toLocaleString("en-US"));
Assertions.assertEquals("9/5/23, 9:04:05 PM", d.toLocaleString("en-US", "America/New_York")); // Java 21+ uses narrow no-break space (U+202F) before AM/PM per CLDR 42+
String expectedLocale_enUS = Runtime.version().feature() >= 21 ? "9/5/23, 9:04:05\u202FPM" : "9/5/23, 9:04:05 PM";
Assertions.assertEquals(expectedLocale_enUS, d.toLocaleString("en-US", "America/New_York"));
Assertions.assertEquals("23. 9. 5. 오후 9:04:05", d.toLocaleString("ko-KR", "America/New_York")); Assertions.assertEquals("23. 9. 5. 오후 9:04:05", d.toLocaleString("ko-KR", "America/New_York"));
Assertions.assertEquals("06.09.23, 04:04:05", d.toLocaleString( "uk-UA", "Europe/Kiev")); Assertions.assertEquals("06.09.23, 04:04:05", d.toLocaleString( "uk-UA", "Europe/Kiev"));
String expected_ver = Runtime.version().feature() == 11 ? "5\u200F/9\u200F/2023 9:04:05 م" : // Java 11 has no comma, Java 17 uses ASCII comma, Java 21+ uses Arabic comma (U+060C)
"5\u200F/9\u200F/2023, 9:04:05 م"; String expected_ar;
Assertions.assertEquals(expected_ver, d.toLocaleString( "ar-EG", "America/New_York")); if (Runtime.version().feature() == 11) {
expected_ar = "5\u200F/9\u200F/2023 9:04:05 م";
} else if (Runtime.version().feature() >= 21) {
expected_ar = "5\u200F/9\u200F/2023\u060C 9:04:05 م";
} else {
expected_ar = "5\u200F/9\u200F/2023, 9:04:05 م";
}
Assertions.assertEquals(expected_ar, d.toLocaleString( "ar-EG", "America/New_York"));
Assertions.assertEquals("Tuesday, September 5, 2023 at 9:04:05 PM Eastern Daylight Time", d.toLocaleString("en-US", JacksonUtil.newObjectNode() // Java 21+ changed "at" to "," and uses NNBSP before AM/PM per CLDR 42+
String expected_enUS_full = Runtime.version().feature() >= 21
? "Tuesday, September 5, 2023, 9:04:05\u202FPM Eastern Daylight Time"
: "Tuesday, September 5, 2023 at 9:04:05 PM Eastern Daylight Time";
Assertions.assertEquals(expected_enUS_full, d.toLocaleString("en-US", JacksonUtil.newObjectNode()
.put("timeZone", "America/New_York") .put("timeZone", "America/New_York")
.put("dateStyle", "full") .put("dateStyle", "full")
.put("timeStyle", "full") .put("timeStyle", "full")
@ -309,15 +330,26 @@ class TbDateTest {
.put("dateStyle", "full") .put("dateStyle", "full")
.put("timeStyle", "full") .put("timeStyle", "full")
.toString())); .toString()));
Assertions.assertEquals("середа, 6 вересня 2023 р. о 04:04:05 за східноєвропейським літнім часом", d.toLocaleString("uk-UA", JacksonUtil.newObjectNode() // Java 21+ changed Ukrainian locale: "о" replaced with "," and NNBSP before "р." per CLDR 42+
String expected_ukUA_full_summer = Runtime.version().feature() >= 21
? "середа, 6 вересня 2023\u202Fр., 04:04:05 за східноєвропейським літнім часом"
: "середа, 6 вересня 2023 р. о 04:04:05 за східноєвропейським літнім часом";
Assertions.assertEquals(expected_ukUA_full_summer, d.toLocaleString("uk-UA", JacksonUtil.newObjectNode()
.put("timeZone", "Europe/Kiev") .put("timeZone", "Europe/Kiev")
.put("dateStyle", "full") .put("dateStyle", "full")
.put("timeStyle", "full") .put("timeStyle", "full")
.toString())); .toString()));
expected_ver = Runtime.version().feature() == 11 ? "الثلاثاء، 5 سبتمبر 2023 9:04:05 م التوقيت الصيفي الشرقي لأمريكا الشمالية" : // Java 11 has no connector, Java 17 uses "في", Java 21+ uses Arabic comma "،"
"الثلاثاء، 5 سبتمبر 2023 في 9:04:05 م التوقيت الصيفي الشرقي لأمريكا الشمالية"; String expected_ar_full;
Assertions.assertEquals(expected_ver, d.toLocaleString("ar-EG", JacksonUtil.newObjectNode() if (Runtime.version().feature() == 11) {
expected_ar_full = "الثلاثاء، 5 سبتمبر 2023 9:04:05 م التوقيت الصيفي الشرقي لأمريكا الشمالية";
} else if (Runtime.version().feature() >= 21) {
expected_ar_full = "الثلاثاء، 5 سبتمبر 2023\u060C 9:04:05 م التوقيت الصيفي الشرقي لأمريكا الشمالية";
} else {
expected_ar_full = "الثلاثاء، 5 سبتمبر 2023 في 9:04:05 م التوقيت الصيفي الشرقي لأمريكا الشمالية";
}
Assertions.assertEquals(expected_ar_full, d.toLocaleString("ar-EG", JacksonUtil.newObjectNode()
.put("timeZone", "America/New_York") .put("timeZone", "America/New_York")
.put("dateStyle", "full") .put("dateStyle", "full")
.put("timeStyle", "full") .put("timeStyle", "full")
@ -825,16 +857,44 @@ class TbDateTest {
@Test @Test
public void toStringAsJs() { public void toStringAsJs() {
TbDate d1 = new TbDate(1975, 12, 31, 23,15,30, 567,"-04:00"); TbDate d1 = new TbDate(1975, 12, 31, 23,15,30, 567,"-04:00");
Assertions.assertEquals("четвер, 1 січня 1976 р. о 06:15:30 за східноєвропейським стандартним часом", d1.toString("uk-UA", "Europe/Kyiv")); // Java 21+ changed Ukrainian locale: "о" (at) replaced with "," and NNBSP before "р." per CLDR 42+
Assertions.assertEquals("Thursday, January 1, 1976 at 6:15:30 AM Eastern European Standard Time", d1.toString("en-US", "Europe/Kyiv")); String expected_ukUA_full = Runtime.version().feature() >= 21
Assertions.assertEquals("1976 Jan 1, Thu 06:15:30 Eastern European Time", d1.toString("UTC", "Europe/Kyiv")); ? "четвер, 1 січня 1976\u202Fр., 06:15:30 за східноєвропейським стандартним часом"
Assertions.assertEquals("Wednesday, December 31, 1975 at 10:15:30 PM Eastern Standard Time", d1.toString("en-US", "America/New_York")); : "четвер, 1 січня 1976 р. о 06:15:30 за східноєвропейським стандартним часом";
Assertions.assertEquals("1975 Dec 31, Wed 22:15:30 Eastern Standard Time", d1.toString("GMT", "America/New_York")); Assertions.assertEquals(expected_ukUA_full, d1.toString("uk-UA", "Europe/Kyiv"));
Assertions.assertEquals("1975 Dec 31, Wed 22:15:30 Eastern Standard Time", d1.toString("UTC", "America/New_York")); // Java 21+ changed "at" to "," and uses NNBSP before AM/PM per CLDR 42+
String expected_enUS_Kyiv = Runtime.version().feature() >= 21
? "Thursday, January 1, 1976, 6:15:30\u202FAM Eastern European Standard Time"
: "Thursday, January 1, 1976 at 6:15:30 AM Eastern European Standard Time";
Assertions.assertEquals(expected_enUS_Kyiv, d1.toString("en-US", "Europe/Kyiv"));
// Java 21+ changed timezone display for UTC locale
String expected_UTC_Kyiv = Runtime.version().feature() >= 21
? "1976 Jan 1, Thu 06:15:30 Kyiv (+0)"
: "1976 Jan 1, Thu 06:15:30 Eastern European Time";
Assertions.assertEquals(expected_UTC_Kyiv, d1.toString("UTC", "Europe/Kyiv"));
// Java 21+ changed "at" to "," and uses NNBSP before AM/PM per CLDR 42+
String expected_enUS_NY = Runtime.version().feature() >= 21
? "Wednesday, December 31, 1975, 10:15:30\u202FPM Eastern Standard Time"
: "Wednesday, December 31, 1975 at 10:15:30 PM Eastern Standard Time";
Assertions.assertEquals(expected_enUS_NY, d1.toString("en-US", "America/New_York"));
// Java 21+ changed timezone display for GMT/UTC locales
String expected_GMT_NY = Runtime.version().feature() >= 21
? "1975 Dec 31, Wed 22:15:30 New York (+0)"
: "1975 Dec 31, Wed 22:15:30 Eastern Standard Time";
Assertions.assertEquals(expected_GMT_NY, d1.toString("GMT", "America/New_York"));
Assertions.assertEquals(expected_GMT_NY, d1.toString("UTC", "America/New_York"));
Assertions.assertEquals(d1.toUTCString("UTC"), d1.toUTCString()); Assertions.assertEquals(d1.toUTCString("UTC"), d1.toUTCString());
Assertions.assertEquals("четвер, 1 січня 1976 р., 03:15:30", d1.toUTCString("uk-UA")); // Java 21+ uses NNBSP before "р." per CLDR 42+
Assertions.assertEquals("Thursday, January 1, 1976, 3:15:30 AM", d1.toUTCString("en-US")); String expected_ukUA_utc = Runtime.version().feature() >= 21
? "четвер, 1 січня 1976\u202Fр., 03:15:30"
: "четвер, 1 січня 1976 р., 03:15:30";
Assertions.assertEquals(expected_ukUA_utc, d1.toUTCString("uk-UA"));
// Java 21+ uses NNBSP before AM/PM per CLDR 42+
String expected_enUS_utc = Runtime.version().feature() >= 21
? "Thursday, January 1, 1976, 3:15:30\u202FAM"
: "Thursday, January 1, 1976, 3:15:30 AM";
Assertions.assertEquals(expected_enUS_utc, d1.toUTCString("en-US"));
Assertions.assertEquals("1976-01-01T03:15:30.567Z", d1.toJSON()); Assertions.assertEquals("1976-01-01T03:15:30.567Z", d1.toJSON());
Assertions.assertEquals("1976-01-01T03:15:30.567Z", d1.toISOString()); Assertions.assertEquals("1976-01-01T03:15:30.567Z", d1.toISOString());
@ -842,22 +902,44 @@ class TbDateTest {
Assertions.assertEquals("1976-01-01 06:15:30", d1.toLocaleString("UTC", "Europe/Kyiv")); Assertions.assertEquals("1976-01-01 06:15:30", d1.toLocaleString("UTC", "Europe/Kyiv"));
Assertions.assertEquals("01.01.76, 06:15:30", d1.toLocaleString("uk-UA", "Europe/Kyiv")); Assertions.assertEquals("01.01.76, 06:15:30", d1.toLocaleString("uk-UA", "Europe/Kyiv"));
Assertions.assertEquals("1975-12-31 22:15:30", d1.toLocaleString("UTC", "America/New_York")); Assertions.assertEquals("1975-12-31 22:15:30", d1.toLocaleString("UTC", "America/New_York"));
Assertions.assertEquals("12/31/75, 10:15:30 PM", d1.toLocaleString("en-US", "America/New_York")); // Java 21+ uses NNBSP before AM/PM per CLDR 42+
String expected_enUS_locale_NY = Runtime.version().feature() >= 21
? "12/31/75, 10:15:30\u202FPM"
: "12/31/75, 10:15:30 PM";
Assertions.assertEquals(expected_enUS_locale_NY, d1.toLocaleString("en-US", "America/New_York"));
Assertions.assertEquals("1976 Jan 1, Thu", d1.toDateString("UTC", "Europe/Kyiv")); Assertions.assertEquals("1976 Jan 1, Thu", d1.toDateString("UTC", "Europe/Kyiv"));
Assertions.assertEquals("четвер, 1 січня 1976 р.", d1.toDateString("uk-UA", "Europe/Kyiv")); // Java 21+ uses NNBSP before "р." per CLDR 42+
String expected_ukUA_date = Runtime.version().feature() >= 21
? "четвер, 1 січня 1976\u202Fр."
: "четвер, 1 січня 1976 р.";
Assertions.assertEquals(expected_ukUA_date, d1.toDateString("uk-UA", "Europe/Kyiv"));
Assertions.assertEquals("1975 Dec 31, Wed", d1.toDateString("UTC", "America/New_York")); Assertions.assertEquals("1975 Dec 31, Wed", d1.toDateString("UTC", "America/New_York"));
Assertions.assertEquals("Wednesday, December 31, 1975", d1.toDateString("en-US", "America/New_York")); Assertions.assertEquals("Wednesday, December 31, 1975", d1.toDateString("en-US", "America/New_York"));
Assertions.assertEquals("06:15:30", d1.toLocaleTimeString("uk-UA", "Europe/Kyiv")); Assertions.assertEquals("06:15:30", d1.toLocaleTimeString("uk-UA", "Europe/Kyiv"));
Assertions.assertEquals("06:15:30", d1.toLocaleTimeString("UTC", "Europe/Kyiv")); Assertions.assertEquals("06:15:30", d1.toLocaleTimeString("UTC", "Europe/Kyiv"));
Assertions.assertEquals("10:15:30 PM", d1.toLocaleTimeString("en-US", "America/New_York")); // Java 21+ uses NNBSP before AM/PM per CLDR 42+
String expected_enUS_time = Runtime.version().feature() >= 21 ? "10:15:30\u202FPM" : "10:15:30 PM";
Assertions.assertEquals(expected_enUS_time, d1.toLocaleTimeString("en-US", "America/New_York"));
Assertions.assertEquals("22:15:30", d1.toLocaleTimeString("UTC", "America/New_York")); Assertions.assertEquals("22:15:30", d1.toLocaleTimeString("UTC", "America/New_York"));
Assertions.assertEquals("06:15:30 за східноєвропейським стандартним часом", d1.toTimeString("uk-UA", "Europe/Kyiv")); Assertions.assertEquals("06:15:30 за східноєвропейським стандартним часом", d1.toTimeString("uk-UA", "Europe/Kyiv"));
Assertions.assertEquals("06:15:30 Eastern European Time", d1.toTimeString("UTC", "Europe/Kyiv")); // Java 21+ changed timezone display for UTC locale
Assertions.assertEquals("10:15:30 PM Eastern Standard Time", d1.toTimeString("en-US", "America/New_York")); String expected_UTC_time_Kyiv = Runtime.version().feature() >= 21
Assertions.assertEquals("22:15:30 Eastern Standard Time", d1.toTimeString("UTC", "America/New_York")); ? "06:15:30 Kyiv (+0)"
: "06:15:30 Eastern European Time";
Assertions.assertEquals(expected_UTC_time_Kyiv, d1.toTimeString("UTC", "Europe/Kyiv"));
// Java 21+ uses NNBSP before AM/PM per CLDR 42+
String expected_enUS_timeStr = Runtime.version().feature() >= 21
? "10:15:30\u202FPM Eastern Standard Time"
: "10:15:30 PM Eastern Standard Time";
Assertions.assertEquals(expected_enUS_timeStr, d1.toTimeString("en-US", "America/New_York"));
// Java 21+ changed timezone display for UTC locale
String expected_UTC_time_NY = Runtime.version().feature() >= 21
? "22:15:30 New York (+0)"
: "22:15:30 Eastern Standard Time";
Assertions.assertEquals(expected_UTC_time_NY, d1.toTimeString("UTC", "America/New_York"));
} }
@Test @Test

4
common/util/src/main/java/org/thingsboard/common/util/ThingsBoardThreadFactory.java

@ -33,9 +33,7 @@ public class ThingsBoardThreadFactory implements ThreadFactory {
} }
private ThingsBoardThreadFactory(String name) { private ThingsBoardThreadFactory(String name) {
SecurityManager s = System.getSecurityManager(); group = Thread.currentThread().getThreadGroup();
group = (s != null) ? s.getThreadGroup() :
Thread.currentThread().getThreadGroup();
namePrefix = name + "-" + namePrefix = name + "-" +
poolNumber.getAndIncrement() + poolNumber.getAndIncrement() +
"-thread-"; "-thread-";

36
dao/src/main/java/org/thingsboard/server/dao/sql/alarm/AlarmRepository.java

@ -98,10 +98,8 @@ public interface AlarmRepository extends JpaRepository<AlarmEntity, UUID> {
"AND ea.entityType = :affectedEntityType " + "AND ea.entityType = :affectedEntityType " +
"AND (:startTime IS NULL OR (a.createdTime >= :startTime AND ea.createdTime >= :startTime)) " + "AND (:startTime IS NULL OR (a.createdTime >= :startTime AND ea.createdTime >= :startTime)) " +
"AND (:endTime IS NULL OR (a.createdTime <= :endTime AND ea.createdTime <= :endTime)) " + "AND (:endTime IS NULL OR (a.createdTime <= :endTime AND ea.createdTime <= :endTime)) " +
"AND ((:#{#alarmTypes == null} = true) OR a.type IN (:alarmTypes)) " + //HHH-15968 "AND ((:alarmTypes) IS NULL OR a.type IN (:alarmTypes)) " +
"AND ((:#{#alarmSeverities == null} = true) OR a.severity IN (:alarmSeverities)) " + //HHH-15968 "AND ((:alarmSeverities) IS NULL OR a.severity IN (:alarmSeverities)) " +
// "AND ((:alarmTypes) IS NULL OR a.type IN (:alarmTypes)) " +
// "AND ((:alarmSeverities) IS NULL OR a.severity IN (:alarmSeverities)) " +
"AND ((:clearFilterEnabled) = FALSE OR a.cleared = :clearFilter) " + "AND ((:clearFilterEnabled) = FALSE OR a.cleared = :clearFilter) " +
"AND ((:ackFilterEnabled) = FALSE OR a.acknowledged = :ackFilter) " + "AND ((:ackFilterEnabled) = FALSE OR a.acknowledged = :ackFilter) " +
"AND (:assigneeId IS NULL OR a.assigneeId = :assigneeId) " + "AND (:assigneeId IS NULL OR a.assigneeId = :assigneeId) " +
@ -119,10 +117,8 @@ public interface AlarmRepository extends JpaRepository<AlarmEntity, UUID> {
"AND ea.entityType = :affectedEntityType " + "AND ea.entityType = :affectedEntityType " +
"AND (:startTime IS NULL OR (a.createdTime >= :startTime AND ea.createdTime >= :startTime)) " + "AND (:startTime IS NULL OR (a.createdTime >= :startTime AND ea.createdTime >= :startTime)) " +
"AND (:endTime IS NULL OR (a.createdTime <= :endTime AND ea.createdTime <= :endTime)) " + "AND (:endTime IS NULL OR (a.createdTime <= :endTime AND ea.createdTime <= :endTime)) " +
"AND ((:#{#alarmTypes == null} = true) OR a.type IN (:alarmTypes)) " + //HHH-15968 "AND ((:alarmTypes) IS NULL OR a.type IN (:alarmTypes)) " +
"AND ((:#{#alarmSeverities == null} = true) OR a.severity IN (:alarmSeverities)) " + //HHH-15968 "AND ((:alarmSeverities) IS NULL OR a.severity IN (:alarmSeverities)) " +
// "AND ((:alarmTypes) IS NULL OR a.type IN (:alarmTypes)) " +
// "AND ((:alarmSeverities) IS NULL OR a.severity IN (:alarmSeverities)) " +
"AND ((:clearFilterEnabled) = FALSE OR a.cleared = :clearFilter) " + "AND ((:clearFilterEnabled) = FALSE OR a.cleared = :clearFilter) " +
"AND ((:ackFilterEnabled) = FALSE OR a.acknowledged = :ackFilter) " + "AND ((:ackFilterEnabled) = FALSE OR a.acknowledged = :ackFilter) " +
"AND (:assigneeId IS NULL OR a.assigneeId = :assigneeId) " + "AND (:assigneeId IS NULL OR a.assigneeId = :assigneeId) " +
@ -183,10 +179,8 @@ public interface AlarmRepository extends JpaRepository<AlarmEntity, UUID> {
"WHERE a.tenantId = :tenantId " + "WHERE a.tenantId = :tenantId " +
"AND (:startTime IS NULL OR a.createdTime >= :startTime) " + "AND (:startTime IS NULL OR a.createdTime >= :startTime) " +
"AND (:endTime IS NULL OR a.createdTime <= :endTime) " + "AND (:endTime IS NULL OR a.createdTime <= :endTime) " +
"AND ((:#{#alarmTypes == null} = true) OR a.type IN (:alarmTypes)) " + //HHH-15968 "AND ((:alarmTypes) IS NULL OR a.type IN (:alarmTypes)) " +
"AND ((:#{#alarmSeverities == null} = true) OR a.severity IN (:alarmSeverities)) " + //HHH-15968 "AND ((:alarmSeverities) IS NULL OR a.severity IN (:alarmSeverities)) " +
// "AND ((:alarmTypes) IS NULL OR a.type IN (:alarmTypes)) " +
// "AND ((:alarmSeverities) IS NULL OR a.severity IN (:alarmSeverities)) " +
"AND ((:clearFilterEnabled) = FALSE OR a.cleared = :clearFilter) " + "AND ((:clearFilterEnabled) = FALSE OR a.cleared = :clearFilter) " +
"AND ((:ackFilterEnabled) = FALSE OR a.acknowledged = :ackFilter) " + "AND ((:ackFilterEnabled) = FALSE OR a.acknowledged = :ackFilter) " +
"AND (:assigneeId IS NULL OR a.assigneeId = :assigneeId) " + "AND (:assigneeId IS NULL OR a.assigneeId = :assigneeId) " +
@ -199,10 +193,8 @@ public interface AlarmRepository extends JpaRepository<AlarmEntity, UUID> {
"WHERE a.tenantId = :tenantId " + "WHERE a.tenantId = :tenantId " +
"AND (:startTime IS NULL OR a.createdTime >= :startTime) " + "AND (:startTime IS NULL OR a.createdTime >= :startTime) " +
"AND (:endTime IS NULL OR a.createdTime <= :endTime) " + "AND (:endTime IS NULL OR a.createdTime <= :endTime) " +
"AND ((:#{#alarmTypes == null} = true) OR a.type IN (:alarmTypes)) " + //HHH-15968 "AND ((:alarmTypes) IS NULL OR a.type IN (:alarmTypes)) " +
"AND ((:#{#alarmSeverities == null} = true) OR a.severity IN (:alarmSeverities)) " + //HHH-15968 "AND ((:alarmSeverities) IS NULL OR a.severity IN (:alarmSeverities)) " +
// "AND ((:alarmTypes) IS NULL OR a.type IN (:alarmTypes)) " +
// "AND ((:alarmSeverities) IS NULL OR a.severity IN (:alarmSeverities)) " +
"AND ((:clearFilterEnabled) = FALSE OR a.cleared = :clearFilter) " + "AND ((:clearFilterEnabled) = FALSE OR a.cleared = :clearFilter) " +
"AND ((:ackFilterEnabled) = FALSE OR a.acknowledged = :ackFilter) " + "AND ((:ackFilterEnabled) = FALSE OR a.acknowledged = :ackFilter) " +
"AND (:assigneeId IS NULL OR a.assigneeId = :assigneeId) " + "AND (:assigneeId IS NULL OR a.assigneeId = :assigneeId) " +
@ -263,10 +255,8 @@ public interface AlarmRepository extends JpaRepository<AlarmEntity, UUID> {
"WHERE a.tenantId = :tenantId AND a.customerId = :customerId " + "WHERE a.tenantId = :tenantId AND a.customerId = :customerId " +
"AND (:startTime IS NULL OR a.createdTime >= :startTime) " + "AND (:startTime IS NULL OR a.createdTime >= :startTime) " +
"AND (:endTime IS NULL OR a.createdTime <= :endTime) " + "AND (:endTime IS NULL OR a.createdTime <= :endTime) " +
"AND ((:#{#alarmTypes == null} = true) OR a.type IN (:alarmTypes)) " + //HHH-15968 "AND ((:alarmTypes) IS NULL OR a.type IN (:alarmTypes)) " +
"AND ((:#{#alarmSeverities == null} = true) OR a.severity IN (:alarmSeverities)) " + //HHH-15968 "AND ((:alarmSeverities) IS NULL OR a.severity IN (:alarmSeverities)) " +
// "AND ((:alarmTypes) IS NULL OR a.type IN (:alarmTypes)) " +
// "AND ((:alarmSeverities) IS NULL OR a.severity IN (:alarmSeverities)) " +
"AND ((:clearFilterEnabled) = FALSE OR a.cleared = :clearFilter) " + "AND ((:clearFilterEnabled) = FALSE OR a.cleared = :clearFilter) " +
"AND ((:ackFilterEnabled) = FALSE OR a.acknowledged = :ackFilter) " + "AND ((:ackFilterEnabled) = FALSE OR a.acknowledged = :ackFilter) " +
"AND (:assigneeId IS NULL OR a.assigneeId = :assigneeId) " + "AND (:assigneeId IS NULL OR a.assigneeId = :assigneeId) " +
@ -280,10 +270,8 @@ public interface AlarmRepository extends JpaRepository<AlarmEntity, UUID> {
"WHERE a.tenantId = :tenantId AND a.customerId = :customerId " + "WHERE a.tenantId = :tenantId AND a.customerId = :customerId " +
"AND (:startTime IS NULL OR a.createdTime >= :startTime) " + "AND (:startTime IS NULL OR a.createdTime >= :startTime) " +
"AND (:endTime IS NULL OR a.createdTime <= :endTime) " + "AND (:endTime IS NULL OR a.createdTime <= :endTime) " +
"AND ((:#{#alarmTypes == null} = true) OR a.type IN (:alarmTypes)) " + //HHH-15968 "AND ((:alarmTypes) IS NULL OR a.type IN (:alarmTypes)) " +
"AND ((:#{#alarmSeverities == null} = true) OR a.severity IN (:alarmSeverities)) " + //HHH-15968 "AND ((:alarmSeverities) IS NULL OR a.severity IN (:alarmSeverities)) " +
// "AND ((:alarmTypes) IS NULL OR a.type IN (:alarmTypes)) " +
// "AND ((:alarmSeverities) IS NULL OR a.severity IN (:alarmSeverities)) " +
"AND ((:clearFilterEnabled) = FALSE OR a.cleared = :clearFilter) " + "AND ((:clearFilterEnabled) = FALSE OR a.cleared = :clearFilter) " +
"AND ((:ackFilterEnabled) = FALSE OR a.acknowledged = :ackFilter) " + "AND ((:ackFilterEnabled) = FALSE OR a.acknowledged = :ackFilter) " +
"AND (:assigneeId IS NULL OR a.assigneeId = :assigneeId) " + "AND (:assigneeId IS NULL OR a.assigneeId = :assigneeId) " +

12
dao/src/main/java/org/thingsboard/server/dao/sql/audit/AuditLogRepository.java

@ -33,8 +33,7 @@ public interface AuditLogRepository extends JpaRepository<AuditLogEntity, UUID>
"a.tenantId = :tenantId " + "a.tenantId = :tenantId " +
"AND (:startTime IS NULL OR a.createdTime >= :startTime) " + "AND (:startTime IS NULL OR a.createdTime >= :startTime) " +
"AND (:endTime IS NULL OR a.createdTime <= :endTime) " + "AND (:endTime IS NULL OR a.createdTime <= :endTime) " +
"AND ((:#{#actionTypes == null} = true) OR a.actionType IN (:actionTypes)) " + //HHH-15968 "AND ((:actionTypes) IS NULL OR a.actionType IN (:actionTypes)) " +
// "AND ((:actionTypes) IS NULL OR a.actionType in (:actionTypes)) " +
"AND (:textSearch IS NULL OR ilike(a.entityType, CONCAT('%', :textSearch, '%')) = true " + "AND (:textSearch IS NULL OR ilike(a.entityType, CONCAT('%', :textSearch, '%')) = true " +
"OR ilike(a.entityName, CONCAT('%', :textSearch, '%')) = true " + "OR ilike(a.entityName, CONCAT('%', :textSearch, '%')) = true " +
"OR ilike(a.userName, CONCAT('%', :textSearch, '%')) = true " + "OR ilike(a.userName, CONCAT('%', :textSearch, '%')) = true " +
@ -54,8 +53,7 @@ public interface AuditLogRepository extends JpaRepository<AuditLogEntity, UUID>
"AND a.entityType = :entityType AND a.entityId = :entityId " + "AND a.entityType = :entityType AND a.entityId = :entityId " +
"AND (:startTime IS NULL OR a.createdTime >= :startTime) " + "AND (:startTime IS NULL OR a.createdTime >= :startTime) " +
"AND (:endTime IS NULL OR a.createdTime <= :endTime) " + "AND (:endTime IS NULL OR a.createdTime <= :endTime) " +
"AND ((:#{#actionTypes == null} = true) OR a.actionType IN (:actionTypes)) " + //HHH-15968 "AND ((:actionTypes) IS NULL OR a.actionType IN (:actionTypes)) " +
// "AND ((:actionTypes) IS NULL OR a.actionType in (:actionTypes)) " +
"AND (:textSearch IS NULL OR ilike(a.entityName, CONCAT('%', :textSearch, '%')) = true " + "AND (:textSearch IS NULL OR ilike(a.entityName, CONCAT('%', :textSearch, '%')) = true " +
"OR ilike(a.userName, CONCAT('%', :textSearch, '%')) = true " + "OR ilike(a.userName, CONCAT('%', :textSearch, '%')) = true " +
"OR ilike(a.actionType, CONCAT('%', :textSearch, '%')) = true " + "OR ilike(a.actionType, CONCAT('%', :textSearch, '%')) = true " +
@ -75,8 +73,7 @@ public interface AuditLogRepository extends JpaRepository<AuditLogEntity, UUID>
"AND a.customerId = :customerId " + "AND a.customerId = :customerId " +
"AND (:startTime IS NULL OR a.createdTime >= :startTime) " + "AND (:startTime IS NULL OR a.createdTime >= :startTime) " +
"AND (:endTime IS NULL OR a.createdTime <= :endTime) " + "AND (:endTime IS NULL OR a.createdTime <= :endTime) " +
"AND ((:#{#actionTypes == null} = true) OR a.actionType IN (:actionTypes)) " + //HHH-15968 "AND ((:actionTypes) IS NULL OR a.actionType IN (:actionTypes)) " +
// "AND ((:actionTypes) IS NULL OR a.actionType in (:actionTypes)) " +
"AND (:textSearch IS NULL OR ilike(a.entityType, CONCAT('%', :textSearch, '%')) = true " + "AND (:textSearch IS NULL OR ilike(a.entityType, CONCAT('%', :textSearch, '%')) = true " +
"OR ilike(a.entityName, CONCAT('%', :textSearch, '%')) = true " + "OR ilike(a.entityName, CONCAT('%', :textSearch, '%')) = true " +
"OR ilike(a.userName, CONCAT('%', :textSearch, '%')) = true " + "OR ilike(a.userName, CONCAT('%', :textSearch, '%')) = true " +
@ -96,8 +93,7 @@ public interface AuditLogRepository extends JpaRepository<AuditLogEntity, UUID>
"AND a.userId = :userId " + "AND a.userId = :userId " +
"AND (:startTime IS NULL OR a.createdTime >= :startTime) " + "AND (:startTime IS NULL OR a.createdTime >= :startTime) " +
"AND (:endTime IS NULL OR a.createdTime <= :endTime) " + "AND (:endTime IS NULL OR a.createdTime <= :endTime) " +
"AND ((:#{#actionTypes == null} = true) OR a.actionType IN (:actionTypes)) " + //HHH-15968 "AND ((:actionTypes) IS NULL OR a.actionType IN (:actionTypes)) " +
// "AND ((:actionTypes) IS NULL OR a.actionType in (:actionTypes)) " +
"AND (:textSearch IS NULL OR ilike(a.entityType, CONCAT('%', :textSearch, '%')) = true " + "AND (:textSearch IS NULL OR ilike(a.entityType, CONCAT('%', :textSearch, '%')) = true " +
"OR ilike(a.entityName, CONCAT('%', :textSearch, '%')) = true " + "OR ilike(a.entityName, CONCAT('%', :textSearch, '%')) = true " +
"OR ilike(a.actionType, CONCAT('%', :textSearch, '%')) = true " + "OR ilike(a.actionType, CONCAT('%', :textSearch, '%')) = true " +

13
msa/tb/docker-cassandra/Dockerfile

@ -14,7 +14,7 @@
# limitations under the License. # limitations under the License.
# #
FROM thingsboard/openjdk17:bookworm-slim FROM thingsboard/openjdk25:trixie-slim
ENV PG_MAJOR=16 ENV PG_MAJOR=16
@ -44,15 +44,14 @@ COPY logback.xml ${pkg.name}.conf start-db.sh stop-db.sh start-tb.sh upgrade-tb.
RUN apt-get update \ RUN apt-get update \
&& apt-get install -y --no-install-recommends wget nmap procps gnupg2 \ && apt-get install -y --no-install-recommends wget nmap procps gnupg2 \
&& echo "deb http://apt.postgresql.org/pub/repos/apt/ $(. /etc/os-release && echo -n $VERSION_CODENAME)-pgdg main" | tee --append /etc/apt/sources.list.d/pgdg.list > /dev/null \ && mkdir -p /etc/apt/keyrings \
&& wget -q https://www.postgresql.org/media/keys/ACCC4CF8.asc -O- | apt-key add - \ && wget -q https://www.postgresql.org/media/keys/ACCC4CF8.asc -O- | gpg --dearmor -o /etc/apt/keyrings/postgresql.gpg \
&& echo "deb https://debian.cassandra.apache.org 40x main" | tee -a /etc/apt/sources.list.d/cassandra.sources.list > /dev/null \ && echo "deb [signed-by=/etc/apt/keyrings/postgresql.gpg] http://apt.postgresql.org/pub/repos/apt/ $(. /etc/os-release && echo -n $VERSION_CODENAME)-pgdg main" | tee /etc/apt/sources.list.d/pgdg.list > /dev/null \
&& wget -q https://downloads.apache.org/cassandra/KEYS -O- | apt-key add - \ && wget -q https://downloads.apache.org/cassandra/KEYS -O- | gpg --dearmor -o /etc/apt/keyrings/cassandra.gpg \
&& echo "deb [signed-by=/etc/apt/keyrings/cassandra.gpg] https://debian.cassandra.apache.org 40x main" | tee /etc/apt/sources.list.d/cassandra.sources.list > /dev/null \
&& apt-get update \ && apt-get update \
&& apt-get install -y --no-install-recommends cassandra cassandra-tools postgresql-${PG_MAJOR} \ && apt-get install -y --no-install-recommends cassandra cassandra-tools postgresql-${PG_MAJOR} \
&& rm -rf /var/lib/apt/lists/* \ && rm -rf /var/lib/apt/lists/* \
&& update-rc.d cassandra disable \
&& update-rc.d postgresql disable \
&& apt-get purge -y --auto-remove \ && apt-get purge -y --auto-remove \
&& sed -i.old '/ulimit/d' /etc/init.d/cassandra \ && sed -i.old '/ulimit/d' /etc/init.d/cassandra \
&& chmod a+x /tmp/*.sh \ && chmod a+x /tmp/*.sh \

8
msa/tb/docker-postgres/Dockerfile

@ -14,7 +14,7 @@
# limitations under the License. # limitations under the License.
# #
FROM thingsboard/openjdk17:bookworm-slim FROM thingsboard/openjdk25:trixie-slim
ENV PG_MAJOR 12 ENV PG_MAJOR 12
@ -36,12 +36,12 @@ COPY logback.xml ${pkg.name}.conf start-db.sh stop-db.sh start-tb.sh upgrade-tb.
RUN apt-get update \ RUN apt-get update \
&& apt-get install -y --no-install-recommends wget gnupg2 \ && apt-get install -y --no-install-recommends wget gnupg2 \
&& echo "deb http://apt.postgresql.org/pub/repos/apt/ $(. /etc/os-release && echo -n $VERSION_CODENAME)-pgdg main" | tee --append /etc/apt/sources.list.d/pgdg.list > /dev/null \ && mkdir -p /etc/apt/keyrings \
&& wget -q https://www.postgresql.org/media/keys/ACCC4CF8.asc -O- | apt-key add - \ && wget -q https://www.postgresql.org/media/keys/ACCC4CF8.asc -O- | gpg --dearmor -o /etc/apt/keyrings/postgresql.gpg \
&& echo "deb [signed-by=/etc/apt/keyrings/postgresql.gpg] http://apt.postgresql.org/pub/repos/apt/ $(. /etc/os-release && echo -n $VERSION_CODENAME)-pgdg main" | tee /etc/apt/sources.list.d/pgdg.list > /dev/null \
&& apt-get update \ && apt-get update \
&& apt-get install -y --no-install-recommends postgresql-${PG_MAJOR} \ && apt-get install -y --no-install-recommends postgresql-${PG_MAJOR} \
&& rm -rf /var/lib/apt/lists/* \ && rm -rf /var/lib/apt/lists/* \
&& update-rc.d postgresql disable \
&& apt-get purge -y --auto-remove \ && apt-get purge -y --auto-remove \
&& chmod a+x /tmp/*.sh \ && chmod a+x /tmp/*.sh \
&& mv /tmp/start-tb.sh /usr/bin \ && mv /tmp/start-tb.sh /usr/bin \

56
packaging/java/build.gradle

@ -16,12 +16,14 @@
import org.apache.tools.ant.filters.ReplaceTokens import org.apache.tools.ant.filters.ReplaceTokens
plugins { plugins {
id "nebula.ospackage" version "8.6.3" id "com.netflix.nebula.ospackage" version "12.1.1"
} }
buildDir = projectBuildDir buildDir = projectBuildDir
version = projectVersion version = projectVersion
distsDirName = "./" base {
distsDirectory = layout.buildDirectory.dir("./")
}
// OS Package plugin configuration // OS Package plugin configuration
ospackage { ospackage {
@ -33,8 +35,8 @@ ospackage {
into pkgInstallFolder into pkgInstallFolder
user pkgUser user = pkgUser
permissionGroup pkgUser permissionGroup = pkgUser
// Copy the actual .jar file // Copy the actual .jar file
from(mainJar) { from(mainJar) {
@ -42,19 +44,25 @@ ospackage {
rename { String fileName -> rename { String fileName ->
"${pkgName}.jar" "${pkgName}.jar"
} }
fileMode 0500 filePermissions {
unix('r-x------') // 0500
}
into "bin" into "bin"
} }
if("${pkgCopyInstallScripts}".equalsIgnoreCase("true")) { if("${pkgCopyInstallScripts}".equalsIgnoreCase("true")) {
// Copy the install files // Copy the install files
from("${buildDir}/bin/install/install.sh") { from("${buildDir}/bin/install/install.sh") {
fileMode 0775 filePermissions {
unix('rwxrwxr-x') // 0775
}
into "bin/install" into "bin/install"
} }
from("${buildDir}/bin/install/upgrade.sh") { from("${buildDir}/bin/install/upgrade.sh") {
fileMode 0775 filePermissions {
unix('rwxrwxr-x') // 0775
}
into "bin/install" into "bin/install"
} }
@ -67,14 +75,18 @@ ospackage {
from("${buildDir}/conf") { from("${buildDir}/conf") {
exclude "${pkgName}.conf" exclude "${pkgName}.conf"
fileType CONFIG | NOREPLACE fileType CONFIG | NOREPLACE
fileMode 0754 filePermissions {
unix('rwxr-xr--') // 0754
}
into "conf" into "conf"
} }
// Copy the data files // Copy the data files
from("${buildDir}/data") { from("${buildDir}/data") {
fileType CONFIG | NOREPLACE fileType CONFIG | NOREPLACE
fileMode 0754 filePermissions {
unix('rwxr-xr--') // 0754
}
into "data" into "data"
} }
@ -92,7 +104,7 @@ buildRpm {
archiveVersion = projectVersion.replace('-', '') archiveVersion = projectVersion.replace('-', '')
archiveFileName = "${pkgName}.rpm" archiveFileName = "${pkgName}.rpm"
// Support Java 17 (existing), plus Java 21 and Java 25 for RPM-based distros // Support Java 25 (current), plus Java 21 and Java 17 (backward compatibility) for RPM-based distros
// Keep using RPM boolean expression syntax since .or() chaining is for DEB only // Keep using RPM boolean expression syntax since .or() chaining is for DEB only
requires("(java-17 or java-17-headless or jre-17 or jre-17-headless or " + requires("(java-17 or java-17-headless or jre-17 or jre-17-headless or " +
"java-21 or java-21-headless or jre-21 or jre-21-headless or " + "java-21 or java-21-headless or jre-21 or jre-21-headless or " +
@ -102,7 +114,9 @@ buildRpm {
include "${pkgName}.conf" include "${pkgName}.conf"
filter(ReplaceTokens, tokens: ['pkg.platform': 'rpm']) filter(ReplaceTokens, tokens: ['pkg.platform': 'rpm'])
fileType CONFIG | NOREPLACE fileType CONFIG | NOREPLACE
fileMode 0754 filePermissions {
unix('rwxr-xr--') // 0754
}
into "${pkgInstallFolder}/conf" into "${pkgInstallFolder}/conf"
} }
@ -111,13 +125,15 @@ buildRpm {
preUninstall file("${buildDir}/control/rpm/prerm") preUninstall file("${buildDir}/control/rpm/prerm")
postUninstall file("${buildDir}/control/rpm/postrm") postUninstall file("${buildDir}/control/rpm/postrm")
user pkgUser user = pkgUser
permissionGroup pkgUser permissionGroup = pkgUser
// Copy the system unit files // Copy the system unit files
from("${buildDir}/control/template.service") { from("${buildDir}/control/template.service") {
addParentDirs = false addParentDirs = false
fileMode 0644 filePermissions {
unix('rw-r--r--') // 0644
}
into "/usr/lib/systemd/system" into "/usr/lib/systemd/system"
rename { String filename -> rename { String filename ->
"${pkgName}.service" "${pkgName}.service"
@ -143,7 +159,9 @@ buildDeb {
include "${pkgName}.conf" include "${pkgName}.conf"
filter(ReplaceTokens, tokens: ['pkg.platform': 'deb']) filter(ReplaceTokens, tokens: ['pkg.platform': 'deb'])
fileType CONFIG | NOREPLACE fileType CONFIG | NOREPLACE
fileMode 0754 filePermissions {
unix('rwxr-xr--') // 0754
}
into "${pkgInstallFolder}/conf" into "${pkgInstallFolder}/conf"
} }
@ -157,13 +175,15 @@ buildDeb {
preUninstall file("${buildDir}/control/deb/prerm") preUninstall file("${buildDir}/control/deb/prerm")
postUninstall file("${buildDir}/control/deb/postrm") postUninstall file("${buildDir}/control/deb/postrm")
user pkgUser user = pkgUser
permissionGroup pkgUser permissionGroup = pkgUser
// Copy the system unit files // Copy the system unit files
from("${buildDir}/control/template.service") { from("${buildDir}/control/template.service") {
addParentDirs = false addParentDirs = false
fileMode 0644 filePermissions {
unix('rw-r--r--') // 0644
}
into "/lib/systemd/system" into "/lib/systemd/system"
rename { String filename -> rename { String filename ->
"${pkgName}.service" "${pkgName}.service"

8
packaging/java/scripts/windows/install.bat

@ -7,11 +7,11 @@ setlocal ENABLEEXTENSIONS
for /f tokens^=2-5^ delims^=.-_^" %%j in ('java -fullversion 2^>^&1') do set "jver=%%j%%k" for /f tokens^=2-5^ delims^=.-_^" %%j in ('java -fullversion 2^>^&1') do set "jver=%%j%%k"
@ECHO CurrentVersion %jver% @ECHO CurrentVersion %jver%
if %jver% NEQ 170 GOTO JAVA_NOT_INSTALLED if %jver% NEQ 250 GOTO JAVA_NOT_INSTALLED
:JAVA_INSTALLED :JAVA_INSTALLED
@ECHO Java 17 found! @ECHO Java 25 found!
@ECHO Installing thingsboard ... @ECHO Installing thingsboard ...
SET loadDemo=false SET loadDemo=false
@ -50,8 +50,8 @@ POPD
GOTO END GOTO END
:JAVA_NOT_INSTALLED :JAVA_NOT_INSTALLED
@ECHO Java 17 is not installed. Only Java 17 is supported @ECHO Java 25 is not installed. Only Java 25 is supported
@ECHO Please go to https://adoptopenjdk.net/index.html and install Java 17. Then retry installation. @ECHO Please go to https://adoptopenjdk.net/index.html and install Java 25. Then retry installation.
PAUSE PAUSE
GOTO END GOTO END

39
packaging/js/build.gradle

@ -13,15 +13,16 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
import org.apache.tools.ant.filters.ReplaceTokens
plugins { plugins {
id "nebula.ospackage" version "8.6.3" id "com.netflix.nebula.ospackage" version "12.1.1"
} }
buildDir = projectBuildDir buildDir = projectBuildDir
version = projectVersion version = projectVersion
distsDirName = "./" base {
distsDirectory = layout.buildDirectory.dir("./")
}
// OS Package plugin configuration // OS Package plugin configuration
ospackage { ospackage {
@ -33,18 +34,22 @@ ospackage {
into pkgInstallFolder into pkgInstallFolder
user pkgUser user = pkgUser
permissionGroup pkgUser permissionGroup = pkgUser
// Copy the executable file // Copy the executable file
from("${buildDir}/package/linux/bin/${pkgName}") { from("${buildDir}/package/linux/bin/${pkgName}") {
fileMode 0500 filePermissions {
unix('r-x------') // 0500
}
into "bin" into "bin"
} }
// Copy the init file // Copy the init file
from("${buildDir}/package/linux/init/template") { from("${buildDir}/package/linux/init/template") {
fileMode 0500 filePermissions {
unix('r-x------') // 0500
}
into "init" into "init"
rename { String filename -> rename { String filename ->
"${pkgName}" "${pkgName}"
@ -54,7 +59,9 @@ ospackage {
// Copy the config files // Copy the config files
from("${buildDir}/package/linux/conf") { from("${buildDir}/package/linux/conf") {
fileType CONFIG | NOREPLACE fileType CONFIG | NOREPLACE
fileMode 0754 filePermissions {
unix('rwxr-xr--') // 0754
}
into "conf" into "conf"
} }
@ -78,13 +85,15 @@ buildRpm {
preUninstall file("${buildDir}/control/rpm/prerm") preUninstall file("${buildDir}/control/rpm/prerm")
postUninstall file("${buildDir}/control/rpm/postrm") postUninstall file("${buildDir}/control/rpm/postrm")
user pkgUser user = pkgUser
permissionGroup pkgUser permissionGroup = pkgUser
// Copy the system unit files // Copy the system unit files
from("${buildDir}/control/template.service") { from("${buildDir}/control/template.service") {
addParentDirs = false addParentDirs = false
fileMode 0644 filePermissions {
unix('rw-r--r--') // 0644
}
into "/usr/lib/systemd/system" into "/usr/lib/systemd/system"
rename { String filename -> rename { String filename ->
"${pkgName}.service" "${pkgName}.service"
@ -111,13 +120,15 @@ buildDeb {
preUninstall file("${buildDir}/control/deb/prerm") preUninstall file("${buildDir}/control/deb/prerm")
postUninstall file("${buildDir}/control/deb/postrm") postUninstall file("${buildDir}/control/deb/postrm")
user pkgUser user = pkgUser
permissionGroup pkgUser permissionGroup = pkgUser
// Copy the system unit files // Copy the system unit files
from("${buildDir}/control/template.service") { from("${buildDir}/control/template.service") {
addParentDirs = false addParentDirs = false
fileMode 0644 filePermissions {
unix('rw-r--r--') // 0644
}
into "/lib/systemd/system" into "/lib/systemd/system"
rename { String filename -> rename { String filename ->
"${pkgName}.service" "${pkgName}.service"

28
pom.xml

@ -28,8 +28,8 @@
<inceptionYear>2016</inceptionYear> <inceptionYear>2016</inceptionYear>
<properties> <properties>
<maven.compiler.source>17</maven.compiler.source> <maven.compiler.source>25</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target> <maven.compiler.target>25</maven.compiler.target>
<main.dir>${basedir}</main.dir> <main.dir>${basedir}</main.dir>
<pkg.disabled>true</pkg.disabled> <pkg.disabled>true</pkg.disabled>
<pkg.process-resources.phase>none</pkg.process-resources.phase> <pkg.process-resources.phase>none</pkg.process-resources.phase>
@ -65,7 +65,7 @@
<protobuf.version>3.25.5</protobuf.version> <!-- A Major v4 does not support by the pubsub yet--> <protobuf.version>3.25.5</protobuf.version> <!-- A Major v4 does not support by the pubsub yet-->
<grpc.version>1.76.0</grpc.version> <grpc.version>1.76.0</grpc.version>
<tbel.version>1.2.8</tbel.version> <tbel.version>1.2.8</tbel.version>
<lombok.version>1.18.38</lombok.version> <lombok.version>1.18.40</lombok.version>
<paho.client.version>1.2.5</paho.client.version> <paho.client.version>1.2.5</paho.client.version>
<paho.mqttv5.client.version>1.2.5</paho.mqttv5.client.version> <paho.mqttv5.client.version>1.2.5</paho.mqttv5.client.version>
<os-maven-plugin.version>1.7.1</os-maven-plugin.version> <os-maven-plugin.version>1.7.1</os-maven-plugin.version>
@ -111,6 +111,7 @@
<jakarta.el.version>4.0.2</jakarta.el.version> <jakarta.el.version>4.0.2</jakarta.el.version>
<antisamy.version>1.7.5</antisamy.version> <antisamy.version>1.7.5</antisamy.version>
<snmp4j.version>3.8.0</snmp4j.version> <snmp4j.version>3.8.0</snmp4j.version>
<bytebuddy.version>1.18.4</bytebuddy.version>
<langchain4j.version>1.8.0-TB</langchain4j.version> <langchain4j.version>1.8.0-TB</langchain4j.version>
<error_prone_annotations.version>2.38.0</error_prone_annotations.version> <error_prone_annotations.version>2.38.0</error_prone_annotations.version>
<animal-sniffer-annotations.version>1.24</animal-sniffer-annotations.version> <animal-sniffer-annotations.version>1.24</animal-sniffer-annotations.version>
@ -605,7 +606,7 @@
<artifactId>maven-compiler-plugin</artifactId> <artifactId>maven-compiler-plugin</artifactId>
<version>3.11.0</version> <version>3.11.0</version>
<configuration> <configuration>
<release>17</release> <release>25</release>
<compilerArgs> <compilerArgs>
<arg>-Xlint:deprecation</arg> <arg>-Xlint:deprecation</arg>
<arg>-Xlint:removal</arg> <arg>-Xlint:removal</arg>
@ -649,7 +650,7 @@
<plugin> <plugin>
<groupId>org.thingsboard</groupId> <groupId>org.thingsboard</groupId>
<artifactId>gradle-maven-plugin</artifactId> <artifactId>gradle-maven-plugin</artifactId>
<version>1.0.12</version> <version>1.0.15</version>
</plugin> </plugin>
<plugin> <plugin>
<groupId>com.github.eirslett</groupId> <groupId>com.github.eirslett</groupId>
@ -663,6 +664,7 @@
<configuration> <configuration>
<argLine> <argLine>
-XX:+UseStringDeduplication -XX:MaxGCPauseMillis=200 -XX:+UseStringDeduplication -XX:MaxGCPauseMillis=200
-XX:+EnableDynamicAgentLoading
--add-opens=java.base/java.lang.reflect=ALL-UNNAMED --add-opens=java.base/java.lang.reflect=ALL-UNNAMED
-Dqueue.edqs.local.rocksdb_path="target/rocksdb/fork_${surefire.forkNumber}/edqs" -Dqueue.edqs.local.rocksdb_path="target/rocksdb/fork_${surefire.forkNumber}/edqs"
-Dqueue.calculated_fields.rocks_db_path="target/rocksdb/fork_${surefire.forkNumber}/cf" -Dqueue.calculated_fields.rocks_db_path="target/rocksdb/fork_${surefire.forkNumber}/cf"
@ -913,6 +915,16 @@
<type>pom</type> <type>pom</type>
<scope>import</scope> <scope>import</scope>
</dependency> </dependency>
<dependency>
<groupId>net.bytebuddy</groupId>
<artifactId>byte-buddy</artifactId>
<version>${bytebuddy.version}</version>
</dependency>
<dependency>
<groupId>net.bytebuddy</groupId>
<artifactId>byte-buddy-agent</artifactId>
<version>${bytebuddy.version}</version>
</dependency>
<dependency> <dependency>
<groupId>org.thingsboard.langchain4j</groupId> <groupId>org.thingsboard.langchain4j</groupId>
<artifactId>langchain4j-bom</artifactId> <artifactId>langchain4j-bom</artifactId>
@ -1955,4 +1967,10 @@
</repository> </repository>
</repositories> </repositories>
<pluginRepositories>
<pluginRepository>
<id>thingsboard-repo</id>
<url>https://repo.thingsboard.io/artifactory/libs-release-public</url>
</pluginRepository>
</pluginRepositories>
</project> </project>

Loading…
Cancel
Save