refactor: update to Springboot4 and Hibernate 7 (#4057)

Co-authored-by: lynx009 <2030509072@qq.com>
This commit is contained in:
Logic
2026-03-09 23:34:15 +08:00
committed by GitHub
co-authored by lynx009
parent 00b83ff531
commit 9e1a460dc7
166 changed files with 1343 additions and 8609 deletions
+2 -2
View File
@@ -3,5 +3,5 @@ FROM gitpod/workspace-full
USER gitpod
RUN bash -c ". /home/gitpod/.sdkman/bin/sdkman-init.sh && \
sdk install java 17.0.3-ms && \
sdk default java 17.0.3-ms"
sdk install java 21.0.2-tem && \
sdk default java 21.0.2-tem"
+2 -2
View File
@@ -32,7 +32,7 @@ Even small corrections to typos are very welcome :)
#### Backend start
1. Requires `maven3+`, `java17` and `lombok` environments
1. Requires `maven3+`, `java21` and `lombok` environments
2. (Optional) Modify the configuration file: `hertzbeat-startup/src/main/resources/application.yml`
@@ -172,7 +172,7 @@ Add WeChat account `ahertzbeat` to pull you into the WeChat group.
#### 后端启动
1. 需要 `maven3+`, `java17` 和 `lombok` 环境
1. 需要 `maven3+`, `java21` 和 `lombok` 环境
2. (可选)修改配置文件配置信息-`hertzbeat-startup/src/main/resources/application.yml`
+1 -1
View File
@@ -156,7 +156,7 @@ Detailed config refer to [Install HertzBeat via Package](https://hertzbeat.apach
##### 3Start via source code
1. Local source code debugging needs to start the back-end project `hertzbeat-startup` and the front-end project `web-app`.
2. Backendneed `maven3+`, `java17`, `lombok`, add VM options in IDE: ` --add-opens=java.base/java.nio=org.apache.arrow.memory.core,ALL-UNNAMED `, then start the `hertzbeat-startup` service.
2. Backendneed `maven3+`, `java21`, `lombok`, add VM options in IDE: ` --add-opens=java.base/java.nio=org.apache.arrow.memory.core,ALL-UNNAMED `, then start the `hertzbeat-startup` service.
3. Webneed `nodejs npm angular-cli` environment, Run `ng serve --open` in `web-app` directory after backend startup.
4. Access `http://localhost:4200` to start, default account: `admin/hertzbeat`
+1 -1
View File
@@ -153,7 +153,7 @@
##### 方式三:本地代码启动
1. 此为前后端分离项目,本地代码调试需要分别启动后端工程 `hertzbeat-startup` 和前端工程 `web-app`
2. 后端:需要 `maven3+`, `java17` 和 `lombok` 环境,修改 `YML` 配置信息,添加JVM参数`--add-opens=java.base/java.nio=org.apache.arrow.memory.core,ALL-UNNAMED`后启动 `hertzbeat-startup` 服务即可。
2. 后端:需要 `maven3+`, `java21` 和 `lombok` 环境,修改 `YML` 配置信息,添加JVM参数`--add-opens=java.base/java.nio=org.apache.arrow.memory.core,ALL-UNNAMED`后启动 `hertzbeat-startup` 服务即可。
3. 前端:需要 `nodejs npm angular-cli`环境,待本地后端启动后,在 `web-app` 目录下启动 `ng serve --open`
4. 浏览器访问 `http://localhost:4200` 即可开始,默认账号密码 `admin/hertzbeat`
+1 -1
View File
@@ -156,7 +156,7 @@
##### 方式3:ローカルの実行
1. ローカルの実行には、バックエンドのプロジェクト`hertzbeat-startup`とフロントエンドのプロジェクト`web-app`を起動する必要があります。
2. バックエンド:`maven3+`、`java17`と`lombok`の環境は必要です。`YML` 設定を修正し、Java仮想マシンパラメータに`--add-opens=java.base/java.nio=org.apache.arrow.memory.core,ALL-UNNAMED` を追加し、`hertzbeat-startup` を起動します。
2. バックエンド:`maven3+`、`Java21`と`lombok`の環境は必要です。`YML` 設定を修正し、Java仮想マシンパラメータに`--add-opens=java.base/java.nio=org.apache.arrow.memory.core,ALL-UNNAMED` を追加し、`hertzbeat-startup` を起動します。
3. フロントエンド:`nodejs npm angular-cli`の環境は必要です。ローカルのバックエンドが立ち上がったら、`web-app` ディレクトリで `ng serve --open` というコマンドを実行します。
4. スタート:`http://localhost:4200`にアクセスします。デフォルトのアカウントとパスワード:`admin/hertzbeat`。
+2 -5
View File
@@ -27,7 +27,7 @@
<version>${hertzbeat.version}</version>
<properties>
<spring-ai.version>1.1.1</spring-ai.version>
<java.version>17</java.version>
<java.version>21</java.version>
</properties>
<dependencies>
@@ -78,10 +78,7 @@
<groupId>com.usthe.sureness</groupId>
<artifactId>spring-boot3-starter-sureness</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.dataformat</groupId>
<artifactId>jackson-dataformat-yaml</artifactId>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
@@ -41,7 +41,7 @@ import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import reactor.core.publisher.Flux;
import javax.validation.Valid;
import jakarta.validation.Valid;
import java.util.List;
import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE;
@@ -26,7 +26,7 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Service;
import javax.annotation.PostConstruct;
import jakarta.annotation.PostConstruct;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
@@ -17,8 +17,7 @@
package org.apache.hertzbeat.ai.sop.registry;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.dataformat.yaml.YAMLFactory;
import tools.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.apache.hertzbeat.ai.sop.model.SopDefinition;
import org.springframework.core.io.Resource;
@@ -28,6 +27,7 @@ import org.springframework.stereotype.Service;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import tools.jackson.dataformat.yaml.YAMLFactory;
/**
* Loader for AI SOP definitions from YAML files.
@@ -17,9 +17,9 @@
package org.apache.hertzbeat.ai.tools.impl;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import tools.jackson.databind.ObjectMapper;
import tools.jackson.databind.node.ArrayNode;
import tools.jackson.databind.node.ObjectNode;
import com.usthe.sureness.subject.SubjectSum;
import lombok.extern.slf4j.Slf4j;
import org.apache.hertzbeat.ai.config.McpContextHolder;
@@ -17,9 +17,8 @@
package org.apache.hertzbeat.ai.utils;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import tools.jackson.databind.node.ArrayNode;
import tools.jackson.databind.node.ObjectNode;
import lombok.extern.slf4j.Slf4j;
import java.time.Instant;
@@ -31,6 +30,7 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.hertzbeat.manager.pojo.dto.Hierarchy;
import tools.jackson.databind.ObjectMapper;
/**
* Utility class providing helper methods for field expression validation, parsing,
+5
View File
@@ -35,6 +35,11 @@
<artifactId>hertzbeat-base</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.hertzbeat</groupId>
<artifactId>hertzbeat-common-core</artifactId>
<scope>provided</scope>
</dependency>
<!-- plugin -->
<dependency>
<groupId>org.apache.hertzbeat</groupId>
@@ -18,6 +18,8 @@
package org.apache.hertzbeat.alert.calculate.realtime;
import com.google.common.util.concurrent.ThreadFactoryBuilder;
import jakarta.annotation.PostConstruct;
import jakarta.annotation.PreDestroy;
import lombok.extern.slf4j.Slf4j;
import org.apache.hertzbeat.alert.calculate.realtime.window.LogWorker;
import org.apache.hertzbeat.alert.calculate.realtime.window.TimeService;
@@ -28,8 +30,6 @@ import org.apache.hertzbeat.common.util.BackoffUtils;
import org.apache.hertzbeat.common.util.ExponentialBackoff;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;
@@ -19,14 +19,14 @@ package org.apache.hertzbeat.alert.calculate.realtime.window;
import com.google.common.util.concurrent.ThreadFactoryBuilder;
import jakarta.annotation.PostConstruct;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import jakarta.annotation.PreDestroy;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.Executors;
@@ -18,6 +18,7 @@
package org.apache.hertzbeat.alert.calculate.realtime.window;
import com.google.common.util.concurrent.ThreadFactoryBuilder;
import jakarta.annotation.PostConstruct;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.Getter;
@@ -25,8 +26,7 @@ import lombok.extern.slf4j.Slf4j;
import org.apache.hertzbeat.common.entity.alerter.AlertDefine;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import jakarta.annotation.PreDestroy;
import java.util.ArrayList;
import java.util.Iterator;
@@ -17,12 +17,10 @@
package org.apache.hertzbeat.alert.notice.impl;
import com.fasterxml.jackson.databind.ObjectMapper;
import jakarta.mail.internet.MimeMessage;
import java.util.Date;
import java.util.Properties;
import java.util.ResourceBundle;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.hertzbeat.common.entity.dto.MailServerConfig;
import org.apache.hertzbeat.alert.notice.AlertNoticeException;
@@ -31,6 +29,7 @@ import org.apache.hertzbeat.common.entity.manager.GeneralConfig;
import org.apache.hertzbeat.common.entity.alerter.NoticeReceiver;
import org.apache.hertzbeat.common.entity.alerter.NoticeTemplate;
import org.apache.hertzbeat.common.support.event.SystemConfigChangeEvent;
import org.apache.hertzbeat.common.util.JsonUtil;
import org.apache.hertzbeat.common.util.ResourceBundleUtil;
import org.apache.hertzbeat.base.dao.GeneralConfigDao;
import org.springframework.beans.factory.annotation.Value;
@@ -44,7 +43,6 @@ import org.springframework.stereotype.Component;
* Send alarm information through email
*/
@Component
@RequiredArgsConstructor
@Slf4j
public class EmailAlertNotifyHandlerImpl extends AbstractAlertNotifyHandlerImpl {
@@ -70,12 +68,15 @@ public class EmailAlertNotifyHandlerImpl extends AbstractAlertNotifyHandlerImpl
private final GeneralConfigDao generalConfigDao;
private final ObjectMapper objectMapper;
private static final String TYPE = "email";
private ResourceBundle bundle = ResourceBundleUtil.getBundle("alerter");
public EmailAlertNotifyHandlerImpl(JavaMailSender javaMailSender, GeneralConfigDao generalConfigDao) {
this.javaMailSender = javaMailSender;
this.generalConfigDao = generalConfigDao;
}
@Override
public void send(NoticeReceiver receiver, NoticeTemplate noticeTemplate, GroupAlert alert) throws AlertNoticeException {
try {
@@ -88,8 +89,8 @@ public class EmailAlertNotifyHandlerImpl extends AbstractAlertNotifyHandlerImpl
if (emailConfig != null && emailConfig.getContent() != null) {
// enable database configuration
String content = emailConfig.getContent();
MailServerConfig emailNoticeSenderConfig = objectMapper.readValue(content, MailServerConfig.class);
if (emailNoticeSenderConfig.isEnable()) {
MailServerConfig emailNoticeSenderConfig = JsonUtil.fromJson(content, MailServerConfig.class);
if (emailNoticeSenderConfig != null && emailNoticeSenderConfig.isEnable()) {
sender.setHost(emailNoticeSenderConfig.getEmailHost());
sender.setPort(emailNoticeSenderConfig.getEmailPort());
sender.setUsername(emailNoticeSenderConfig.getEmailUsername());
@@ -18,9 +18,6 @@
package org.apache.hertzbeat.alert.notice.impl;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
@@ -49,6 +46,7 @@ import java.util.List;
import java.util.Objects;
import java.util.UUID;
import java.util.stream.Collectors;
import tools.jackson.databind.JsonNode;
/**
* FeiShu app alert notify impl
@@ -78,7 +76,6 @@ public class FeiShuAppAlertNotifyHandlerImpl extends AbstractAlertNotifyHandlerI
*/
private static final String APP_BATCH_MESSAGE_URL = "https://open.feishu.cn/open-apis/message/v4/batch_send/";
private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();
private static final byte USER_RECEIVE_TYPE = 0;
private static final byte CHAT_RECEIVE_TYPE = 1;
private static final byte PART_RECEIVE_TYPE = 2;
@@ -134,7 +131,7 @@ public class FeiShuAppAlertNotifyHandlerImpl extends AbstractAlertNotifyHandlerI
* @param messageContent Message content
* @see <a href="https://open.feishu.cn/document/server-docs/im-v1/batch_message/send-messages-in-batches">send message</a>
*/
private void sendLarkMessage(String accessToken, String receiverIdType, String receiverId, JsonNode messageContent) throws JsonProcessingException {
private void sendLarkMessage(String accessToken, String receiverIdType, String receiverId, JsonNode messageContent) {
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
headers.setBearerAuth(accessToken);
@@ -246,7 +243,7 @@ public class FeiShuAppAlertNotifyHandlerImpl extends AbstractAlertNotifyHandlerI
return response.getBody();
}
private JsonNode createLarkMessage(NoticeReceiver receiver, String notificationContent) throws JsonProcessingException {
private JsonNode createLarkMessage(NoticeReceiver receiver, String notificationContent) {
String larkCardMessage = """
{
"schema": "2.0",
@@ -359,12 +356,12 @@ public class FeiShuAppAlertNotifyHandlerImpl extends AbstractAlertNotifyHandlerI
String jsonStr = String.format(larkCardMessage,
notificationContent.replace("\"", "\\\"") + atUserElement,
alerterProperties.getConsoleUrl());
return OBJECT_MAPPER.readTree(jsonStr);
return JsonUtil.fromJson(jsonStr);
}
private String escapedCompactJson(JsonNode json) throws JsonProcessingException {
return OBJECT_MAPPER.writeValueAsString(json);
private String escapedCompactJson(JsonNode json) {
return json.toString();
}
/**
@@ -17,7 +17,6 @@
package org.apache.hertzbeat.alert.service;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.apache.hertzbeat.common.entity.dto.sms.SmsConfig;
import org.apache.hertzbeat.alert.service.impl.SmsLocalSmsClientImpl;
@@ -30,6 +29,7 @@ import org.apache.hertzbeat.base.dao.GeneralConfigDao;
import org.apache.hertzbeat.common.constants.GeneralConfigTypeEnum;
import org.apache.hertzbeat.common.entity.manager.GeneralConfig;
import org.apache.hertzbeat.common.support.event.SmsConfigChangeEvent;
import org.apache.hertzbeat.common.util.JsonUtil;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Component;
@@ -50,14 +50,12 @@ public class SmsClientFactory {
private static final String TYPE = GeneralConfigTypeEnum.sms.name();
private final GeneralConfigDao generalConfigDao;
private final ObjectMapper objectMapper;
private final SmsConfig yamlSmsConfig;
private volatile SmsClient currentSmsClient;
public SmsClientFactory(GeneralConfigDao generalConfigDao, ObjectMapper objectMapper, SmsConfig yamlSmsConfig) {
public SmsClientFactory(GeneralConfigDao generalConfigDao, SmsConfig yamlSmsConfig) {
this.generalConfigDao = generalConfigDao;
this.objectMapper = objectMapper;
this.yamlSmsConfig = yamlSmsConfig;
}
@@ -118,7 +116,7 @@ public class SmsClientFactory {
try {
GeneralConfig config = generalConfigDao.findByType(TYPE);
if (config != null && config.getContent() != null) {
return objectMapper.readValue(config.getContent(), SmsConfig.class);
return JsonUtil.fromJson(config.getContent(), SmsConfig.class);
}
} catch (Exception e) {
log.error("[SmsClientFactory] Failed to load database configuration", e);
@@ -19,7 +19,6 @@ package org.apache.hertzbeat.alert.service.impl;
import static org.apache.hertzbeat.common.constants.ExportFileConstants.ExcelFile.FILE_SUFFIX;
import static org.apache.hertzbeat.common.constants.ExportFileConstants.ExcelFile.TYPE;
import com.fasterxml.jackson.core.type.TypeReference;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
@@ -42,6 +41,7 @@ import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.ss.usermodel.WorkbookFactory;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import tools.jackson.core.type.TypeReference;
/**
* Configure the import and export EXCEL format
@@ -19,27 +19,22 @@ package org.apache.hertzbeat.alert.service.impl;
import static org.apache.hertzbeat.common.constants.ExportFileConstants.JsonFile.FILE_SUFFIX;
import static org.apache.hertzbeat.common.constants.ExportFileConstants.JsonFile.TYPE;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.List;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.hertzbeat.alert.dto.ExportAlertDefineDTO;
import org.apache.hertzbeat.common.util.JsonUtil;
import org.springframework.stereotype.Service;
import tools.jackson.core.type.TypeReference;
/**
* Configure the import and export JSON format
*/
@Slf4j
@RequiredArgsConstructor
@Service
public class AlertDefineJsonImExportServiceImpl extends AlertDefineAbstractImExportServiceImpl {
private final ObjectMapper objectMapper;
@Override
public String type() {
return TYPE;
@@ -52,22 +47,12 @@ public class AlertDefineJsonImExportServiceImpl extends AlertDefineAbstractImExp
@Override
public List<ExportAlertDefineDTO> parseImport(InputStream is) {
try {
return objectMapper.readValue(is, new TypeReference<>() {
});
} catch (IOException ex) {
log.error("import alertDefine failed.", ex);
throw new RuntimeException("import alertDefine failed");
}
return JsonUtil.fromJson(is, new TypeReference<>() {
});
}
@Override
public void writeOs(List<ExportAlertDefineDTO> exportAlertDefineList, OutputStream os) {
try {
objectMapper.writeValue(os, exportAlertDefineList);
} catch (IOException ex) {
log.error("export alertDefine failed.", ex);
throw new RuntimeException("export alertDefine failed");
}
JsonUtil.toJson(exportAlertDefineList, os);
}
}
@@ -17,9 +17,8 @@
package org.apache.hertzbeat.alert.service.impl;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import jakarta.annotation.Resource;
import tools.jackson.core.type.TypeReference;
import jakarta.persistence.criteria.CriteriaBuilder;
import jakarta.persistence.criteria.Predicate;
import jakarta.servlet.http.HttpServletResponse;
@@ -39,6 +38,7 @@ import org.apache.hertzbeat.common.entity.alerter.AlertDefine;
import org.apache.hertzbeat.common.entity.manager.Label;
import org.apache.hertzbeat.common.util.FileUtil;
import org.apache.hertzbeat.common.util.JexlExpressionRunner;
import org.apache.hertzbeat.common.util.JsonUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
@@ -51,7 +51,6 @@ import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;
import org.springframework.web.multipart.MultipartFile;
import javax.annotation.Resource;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
@@ -185,14 +184,9 @@ public class AlertDefineServiceImpl implements AlertDefineService {
@Override
public Page<AlertDefine> getAlertDefines(List<Long> defineIds, String search, String sort, String order, int pageIndex, int pageSize) {
// parse translation content list
ObjectMapper objectMapper = new ObjectMapper();
List<String> searchList = Collections.emptyList();
if (StringUtils.hasText(search)) {
try {
searchList = objectMapper.readValue(URLDecoder.decode(search, StandardCharsets.UTF_8), new TypeReference<>() {});
} catch (JsonProcessingException e) {
throw new IllegalArgumentException("Failed to parse search parameter", e);
}
searchList = JsonUtil.fromJson(URLDecoder.decode(search, StandardCharsets.UTF_8), new TypeReference<>() {});
}
List<String> finalSearchList = searchList;
// build search condition
@@ -17,7 +17,7 @@
package org.apache.hertzbeat.alert.service.impl;
import com.fasterxml.jackson.core.type.TypeReference;
import tools.jackson.core.type.TypeReference;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.BooleanUtils;
import org.apache.commons.lang3.StringUtils;
@@ -17,7 +17,6 @@
package org.apache.hertzbeat.alert.service.impl;
import com.fasterxml.jackson.databind.JsonNode;
import lombok.extern.slf4j.Slf4j;
import org.apache.hertzbeat.common.entity.dto.sms.AlibabaSmsProperties;
import org.apache.hertzbeat.alert.service.SmsClient;
@@ -45,6 +44,7 @@ import java.util.Map;
import java.util.SimpleTimeZone;
import java.util.TreeMap;
import java.util.UUID;
import tools.jackson.databind.JsonNode;
import static org.apache.hertzbeat.common.constants.SmsConstants.ALIBABA;
@@ -17,8 +17,7 @@
package org.apache.hertzbeat.alert.service.impl;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import tools.jackson.databind.JsonNode;
import lombok.extern.slf4j.Slf4j;
import org.apache.hertzbeat.common.entity.dto.sms.AwsSmsProperties;
import org.apache.hertzbeat.alert.service.SmsClient;
@@ -110,7 +109,10 @@ public class AwsSmsClientImpl implements SmsClient {
String endpoint = "https://" + SERVICE + "." + region + ".amazonaws.com";
try (CloseableHttpClient httpClient = HttpClients.createDefault()) {
String payloadInString = new ObjectMapper().writeValueAsString(payload);
String payloadInString = JsonUtil.toJson(payload);
if (payloadInString == null) {
throw new SendMessageException("Failed to serialize SMS payload");
}
URI requestUri = new URI(endpoint);
HttpPost httpPost = createHttpPost(requestUri, amzDate, payloadInString);
@@ -17,7 +17,7 @@
package org.apache.hertzbeat.alert.service.impl;
import com.fasterxml.jackson.databind.JsonNode;
import tools.jackson.databind.JsonNode;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
@@ -17,7 +17,7 @@
package org.apache.hertzbeat.alert.service.impl;
import com.fasterxml.jackson.core.type.TypeReference;
import tools.jackson.core.type.TypeReference;
import java.time.Instant;
import java.util.HashMap;
import java.util.List;
@@ -17,7 +17,6 @@
package org.apache.hertzbeat.alert.service.impl;
import com.fasterxml.jackson.core.type.TypeReference;
import lombok.extern.slf4j.Slf4j;
import org.apache.hertzbeat.alert.dto.SkyWalkingExternAlert;
import org.apache.hertzbeat.alert.reduce.AlarmCommonReduce;
@@ -32,6 +31,7 @@ import java.time.Instant;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import tools.jackson.core.type.TypeReference;
/**
* SkyWalking external alarm service impl
@@ -17,7 +17,7 @@
package org.apache.hertzbeat.alert.service.impl;
import com.fasterxml.jackson.databind.JsonNode;
import tools.jackson.databind.JsonNode;
import lombok.Getter;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
@@ -33,7 +33,7 @@ import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.apache.hertzbeat.common.util.JsonUtil;
import com.fasterxml.jackson.databind.JsonNode;
import tools.jackson.databind.JsonNode;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
@@ -17,7 +17,7 @@
package org.apache.hertzbeat.alert.service.impl;
import com.fasterxml.jackson.databind.JsonNode;
import tools.jackson.databind.JsonNode;
import lombok.extern.slf4j.Slf4j;
import org.apache.hertzbeat.common.entity.dto.sms.TwilioSmsProperties;
import org.apache.hertzbeat.alert.service.SmsClient;
@@ -31,7 +31,6 @@ import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import com.fasterxml.jackson.databind.JsonNode;
import org.apache.hertzbeat.alert.util.CryptoUtils;
import java.io.IOException;
@@ -41,6 +40,7 @@ import java.util.Map;
import java.util.TreeMap;
import java.util.UUID;
import java.util.stream.Collectors;
import tools.jackson.databind.JsonNode;
import static org.apache.hertzbeat.common.constants.SmsConstants.UNISMS;
@@ -17,10 +17,8 @@
package org.apache.hertzbeat.alert.service.impl;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import tools.jackson.databind.JsonNode;
import lombok.RequiredArgsConstructor;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.hertzbeat.alert.dto.VolcEngineExternEventAlert;
@@ -56,10 +54,12 @@ public class VolcEngineExternAlertService implements ExternAlertService {
);
@Override
@SneakyThrows
public void addExternAlert(String content) {
ObjectMapper mapper = new ObjectMapper();
JsonNode root = mapper.readTree(content);
JsonNode root = JsonUtil.fromJson(content);
if (root == null) {
log.warn("parse extern alert content failed! content: {}", content);
return;
}
String type = root.get("Type").asText();
if (VolcEngineExternMetricAlert.ALERT_TYPE_EVENT.equals(type)) {
VolcEngineExternEventAlert eventAlert = JsonUtil.fromJson(content, VolcEngineExternEventAlert.class);
@@ -19,13 +19,10 @@ package org.apache.hertzbeat.alert.notice.impl;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.lenient;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.util.Properties;
import org.apache.hertzbeat.common.entity.dto.MailServerConfig;
import org.apache.hertzbeat.base.dao.GeneralConfigDao;
@@ -35,6 +32,7 @@ import org.apache.hertzbeat.common.entity.alerter.NoticeTemplate;
import org.apache.hertzbeat.common.entity.alerter.SingleAlert;
import org.apache.hertzbeat.alert.notice.AlertNoticeException;
import org.apache.hertzbeat.common.entity.manager.GeneralConfig;
import org.apache.hertzbeat.common.util.JsonUtil;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
@@ -67,9 +65,6 @@ class EmailAlertNotifyHandlerImplTest {
@Mock
private MimeMessage mimeMessage;
@Mock
private ObjectMapper objectMapper;
@InjectMocks
private EmailAlertNotifyHandlerImpl emailAlertNotifyHandler;
@@ -78,7 +73,7 @@ class EmailAlertNotifyHandlerImplTest {
private NoticeTemplate template;
@BeforeEach
public void setUp() throws JsonProcessingException {
public void setUp() {
receiver = new NoticeReceiver();
receiver.setId(1L);
receiver.setName("test-receiver");
@@ -106,10 +101,11 @@ class EmailAlertNotifyHandlerImplTest {
mailServerConfig.setEmailUsername("sender@example.com");
mailServerConfig.setEmailPassword("password");
mailServerConfig.setEnable(true);
GeneralConfig generalConfig = GeneralConfig.builder().content("").build();
GeneralConfig generalConfig = GeneralConfig.builder()
.content(JsonUtil.toJson(mailServerConfig))
.build();
when(generalConfigDao.findByType(any())).thenReturn(generalConfig);
when(objectMapper.readValue(any(String.class), eq(MailServerConfig.class)))
.thenReturn(mailServerConfig);
when(mailSender.getJavaMailProperties()).thenReturn(new Properties());
}
@@ -19,20 +19,11 @@ package org.apache.hertzbeat.alert.service;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.jupiter.api.Assertions.assertTrue;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.charset.StandardCharsets;
import java.util.List;
import org.apache.hertzbeat.alert.dto.AlertDefineDTO;
@@ -40,22 +31,13 @@ import org.apache.hertzbeat.alert.dto.ExportAlertDefineDTO;
import org.apache.hertzbeat.alert.service.impl.AlertDefineJsonImExportServiceImpl;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
/**
* test case for {@link AlertDefineJsonImExportServiceImpl}
*/
@ExtendWith(MockitoExtension.class)
class AlertDefineJsonImExportServiceTest {
@Mock
private ObjectMapper objectMapper;
@InjectMocks
private AlertDefineJsonImExportServiceImpl service;
@SuppressWarnings("checkstyle:OperatorWrap")
@@ -68,6 +50,7 @@ class AlertDefineJsonImExportServiceTest {
@BeforeEach
public void setup() {
service = new AlertDefineJsonImExportServiceImpl();
inputStream = new ByteArrayInputStream(JSON_DATA.getBytes(StandardCharsets.UTF_8));
@@ -87,59 +70,43 @@ class AlertDefineJsonImExportServiceTest {
}
@Test
void testParseImport() throws IOException {
when(objectMapper.readValue(
any(InputStream.class),
any(TypeReference.class))
).thenReturn(alertDefineList);
void testParseImport() {
List<ExportAlertDefineDTO> result = service.parseImport(inputStream);
assertNotNull(result);
assertEquals(1, result.size());
assertEquals(alertDefineList, result);
verify(objectMapper, times(1)).readValue(any(InputStream.class), any(TypeReference.class));
assertEquals("App1", result.get(0).getAlertDefine().getName());
assertEquals("realtime", result.get(0).getAlertDefine().getType());
}
@Test
void testParseImportFailed() throws IOException {
void testParseImportFailed() {
InputStream invalidInputStream = new ByteArrayInputStream("invalid json".getBytes(StandardCharsets.UTF_8));
when(objectMapper.readValue(
any(InputStream.class),
any(TypeReference.class))
).thenThrow(new IOException("Test Exception"));
List<ExportAlertDefineDTO> result = service.parseImport(invalidInputStream);
RuntimeException exception = assertThrows(RuntimeException.class, () -> service.parseImport(inputStream));
assertEquals("import alertDefine failed", exception.getMessage());
verify(objectMapper, times(1)).readValue(any(InputStream.class), any(TypeReference.class));
assertNull(result);
}
@Test
void testWriteOs() throws IOException {
void testWriteOs() {
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
service.writeOs(alertDefineList, outputStream);
verify(objectMapper, times(1)).writeValue(any(OutputStream.class), eq(alertDefineList));
String result = outputStream.toString(StandardCharsets.UTF_8);
assertNotNull(result);
assertTrue(result.contains("App1"));
assertTrue(result.contains("realtime"));
}
@Test
void testWriteOsFailed() throws IOException {
doThrow(new IOException("Test Exception")).when(objectMapper).writeValue(any(OutputStream.class), any());
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
RuntimeException exception = assertThrows(
RuntimeException.class,
() -> service.writeOs(alertDefineList, outputStream)
);
assertEquals("export alertDefine failed", exception.getMessage());
verify(objectMapper, times(1)).writeValue(any(OutputStream.class), eq(alertDefineList));
void testType() {
assertEquals("JSON", service.type());
}
@Test
void testGetFileName() {
assertTrue(service.getFileName().endsWith(".json"));
}
}
@@ -17,8 +17,6 @@
package org.apache.hertzbeat.alert.service;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.hertzbeat.common.entity.dto.sms.SmsConfig;
import org.apache.hertzbeat.common.entity.dto.sms.SmslocalSmsProperties;
import org.apache.hertzbeat.base.dao.GeneralConfigDao;
@@ -46,9 +44,6 @@ public class SmsClientFactoryTest {
@Mock
private GeneralConfigDao generalConfigDao;
@Mock
private ObjectMapper objectMapper;
@Mock
private SmsConfig yamlSmsConfig;
@@ -57,7 +52,7 @@ public class SmsClientFactoryTest {
@Test
void testloadDbConfig() throws JsonProcessingException {
void testloadDbConfig() {
GeneralConfig generalConfig = new GeneralConfig();
SmsConfig smsConfig = new SmsConfig();
@@ -66,7 +61,6 @@ public class SmsClientFactoryTest {
smsConfig.setSmslocal(new SmslocalSmsProperties("11"));
generalConfig.setContent(JsonUtil.toJson(smsConfig));
when(objectMapper.readValue(generalConfig.getContent(), SmsConfig.class)).thenReturn(smsConfig);
when(generalConfigDao.findByType(GeneralConfigTypeEnum.sms.name())).thenReturn(generalConfig);
assertNotNull(smsClientFactory.getSmsClient());
@@ -17,7 +17,6 @@
package org.apache.hertzbeat.collector.collect.push;
import com.fasterxml.jackson.core.type.TypeReference;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
@@ -48,6 +47,7 @@ import org.apache.http.client.protocol.HttpClientContext;
import org.apache.http.protocol.HttpContext;
import org.apache.http.util.EntityUtils;
import org.springframework.http.MediaType;
import tools.jackson.core.type.TypeReference;
/**
* push style collect
@@ -17,7 +17,7 @@
package org.apache.hertzbeat.collector.collect.sd;
import com.fasterxml.jackson.core.type.TypeReference;
import tools.jackson.core.type.TypeReference;
import com.google.common.collect.Lists;
import java.io.IOException;
import java.net.MalformedURLException;
@@ -21,9 +21,6 @@ import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.jupiter.api.Assertions.assertTrue;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.gson.Gson;
import com.google.gson.JsonElement;
import java.util.ArrayList;
@@ -36,6 +33,7 @@ import com.google.gson.JsonObject;
import com.google.gson.JsonPrimitive;
import org.apache.hertzbeat.common.entity.job.Configmap;
import org.apache.hertzbeat.common.entity.job.Metrics;
import org.apache.hertzbeat.common.util.JsonUtil;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
@@ -46,8 +44,6 @@ import org.junit.jupiter.params.provider.MethodSource;
*/
class CollectUtilTest {
private static final ObjectMapper JSON_MAPPER = new ObjectMapper();
@Test
void countMatchKeyword() {
int keyword = CollectUtil.countMatchKeyword("hertzbeat", "e");
@@ -115,7 +111,7 @@ class CollectUtilTest {
}
@Test
void replaceCryPlaceholder() throws JsonMappingException, JsonProcessingException {
void replaceCryPlaceholder() {
Metrics metrics = Metrics.builder().name("^o^name^o^").build();
JsonElement jsonElement = new Gson().toJsonTree(metrics);
Map<String, Configmap> configmap = new HashMap<>();
@@ -125,7 +121,7 @@ class CollectUtilTest {
Metrics metricsTarget = Metrics.builder().name("张三").build();
JsonElement jsonElementTarget = new Gson().toJsonTree(metricsTarget);
assertEquals(JSON_MAPPER.readTree(jsonElementTarget.toString()), JSON_MAPPER.readTree(res1.toString()));
assertEquals(JsonUtil.fromJson(jsonElementTarget.toString()), JsonUtil.fromJson(res1.toString()));
List<Metrics> metricsList = new ArrayList<>();
metricsList.add(metrics);
@@ -137,7 +133,7 @@ class CollectUtilTest {
metricsListTarget.add(metricsTarget);
metricsListTarget.add(metricsTarget);
JsonElement jsonArrayTarget = new Gson().toJsonTree(metricsListTarget);
assertEquals(JSON_MAPPER.readTree(jsonArrayTarget.toString()), JSON_MAPPER.readTree(res2.toString()));
assertEquals(JsonUtil.fromJson(jsonArrayTarget.toString()), JsonUtil.fromJson(res2.toString()));
}
static Stream<Arguments> testParamsForShouldVerifyReplaceCryPlaceholder() {
@@ -181,10 +177,10 @@ class CollectUtilTest {
@MethodSource("testParamsForShouldVerifyReplaceCryPlaceholder")
void shouldVerifyReplaceCryPlaceholder(JsonObject jsonObject,
Map<String, Configmap> configmap,
JsonObject jsonObjectTarget) throws JsonProcessingException {
JsonObject jsonObjectTarget) {
JsonElement res1 = CollectUtil.replaceCryPlaceholder(jsonObject, configmap);
assertEquals(JSON_MAPPER.readTree(jsonObjectTarget.toString()), JSON_MAPPER.readTree(res1.toString()));
assertEquals(JsonUtil.fromJson(jsonObjectTarget.toString()), JsonUtil.fromJson(res1.toString()));
List<JsonObject> metricsList = new ArrayList<>();
metricsList.add(jsonObject);
@@ -195,11 +191,11 @@ class CollectUtilTest {
metricsListTarget.add(jsonObjectTarget);
JsonElement jsonArrayTarget = new Gson().toJsonTree(metricsListTarget);
assertEquals(JSON_MAPPER.readTree(jsonArrayTarget.toString()), JSON_MAPPER.readTree(res2.toString()));
assertEquals(JsonUtil.fromJson(jsonArrayTarget.toString()), JsonUtil.fromJson(res2.toString()));
}
@Test
void replaceSmilingPlaceholder() throws JsonMappingException, JsonProcessingException {
void replaceSmilingPlaceholder() {
Metrics metrics = Metrics.builder().name("^_^name^_^").build();
JsonElement jsonElement = new Gson().toJsonTree(metrics);
HashMap<String, Configmap> configmap = new HashMap<>();
@@ -208,7 +204,7 @@ class CollectUtilTest {
JsonElement res = CollectUtil.replaceSmilingPlaceholder(jsonElement, configmap);
Metrics metricsTarget = Metrics.builder().name("张三").build();
JsonElement jsonElement2 = new Gson().toJsonTree(metricsTarget);
assertEquals(JSON_MAPPER.readTree(jsonElement2.toString()), JSON_MAPPER.readTree(res.toString()));
assertEquals(JsonUtil.fromJson(jsonElement2.toString()), JsonUtil.fromJson(res.toString()));
List<Metrics> metricsList = new ArrayList<>();
metricsList.add(metrics);
@@ -220,7 +216,7 @@ class CollectUtilTest {
metricsListTarget.add(metricsTarget);
metricsListTarget.add(metricsTarget);
JsonElement jsonArrayTarget = new Gson().toJsonTree(metricsListTarget);
assertEquals(JSON_MAPPER.readTree(jsonArrayTarget.toString()), JSON_MAPPER.readTree(res2.toString()));
assertEquals(JsonUtil.fromJson(jsonArrayTarget.toString()), JsonUtil.fromJson(res2.toString()));
}
@Test
@@ -57,10 +57,6 @@
<artifactId>sshd-core</artifactId>
<version>${sshd-core.version}</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
@@ -17,7 +17,7 @@
package org.apache.hertzbeat.collector.dispatch.entrance.processor;
import com.fasterxml.jackson.core.type.TypeReference;
import tools.jackson.core.type.TypeReference;
import io.netty.channel.ChannelHandlerContext;
import lombok.extern.slf4j.Slf4j;
import org.apache.hertzbeat.collector.dispatch.entrance.CollectServer;
@@ -18,7 +18,7 @@
package org.apache.hertzbeat.collector.util;
import com.beetstra.jutf7.CharsetProvider;
import com.fasterxml.jackson.core.type.TypeReference;
import tools.jackson.core.type.TypeReference;
import com.google.gson.Gson;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
+1 -1
View File
@@ -28,7 +28,7 @@
<name>${project.artifactId}</name>
<packaging>pom</packaging>
<properties>
<java.version>17</java.version>
<java.version>21</java.version>
<maven.compiler.source>${java.version}</maven.compiler.source>
<maven.compiler.target>${java.version}</maven.compiler.target>
</properties>
+15 -5
View File
@@ -131,26 +131,36 @@
<version>${javaparser.version}</version>
<scope>test</scope>
</dependency>
<!-- Test dependencies -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.github.jsqlparser</groupId>
<artifactId>jsqlparser</artifactId>
</dependency>
<!-- jackson for optional json processing -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<groupId>tools.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.dataformat</groupId>
<groupId>tools.jackson.dataformat</groupId>
<artifactId>jackson-dataformat-xml</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>tools.jackson.dataformat</groupId>
<artifactId>jackson-dataformat-yaml</artifactId>
</dependency>
<!-- swagger annotations (optional) -->
<dependency>
<groupId>org.springdoc</groupId>
@@ -6,7 +6,7 @@
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
@@ -17,14 +17,8 @@
package org.apache.hertzbeat.common.entity.dto;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.ObjectCodec;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.google.gson.JsonObject;
import java.io.IOException;
import java.util.List;
import lombok.AllArgsConstructor;
import lombok.EqualsAndHashCode;
@@ -32,6 +26,11 @@ import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.ToString;
import lombok.experimental.Accessors;
import tools.jackson.core.JsonParser;
import tools.jackson.databind.DeserializationContext;
import tools.jackson.databind.JsonNode;
import tools.jackson.databind.ValueDeserializer;
import tools.jackson.databind.annotation.JsonDeserialize;
/**
* prometheus vector or matrix entity
@@ -42,6 +41,7 @@ import lombok.experimental.Accessors;
@Accessors(chain = true)
@ToString
@Getter
@JsonIgnoreProperties(ignoreUnknown = true)
public class PromVectorOrMatrix {
private String status;
private Data data;
@@ -81,15 +81,18 @@ public class PromVectorOrMatrix {
@lombok.Data
@NoArgsConstructor
@Accessors(chain = true)
public static class MetricJsonObjectDeserializer extends JsonDeserializer<JsonObject>{
public static class MetricJsonObjectDeserializer extends ValueDeserializer<JsonObject> {
@Override
public JsonObject deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException {
ObjectCodec oc = jp.getCodec();
JsonNode node = oc.readTree(jp);
public JsonObject deserialize(JsonParser jp, DeserializationContext ctxt) {
JsonNode node = jp.objectReadContext().readTree(jp);
JsonObject metric = new JsonObject();
node.fields().forEachRemaining(entry -> metric.addProperty(entry.getKey(), entry.getValue().asText()));
if (node != null && node.isObject()) {
node.properties().forEach(entry ->
metric.addProperty(entry.getKey(), entry.getValue().asString())
);
}
return metric;
}
@@ -17,15 +17,16 @@
package org.apache.hertzbeat.common.entity.sd;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlElementWrapper;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.List;
import tools.jackson.dataformat.xml.annotation.JacksonXmlElementWrapper;
import tools.jackson.dataformat.xml.annotation.JacksonXmlProperty;
import tools.jackson.dataformat.xml.annotation.JacksonXmlRootElement;
/**
* eureka service discovery entity
@@ -17,12 +17,11 @@
package org.apache.hertzbeat.common.serialize;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.nio.charset.StandardCharsets;
import java.util.Map;
import lombok.extern.slf4j.Slf4j;
import org.apache.hertzbeat.common.entity.log.LogEntry;
import org.apache.hertzbeat.common.util.JsonUtil;
import org.apache.kafka.common.header.Headers;
import org.apache.kafka.common.serialization.Deserializer;
@@ -32,12 +31,6 @@ import org.apache.kafka.common.serialization.Deserializer;
@Slf4j
public class KafkaLogEntryDeserializer implements Deserializer<LogEntry> {
private final ObjectMapper objectMapper;
public KafkaLogEntryDeserializer() {
this.objectMapper = new ObjectMapper();
}
@Override
public void configure(Map<String, ?> configs, boolean isKey) {
Deserializer.super.configure(configs, isKey);
@@ -49,13 +42,12 @@ public class KafkaLogEntryDeserializer implements Deserializer<LogEntry> {
log.warn("Empty data received for topic: {}", topic);
return null;
}
try {
String jsonString = new String(data, StandardCharsets.UTF_8);
return objectMapper.readValue(jsonString, LogEntry.class);
} catch (JsonProcessingException e) {
log.error("Failed to deserialize LogEntry from JSON for topic: {}", topic, e);
return null;
String jsonString = new String(data, StandardCharsets.UTF_8);
LogEntry logEntry = JsonUtil.fromJson(jsonString, LogEntry.class);
if (logEntry == null) {
log.warn("Failed to deserialize LogEntry from topic: {}", topic);
}
return logEntry;
}
@Override
@@ -17,12 +17,11 @@
package org.apache.hertzbeat.common.serialize;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.nio.charset.StandardCharsets;
import java.util.Map;
import lombok.extern.slf4j.Slf4j;
import org.apache.hertzbeat.common.entity.log.LogEntry;
import org.apache.hertzbeat.common.util.JsonUtil;
import org.apache.kafka.common.header.Headers;
import org.apache.kafka.common.serialization.Serializer;
@@ -32,12 +31,6 @@ import org.apache.kafka.common.serialization.Serializer;
@Slf4j
public class KafkaLogEntrySerializer implements Serializer<LogEntry> {
private final ObjectMapper objectMapper;
public KafkaLogEntrySerializer() {
this.objectMapper = new ObjectMapper();
}
@Override
public void configure(Map<String, ?> configs, boolean isKey) {
Serializer.super.configure(configs, isKey);
@@ -49,13 +42,12 @@ public class KafkaLogEntrySerializer implements Serializer<LogEntry> {
log.warn("LogEntry is null for topic: {}", topic);
return null;
}
try {
String jsonString = objectMapper.writeValueAsString(logEntry);
return jsonString.getBytes(StandardCharsets.UTF_8);
} catch (JsonProcessingException e) {
log.error("Failed to serialize LogEntry to JSON for topic: {}", topic, e);
String jsonString = JsonUtil.toJson(logEntry);
if (jsonString == null) {
log.error("Failed to serialize LogEntry for topic: {}", topic);
return null;
}
return jsonString.getBytes(StandardCharsets.UTF_8);
}
@Override
@@ -17,11 +17,11 @@
package org.apache.hertzbeat.common.serialize;
import com.fasterxml.jackson.databind.ObjectMapper;
import io.lettuce.core.codec.RedisCodec;
import io.netty.buffer.Unpooled;
import lombok.extern.slf4j.Slf4j;
import org.apache.hertzbeat.common.entity.log.LogEntry;
import org.apache.hertzbeat.common.util.JsonUtil;
import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;
@@ -32,12 +32,6 @@ import java.nio.charset.StandardCharsets;
@Slf4j
public class RedisLogEntryCodec implements RedisCodec<String, LogEntry> {
private final ObjectMapper objectMapper;
public RedisLogEntryCodec() {
this.objectMapper = new ObjectMapper();
}
@Override
public String decodeKey(ByteBuffer byteBuffer) {
return Unpooled.wrappedBuffer(byteBuffer).toString(StandardCharsets.UTF_8);
@@ -48,13 +42,12 @@ public class RedisLogEntryCodec implements RedisCodec<String, LogEntry> {
if (byteBuffer == null || !byteBuffer.hasRemaining()) {
return null;
}
try {
String jsonString = Unpooled.wrappedBuffer(byteBuffer).toString(StandardCharsets.UTF_8);
return objectMapper.readValue(jsonString, LogEntry.class);
} catch (Exception e) {
log.error("Failed to decode LogEntry from JSON: {}", e.getMessage());
return null;
String jsonString = Unpooled.wrappedBuffer(byteBuffer).toString(StandardCharsets.UTF_8);
LogEntry logEntry = JsonUtil.fromJson(jsonString, LogEntry.class);
if (logEntry == null) {
log.error("Failed to decode LogEntry from JSON");
}
return logEntry;
}
@Override
@@ -64,12 +57,11 @@ public class RedisLogEntryCodec implements RedisCodec<String, LogEntry> {
@Override
public ByteBuffer encodeValue(LogEntry logEntry) {
try {
String jsonString = objectMapper.writeValueAsString(logEntry);
return ByteBuffer.wrap(jsonString.getBytes(StandardCharsets.UTF_8));
} catch (Exception e) {
log.error("Failed to encode LogEntry to JSON: {}", e.getMessage());
String jsonString = JsonUtil.toJson(logEntry);
if (jsonString == null) {
log.error("Failed to encode LogEntry to JSON");
return null;
}
return ByteBuffer.wrap(jsonString.getBytes(StandardCharsets.UTF_8));
}
}
@@ -19,7 +19,6 @@
package org.apache.hertzbeat.common.util;
import com.fasterxml.jackson.core.type.TypeReference;
import com.google.common.collect.Maps;
import org.apache.commons.jexl3.JexlBuilder;
import org.apache.commons.jexl3.JexlContext;
@@ -32,6 +31,7 @@ import org.apache.hertzbeat.common.constants.CommonConstants;
import java.nio.charset.StandardCharsets;
import java.util.Map;
import java.util.function.Function;
import tools.jackson.core.type.TypeReference;
/**
* jexl express runner
@@ -19,15 +19,18 @@ package org.apache.hertzbeat.common.util;
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import javax.annotation.concurrent.ThreadSafe;
import java.io.InputStream;
import java.io.OutputStream;
import lombok.extern.slf4j.Slf4j;
import tools.jackson.core.JacksonException;
import tools.jackson.core.type.TypeReference;
import tools.jackson.databind.DeserializationFeature;
import tools.jackson.databind.JsonNode;
import tools.jackson.databind.ObjectMapper;
import tools.jackson.databind.SerializationFeature;
import tools.jackson.databind.json.JsonMapper;
import javax.annotation.concurrent.ThreadSafe;
/**
* json util
@@ -36,27 +39,25 @@ import lombok.extern.slf4j.Slf4j;
@Slf4j
public final class JsonUtil {
private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();
private static final ObjectMapper OBJECT_MAPPER = JsonMapper.builder()
.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
.configure(DeserializationFeature.FAIL_ON_NULL_FOR_PRIMITIVES, false)
.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false)
.changeDefaultVisibility(vc -> vc.withVisibility(PropertyAccessor.FIELD, JsonAutoDetect.Visibility.ANY))
.build();
private JsonUtil() {
}
static {
OBJECT_MAPPER
.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false)
.setVisibility(PropertyAccessor.FIELD, JsonAutoDetect.Visibility.ANY)
.registerModule(new JavaTimeModule());
}
public static String toJson(Object source) {
if (source == null) {
return null;
}
try {
return OBJECT_MAPPER.writeValueAsString(source);
} catch (JsonProcessingException e) {
log.error(e.getMessage(), e);
} catch (JacksonException e) {
log.error("Error converting object to JSON: {}", e.getMessage(), e);
return null;
}
}
@@ -67,8 +68,8 @@ public final class JsonUtil {
}
try {
return OBJECT_MAPPER.readValue(jsonStr, clazz);
} catch (Exception e) {
log.error(e.getMessage(), e);
} catch (JacksonException e) {
log.error("Error parsing JSON to class {}: {}", clazz.getName(), e.getMessage(), e);
return null;
}
}
@@ -79,8 +80,8 @@ public final class JsonUtil {
}
try {
return OBJECT_MAPPER.readValue(jsonStr, type);
} catch (Exception e) {
log.error(e.getMessage(), e);
} catch (JacksonException e) {
log.error("Error parsing JSON to TypeReference: {}", e.getMessage(), e);
return null;
}
}
@@ -91,8 +92,8 @@ public final class JsonUtil {
}
try {
return OBJECT_MAPPER.readTree(jsonStr);
} catch (Exception e) {
log.error(e.getMessage(), e);
} catch (JacksonException e) {
log.error("Error reading JSON tree: {}", e.getMessage(), e);
return null;
}
}
@@ -102,21 +103,18 @@ public final class JsonUtil {
* @param jsonStr json string
* @return true if the string is a json string
*/
public static boolean isJsonStr(String jsonStr) {
if (jsonStr == null || jsonStr.trim().isEmpty()) {
return false;
}
jsonStr = jsonStr.trim();
if (!(jsonStr.startsWith("{") && jsonStr.endsWith("}"))
&& !(jsonStr.startsWith("[") && jsonStr.endsWith("]"))) {
if (!isJsonLike(jsonStr)) {
return false;
}
try {
OBJECT_MAPPER.readTree(jsonStr);
return true;
} catch (Exception ignored) {
} catch (JacksonException ignored) {
return false;
}
}
@@ -128,7 +126,7 @@ public final class JsonUtil {
try {
JsonNode jsonNode = OBJECT_MAPPER.readTree(jsonStr);
return jsonNode.isArray();
} catch (Exception ignore) {
} catch (JacksonException ignore) {
return false;
}
}
@@ -142,4 +140,56 @@ public final class JsonUtil {
char end = jsonStr.charAt(jsonStr.length() - 1);
return (start == '{' && end == '}') || (start == '[' && end == ']');
}
/**
* Parse JSON from InputStream to object
* @param is input stream
* @param type type reference
* @return parsed object or null if error
*/
public static <T> T fromJson(InputStream is, TypeReference<T> type) {
if (is == null) {
return null;
}
try {
return OBJECT_MAPPER.readValue(is, type);
} catch (JacksonException e) {
log.error("Error parsing JSON from InputStream to TypeReference: {}", e.getMessage(), e);
return null;
}
}
/**
* Write object to OutputStream as JSON
* @param source object to serialize
* @param os output stream
*/
public static void toJson(Object source, OutputStream os) {
if (source == null || os == null) {
return;
}
try {
OBJECT_MAPPER.writeValue(os, source);
} catch (JacksonException e) {
log.error("Error writing object to OutputStream as JSON: {}", e.getMessage(), e);
}
}
/**
* Convert a value from one type to another using JSON serialization/deserialization
* @param fromValue source value
* @param toValueType target type
* @return converted value or null if error
*/
public static <T> T convertValue(Object fromValue, Class<T> toValueType) {
if (fromValue == null) {
return null;
}
try {
return OBJECT_MAPPER.convertValue(fromValue, toValueType);
} catch (JacksonException e) {
log.error("Error converting value to {}: {}", toValueType.getName(), e.getMessage(), e);
return null;
}
}
}
@@ -0,0 +1,77 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.hertzbeat.common.util;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import tools.jackson.core.JacksonException;
import tools.jackson.core.type.TypeReference;
import tools.jackson.databind.DeserializationFeature;
import tools.jackson.databind.SerializationFeature;
import tools.jackson.dataformat.xml.XmlMapper;
/**
* xml util
*/
@Slf4j
public class XmlUtil {
private static final XmlMapper XML_MAPPER = XmlMapper.builder()
.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false)
.build();
private XmlUtil() {
}
/**
* Convert object to XML string
*/
public static String toXml(Object source) {
if (source == null) {
return null;
}
return XML_MAPPER.writeValueAsString(source);
}
/**
* Convert XML string to object
*/
public static <T> T fromXml(String xml, Class<T> clazz) {
if (StringUtils.isEmpty(xml)) {
return null;
}
return XML_MAPPER.readValue(xml, clazz);
}
/**
* Convert XML string to object with TypeReference
*/
public static <T> T fromXml(String xml, TypeReference<T> type) {
if (!StringUtils.isEmpty(xml)) {
return null;
}
try {
return XML_MAPPER.readValue(xml, type);
} catch (JacksonException e) {
log.error("Error parsing XML to TypeReference: {}", e.getMessage(), e);
return null;
}
}
}
@@ -24,7 +24,7 @@ import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.jupiter.api.Assertions.assertTrue;
import com.fasterxml.jackson.core.type.TypeReference;
import tools.jackson.core.type.TypeReference;
import java.util.Map;
import org.junit.jupiter.api.Test;
@@ -47,7 +47,7 @@ class JsonUtilTest {
void testFromJson() {
assertNull(JsonUtil.fromJson("", new TypeReference<>() {
}));
assertNull(JsonUtil.fromJson(null, new TypeReference<>() {
assertNull(JsonUtil.fromJson((String) null, new TypeReference<>() {
}));
assertNull(JsonUtil.fromJson(" ", new TypeReference<>() {
}));
-16
View File
@@ -52,20 +52,9 @@
<artifactId>spring-boot-autoconfigure</artifactId>
</dependency>
<!-- jpa -->
<dependency>
<groupId>org.eclipse.persistence</groupId>
<artifactId>org.eclipse.persistence.jpa</artifactId>
<version>${eclipse-jpa.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
<exclusions>
<exclusion>
<groupId>org.hibernate.orm</groupId>
<artifactId>hibernate-core</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- validation -->
<dependency>
@@ -78,11 +67,6 @@
<artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
<scope>provided</scope>
</dependency>
<!-- jackson -->
<dependency>
<groupId>com.fasterxml.jackson.dataformat</groupId>
<artifactId>jackson-dataformat-xml</artifactId>
</dependency>
</dependencies>
</project>
@@ -1,68 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.hertzbeat.common.config;
import lombok.extern.slf4j.Slf4j;
import org.eclipse.persistence.config.SessionCustomizer;
import org.eclipse.persistence.descriptors.ClassDescriptor;
import org.eclipse.persistence.mappings.DatabaseMapping;
import org.eclipse.persistence.sessions.Session;
/**
* change column name that from upper-case to lower-case-with-underscore
*/
@Slf4j
public class EclipseLinkCustomizer implements SessionCustomizer {
@Override
public void customize(Session session) throws Exception {
for (ClassDescriptor descriptor : session.getDescriptors().values()) {
for (DatabaseMapping mapping : descriptor.getMappings()) {
if (mapping.isDirectToFieldMapping()) {
// update the column name to lower case with underscore
if (!mapping.getField().getName().equalsIgnoreCase(mapping.getAttributeName())) {
// already custom define the column name, ignore
continue;
}
// todo here i try to change column name that from upper-case to lower-case-with-underscore
// but failed, when update name, something relate exception happen more
mapping.getField().setName(convertCamelCase(mapping.getAttributeName()));
}
}
}
}
private String convertCamelCase(String camelCase) {
StringBuilder result = new StringBuilder();
if (camelCase != null && !camelCase.isEmpty()) {
result.append(Character.toLowerCase(camelCase.charAt(0)));
for (int i = 1; i < camelCase.length(); i++) {
char currentChar = camelCase.charAt(i);
if (Character.isUpperCase(currentChar)) {
result.append('_').append(Character.toLowerCase(currentChar));
} else {
result.append(currentChar);
}
}
}
return result.toString();
}
}
@@ -1,61 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.hertzbeat.common.config;
import java.util.HashMap;
import java.util.Map;
import javax.sql.DataSource;
import org.eclipse.persistence.config.PersistenceUnitProperties;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.autoconfigure.orm.jpa.JpaBaseConfiguration;
import org.springframework.boot.autoconfigure.orm.jpa.JpaProperties;
import org.springframework.context.annotation.Configuration;
import org.springframework.orm.jpa.vendor.AbstractJpaVendorAdapter;
import org.springframework.orm.jpa.vendor.EclipseLinkJpaVendorAdapter;
import org.springframework.transaction.jta.JtaTransactionManager;
/**
* jpa eclipselink impl config
*/
@Configuration
@ConditionalOnProperty(prefix = "spring.datasource", name = "url")
public class EclipseLinkJpaConfiguration extends JpaBaseConfiguration {
protected EclipseLinkJpaConfiguration(DataSource dataSource, JpaProperties properties,
ObjectProvider<JtaTransactionManager> jtaTransactionManager) {
super(dataSource, properties, jtaTransactionManager);
}
@Override
protected AbstractJpaVendorAdapter createJpaVendorAdapter() {
return new EclipseLinkJpaVendorAdapter();
}
@Override
protected Map<String, Object> getVendorProperties() {
HashMap<String, Object> map = new HashMap<>(8);
map.put(PersistenceUnitProperties.DDL_GENERATION, "create-or-extend-tables");
map.put(PersistenceUnitProperties.SESSION_CUSTOMIZER, "org.apache.hertzbeat.common.config.EclipseLinkCustomizer");
map.put(PersistenceUnitProperties.ALLOW_NATIVE_SQL_QUERIES, "true");
map.put(PersistenceUnitProperties.WEAVING, "true");
return map;
}
}
@@ -24,7 +24,6 @@ import jakarta.persistence.EntityListeners;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.JoinColumn;
import jakarta.persistence.OneToMany;
import jakarta.persistence.Table;
import org.springframework.data.annotation.CreatedBy;
@@ -78,7 +77,6 @@ public class ChatConversation {
/**
* List of messages in this conversation (one-to-many relationship)
*/
@OneToMany
@JoinColumn(name = "conversation_id")
@OneToMany(mappedBy = "conversation")
private List<ChatMessage> messages;
}
@@ -19,14 +19,16 @@ package org.apache.hertzbeat.common.entity.ai;
import static io.swagger.v3.oas.annotations.media.Schema.AccessMode.READ_ONLY;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.EntityListeners;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.Index;
import jakarta.persistence.JoinColumn;
import jakarta.persistence.Lob;
import jakarta.persistence.ManyToOne;
import jakarta.persistence.Table;
import jakarta.validation.constraints.NotBlank;
import java.time.LocalDateTime;
@@ -59,8 +61,14 @@ public class ChatMessage {
private Long id;
@Schema(title = "conversation id")
@Column(name = "conversation_id", insertable = false, updatable = false)
private Long conversationId;
@Schema(title = "conversation", hidden = true)
@ManyToOne
@JoinColumn(name = "conversation_id")
private ChatConversation conversation;
@Schema(title = "message content")
@Lob
@NotBlank
@@ -17,7 +17,7 @@
package org.apache.hertzbeat.common.entity.alerter;
import com.fasterxml.jackson.core.type.TypeReference;
import tools.jackson.core.type.TypeReference;
import jakarta.persistence.AttributeConverter;
import jakarta.persistence.Converter;
import java.util.HashMap;
@@ -17,7 +17,7 @@
package org.apache.hertzbeat.common.entity.manager;
import com.fasterxml.jackson.core.type.TypeReference;
import tools.jackson.core.type.TypeReference;
import jakarta.persistence.AttributeConverter;
import jakarta.persistence.Converter;
import java.util.List;
@@ -17,7 +17,7 @@
package org.apache.hertzbeat.common.entity.manager;
import com.fasterxml.jackson.core.type.TypeReference;
import tools.jackson.core.type.TypeReference;
import jakarta.persistence.AttributeConverter;
import jakarta.persistence.Converter;
import java.util.List;
@@ -17,13 +17,13 @@
package org.apache.hertzbeat.common.entity.manager;
import com.fasterxml.jackson.core.type.TypeReference;
import jakarta.persistence.AttributeConverter;
import jakarta.persistence.Converter;
import java.util.List;
import java.util.Map;
import org.apache.hertzbeat.common.util.JsonUtil;
import org.springframework.stereotype.Component;
import tools.jackson.core.type.TypeReference;
/**
* json map list str converter
@@ -17,7 +17,7 @@
package org.apache.hertzbeat.common.entity.manager;
import com.fasterxml.jackson.core.type.TypeReference;
import tools.jackson.core.type.TypeReference;
import jakarta.persistence.AttributeConverter;
import jakarta.persistence.Converter;
import java.util.List;
@@ -17,7 +17,7 @@
package org.apache.hertzbeat.common.entity.manager;
import com.fasterxml.jackson.core.type.TypeReference;
import tools.jackson.core.type.TypeReference;
import jakarta.persistence.AttributeConverter;
import jakarta.persistence.Converter;
import java.util.List;
@@ -1,78 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.hertzbeat.common.util;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.dataformat.xml.XmlMapper;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.StringUtils;
/**
* xml util
*/
@Slf4j
public class XmlUtil {
private static final XmlMapper XML_MAPPER = new XmlMapper();
static {
XML_MAPPER.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false)
.registerModule(new JavaTimeModule());
}
public String toXml(Object source) {
if (source == null) {
return null;
}
try {
return XML_MAPPER.writeValueAsString(source);
} catch (JsonProcessingException e) {
log.error(e.getMessage(), e);
return null;
}
}
public static <T> T fromXml(String xml, Class<T> clazz) {
if (!StringUtils.hasText(xml)) {
return null;
}
try {
return XML_MAPPER.readValue(xml, clazz);
} catch (Exception e) {
log.error(e.getMessage(), e);
return null;
}
}
public static <T> T fromXml(String xml, TypeReference<T> type) {
if (!StringUtils.hasText(xml)) {
return null;
}
try {
return XML_MAPPER.readValue(xml, type);
} catch (Exception e) {
log.error(e.getMessage(), e);
return null;
}
}
}
@@ -39,6 +39,7 @@ import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
import static org.mockito.Mockito.lenient;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
@@ -71,7 +72,7 @@ public abstract class AbstractCollectE2eTest {
public void setUp() throws Exception {
// Initialize mocks
MockitoAnnotations.openMocks(this);
when(defineDao.findAll()).thenReturn(new ArrayList<>());
lenient().when(defineDao.findAll()).thenReturn(new ArrayList<>());
when(timeout.task()).thenReturn(timerJob);
when(timerJob.getJob()).thenReturn(job);
metricsCollect = new MetricsCollect(mock(Metrics.class), timeout, mock(CollectDataDispatch.class), null, List.of());
+5 -2
View File
@@ -31,8 +31,6 @@
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<okhttp.version>4.12.0</okhttp.version>
<jackson.version>2.15.2</jackson.version>
<maven.resources.plugin.version>3.3.1</maven.resources.plugin.version>
<maven.dependency.plugin.version>3.6.1</maven.dependency.plugin.version>
@@ -84,6 +82,11 @@
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-test-autoconfigure</artifactId>
<scope>test</scope>
</dependency>
<!-- JUnit 5 -->
<dependency>
@@ -28,10 +28,11 @@ import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestInstance;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.mock.mockito.SpyBean;
import org.springframework.boot.test.web.server.LocalServerPort;
import org.springframework.test.context.bean.override.mockito.MockitoSpyBean;
import org.springframework.test.context.DynamicPropertyRegistry;
import org.springframework.test.context.DynamicPropertySource;
import org.springframework.test.context.TestPropertySource;
import org.testcontainers.containers.GenericContainer;
import org.testcontainers.containers.Network;
import org.testcontainers.containers.wait.strategy.Wait;
@@ -44,6 +45,7 @@ import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import static org.awaitility.Awaitility.await;
import static org.junit.jupiter.api.Assertions.assertEquals;
@@ -59,6 +61,10 @@ import static org.mockito.Mockito.doAnswer;
* E2E tests for periodic log alert processing.
*/
@SpringBootTest(classes = org.apache.hertzbeat.startup.HertzBeatApplication.class, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@TestPropertySource(properties = {
"warehouse.store.duckdb.enabled=false",
"warehouse.store.greptime.enabled=true"
})
@Slf4j
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
public class LogPeriodicAlertE2eTest {
@@ -81,7 +87,7 @@ public class LogPeriodicAlertE2eTest {
AlertDefine errorCountAlertByGroup;
AlertDefine errorCountAlertByIndividual;
@SpyBean
@MockitoSpyBean
private AlarmCommonReduce alarmCommonReduce;
static GenericContainer<?> vector;
@@ -101,9 +107,7 @@ public class LogPeriodicAlertE2eTest {
@DynamicPropertySource
static void greptimeProps(DynamicPropertyRegistry r) {
// Configure GreptimeDB storage
r.add("warehouse.store.duckdb.enabled", () -> "false");
r.add("warehouse.store.greptime.enabled", () -> "true");
// Configure GreptimeDB storage endpoints (dynamic ports)
r.add("warehouse.store.greptime.http-endpoint", () -> "http://localhost:" + greptimedb.getMappedPort(GREPTIME_HTTP_PORT));
r.add("warehouse.store.greptime.grpc-endpoints", () -> "localhost:" + greptimedb.getMappedPort(GREPTIME_GRPC_PORT));
r.add("warehouse.store.greptime.username", () -> "");
@@ -111,10 +115,15 @@ public class LogPeriodicAlertE2eTest {
}
@BeforeAll
void setUpAll() {
void setUpAll() throws InterruptedException {
// Setup test alert definitions
setupTestAlertDefines();
Testcontainers.exposeHostPorts(port);
// Wait for HertzBeat to be fully ready before starting Vector
log.info("Waiting for HertzBeat to be fully ready on port {}...", port);
Thread.sleep(5000); // Give HertzBeat time to fully initialize
vector = new GenericContainer<>(DockerImageName.parse(VECTOR_IMAGE))
.withExposedPorts(VECTOR_PORT)
.withCopyFileToContainer(MountableFile.forClasspathResource("vector.yml"), VECTOR_CONFIG_PATH)
@@ -171,19 +180,22 @@ public class LogPeriodicAlertE2eTest {
await().atMost(Duration.ofSeconds(60))
.pollInterval(Duration.ofSeconds(3))
.untilAsserted(() -> assertFalse(capturedGroupAlerts.isEmpty(),
"Should have generated periodic error count group alert"));
.untilAsserted(() -> {
Optional<SingleAlert> matchedAlert = capturedGroupAlerts.stream()
.flatMap(List::stream)
.filter(alert -> alert.getLabels() != null)
.filter(alert -> String.valueOf(errorCountAlertByGroup.getId())
.equals(alert.getLabels().get(CommonConstants.LABEL_DEFINE_ID)))
.findFirst();
List<SingleAlert> groupAlerts = capturedGroupAlerts.get(0);
assertNotNull(groupAlerts, "Group alerts should not be null");
assertFalse(groupAlerts.isEmpty(), "Group alerts should not be empty");
SingleAlert anyAlert = groupAlerts.get(0);
assertEquals(CommonConstants.ALERT_STATUS_FIRING, anyAlert.getStatus(), "Alert should be in firing status");
assertNotNull(anyAlert.getLabels(), "Alert should have labels");
assertEquals(CommonConstants.ALERT_SEVERITY_CRITICAL, anyAlert.getLabels().get(CommonConstants.LABEL_ALERT_SEVERITY), "Alert should have critical severity");
assertTrue(anyAlert.getTriggerTimes() >= 1, "Alert should indicate aggregated trigger times");
assertTrue(matchedAlert.isPresent(), "Should have captured group alert from target alert define");
SingleAlert anyAlert = matchedAlert.get();
assertEquals(CommonConstants.ALERT_STATUS_FIRING, anyAlert.getStatus(), "Alert should be in firing status");
assertEquals(CommonConstants.ALERT_SEVERITY_CRITICAL,
anyAlert.getLabels().get(CommonConstants.LABEL_ALERT_SEVERITY),
"Alert should have critical severity");
assertTrue(anyAlert.getTriggerTimes() >= 1, "Alert should indicate aggregated trigger times");
});
}
/**
@@ -27,8 +27,8 @@ import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestInstance;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.mock.mockito.SpyBean;
import org.springframework.boot.test.web.server.LocalServerPort;
import org.springframework.test.context.bean.override.mockito.MockitoSpyBean;
import org.testcontainers.containers.GenericContainer;
import org.testcontainers.containers.Network;
import org.testcontainers.containers.wait.strategy.Wait;
@@ -64,7 +64,8 @@ public class LogRealTimeAlertE2eTest {
private static final int VECTOR_PORT = 8686;
private static final String VECTOR_CONFIG_PATH = "/etc/vector/vector.yml";
private static final String ENV_HERTZBEAT_PORT = "HERTZBEAT_PORT";
private static final Duration CONTAINER_STARTUP_TIMEOUT = Duration.ofSeconds(120);
private static final Duration CONTAINER_STARTUP_TIMEOUT = Duration.ofSeconds(180);
private static final Duration TEST_WAIT_TIMEOUT = Duration.ofSeconds(120);
@LocalServerPort
private int port;
@@ -72,18 +73,23 @@ public class LogRealTimeAlertE2eTest {
private final List<SingleAlert> capturedAlerts = new ArrayList<>();
private final ArrayList<List<SingleAlert>> capturedGroupAlerts = new ArrayList<>();
@SpyBean
@MockitoSpyBean
private AlarmCommonReduce alarmCommonReduce;
static GenericContainer<?> vector;
@BeforeAll
void setUpAll() {
void setUpAll() throws InterruptedException {
// Setup test alert definitions
setupTestAlertDefines();
// Expose host ports for testcontainers
Testcontainers.exposeHostPorts(port);
// Wait for HertzBeat to be fully ready before starting Vector
log.info("Waiting for HertzBeat to be fully ready on port {}...", port);
Thread.sleep(5000); // Give HertzBeat time to fully initialize
vector = new GenericContainer<>(DockerImageName.parse(VECTOR_IMAGE))
.withExposedPorts(VECTOR_PORT)
.withCopyFileToContainer(MountableFile.forClasspathResource("vector.yml"), VECTOR_CONFIG_PATH)
@@ -107,8 +113,8 @@ public class LogRealTimeAlertE2eTest {
capturedAlerts.clear();
// Wait for real alert to be generated through AlarmCommonReduce
await().atMost(Duration.ofSeconds(60))
.pollInterval(Duration.ofSeconds(2))
await().atMost(TEST_WAIT_TIMEOUT)
.pollInterval(Duration.ofSeconds(3))
.untilAsserted(() -> assertFalse(capturedAlerts.isEmpty(),
"Should have generated at least one alert for error logs"));
@@ -64,8 +64,13 @@ public class LogIngestionE2eTest {
static GenericContainer<?> vector;
@BeforeAll
void setUpAll() {
void setUpAll() throws InterruptedException {
Testcontainers.exposeHostPorts(port);
// Wait for HertzBeat to be fully ready before starting Vector
log.info("Waiting for HertzBeat to be fully ready on port {}...", port);
Thread.sleep(5000); // Give HertzBeat time to fully initialize
vector = new GenericContainer<>(DockerImageName.parse(VECTOR_IMAGE))
.withExposedPorts(VECTOR_PORT)
.withCopyFileToContainer(MountableFile.forClasspathResource("vector.yml"), VECTOR_CONFIG_PATH)
@@ -29,6 +29,10 @@ import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.web.server.LocalServerPort;
import org.springframework.test.context.DynamicPropertyRegistry;
import org.springframework.test.context.DynamicPropertySource;
import org.springframework.test.context.TestPropertySource;
import java.util.ArrayList;
import java.util.List;
import org.testcontainers.containers.GenericContainer;
import org.testcontainers.containers.Network;
import org.testcontainers.containers.wait.strategy.Wait;
@@ -37,8 +41,6 @@ import org.testcontainers.utility.DockerImageName;
import org.testcontainers.utility.MountableFile;
import java.time.Duration;
import java.util.ArrayList;
import java.util.List;
import static org.awaitility.Awaitility.await;
import static org.junit.jupiter.api.Assertions.assertFalse;
@@ -48,6 +50,10 @@ import static org.junit.jupiter.api.Assertions.assertNotNull;
* E2E tests for GreptimeDB log storage.
*/
@SpringBootTest(classes = org.apache.hertzbeat.startup.HertzBeatApplication.class, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@TestPropertySource(properties = {
"warehouse.store.duckdb.enabled=false",
"warehouse.store.greptime.enabled=true"
})
@Slf4j
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
public class GreptimeLogStorageE2eTest {
@@ -86,8 +92,6 @@ public class GreptimeLogStorageE2eTest {
@DynamicPropertySource
static void greptimeProps(DynamicPropertyRegistry r) {
r.add("warehouse.store.duckdb.enabled", () -> "false");
r.add("warehouse.store.greptime.enabled", () -> "true");
r.add("warehouse.store.greptime.http-endpoint", () -> "http://localhost:" + greptimedb.getMappedPort(GREPTIME_HTTP_PORT));
r.add("warehouse.store.greptime.grpc-endpoints", () -> "localhost:" + greptimedb.getMappedPort(GREPTIME_GRPC_PORT));
r.add("warehouse.store.greptime.username", () -> "");
@@ -96,10 +100,14 @@ public class GreptimeLogStorageE2eTest {
@BeforeAll
void setUpAll() {
void setUpAll() throws InterruptedException {
// Expose host ports for testcontainers
Testcontainers.exposeHostPorts(port);
// Wait for HertzBeat to be fully ready before starting Vector
log.info("Waiting for HertzBeat to be fully ready on port {}...", port);
Thread.sleep(5000); // Give HertzBeat time to fully initialize
vector = new GenericContainer<>(DockerImageName.parse(VECTOR_IMAGE))
.withExposedPorts(VECTOR_PORT)
.withCopyFileToContainer(MountableFile.forClasspathResource("vector.yml"), VECTOR_CONFIG_PATH)
@@ -114,6 +122,7 @@ public class GreptimeLogStorageE2eTest {
@Test
void testLogStorageToGreptimeDb() {
log.info("GreptimeDbDataStorage serverAvailable: {}", greptimeDbDataStorage.isServerAvailable());
List<LogEntry> capturedLogs = new ArrayList<>();
@@ -143,12 +152,24 @@ public class GreptimeLogStorageE2eTest {
assertNotNull(firstLog.getBody(), "Log body should not be null");
assertNotNull(firstLog.getSeverityText(), "Severity text should not be null");
// Directly write logs to GreptimeDB to test storage functionality
log.info("Directly writing {} captured logs to GreptimeDB", capturedLogs.size());
greptimeDbDataStorage.saveLogDataBatch(capturedLogs);
// Give some time for the write to complete
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
// Additional wait to ensure logs are persisted to GreptimeDB
await().atMost(Duration.ofSeconds(30))
.pollInterval(Duration.ofSeconds(2))
.untilAsserted(() -> {
// Query GreptimeDB directly to verify data persistence
List<LogEntry> storedLogs = queryStoredLogs();
log.info("Queried {} logs from GreptimeDB", storedLogs.size());
assertFalse(storedLogs.isEmpty(), "Should have logs stored in GreptimeDB");
});
}
@@ -157,10 +178,10 @@ public class GreptimeLogStorageE2eTest {
* Helper method to query stored logs directly from GreptimeDB
*/
private List<LogEntry> queryStoredLogs() {
long endTime = System.currentTimeMillis();
long startTime = endTime - Duration.ofMinutes(5).toMillis(); // Look back 5 minutes
return greptimeDbDataStorage.queryLogsByMultipleConditions(
startTime, endTime, null, null, null, null, null);
// Query without time condition to verify data exists
List<LogEntry> result = greptimeDbDataStorage.queryLogsByMultipleConditions(
null, null, null, null, null, null, null);
log.info("queryLogsByMultipleConditions returned {} entries", result.size());
return result;
}
}
@@ -96,7 +96,7 @@ sinks:
encoding:
codec: json
# Send to HertzBeat
# Send to HertzBeat with increased timeout and retry
emit_syslog:
inputs: [ "remap_syslog" ]
type: opentelemetry
@@ -114,4 +114,13 @@ sinks:
strategy: basic
user: admin
password: hertzbeat
# Increase timeout and retry settings for stability in CI environments
request:
timeout_secs: 60
retry_attempts: 10
retry_initial_backoff_secs: 2
retry_max_duration_secs: 120
# Batch settings for better throughput
batch:
max_bytes: 524288
timeout_secs: 5
+5
View File
@@ -42,6 +42,11 @@
<groupId>org.apache.hertzbeat</groupId>
<artifactId>hertzbeat-warehouse</artifactId>
</dependency>
<!-- hertzbeat common-core -->
<dependency>
<groupId>org.apache.hertzbeat</groupId>
<artifactId>hertzbeat-common-core</artifactId>
</dependency>
<!-- jpa -->
<dependency>
<groupId>org.springframework.boot</groupId>
@@ -17,8 +17,7 @@
package org.apache.hertzbeat.grafana.service;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import tools.jackson.databind.JsonNode;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.hertzbeat.base.dao.GeneralConfigDao;
@@ -77,8 +76,6 @@ public class DashboardService {
@Autowired
private GeneralConfigDao generalConfigDao;
private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();
/**
* Creates or updates a dashboard in Grafana.
* The "id" field will be removed from the dashboard JSON before sending
@@ -275,7 +272,10 @@ public class DashboardService {
try {
GeneralConfig config = generalConfigDao.findByType(GeneralConfigTypeEnum.system.name());
if (config != null && config.getContent() != null) {
JsonNode root = OBJECT_MAPPER.readTree(config.getContent());
JsonNode root = JsonUtil.fromJson(config.getContent());
if (root == null) {
return ThemeEnum.LIGHT.getValue();
}
JsonNode node = root.get("theme");
if (node != null && !node.isNull()) {
return ThemeEnum.convert(node.asText());
@@ -23,7 +23,7 @@ import static org.apache.hertzbeat.grafana.common.GrafanaConstants.CREATE_SERVIC
import static org.apache.hertzbeat.grafana.common.GrafanaConstants.CREATE_SERVICE_TOKEN_API;
import static org.apache.hertzbeat.grafana.common.GrafanaConstants.GET_SERVICE_ACCOUNTS_API;
import static org.apache.hertzbeat.grafana.common.GrafanaConstants.GRAFANA_CONFIG;
import com.fasterxml.jackson.databind.JsonNode;
import tools.jackson.databind.JsonNode;
import jakarta.annotation.PostConstruct;
import java.nio.charset.StandardCharsets;
+4 -4
View File
@@ -138,10 +138,10 @@
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<!-- database migration -->
<dependency>
<groupId>org.flywaydb</groupId>
<artifactId>flyway-core</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-flyway</artifactId>
</dependency>
<dependency>
<groupId>org.flywaydb</groupId>
<artifactId>flyway-mysql</artifactId>
@@ -0,0 +1,147 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.usthe.sureness.configuration;
import com.usthe.sureness.mgt.SecurityManager;
import com.usthe.sureness.processor.exception.DisabledAccountException;
import com.usthe.sureness.processor.exception.ExcessiveAttemptsException;
import com.usthe.sureness.processor.exception.ExpiredCredentialsException;
import com.usthe.sureness.processor.exception.IncorrectCredentialsException;
import com.usthe.sureness.processor.exception.NeedDigestInfoException;
import com.usthe.sureness.processor.exception.UnauthorizedException;
import com.usthe.sureness.processor.exception.UnknownAccountException;
import com.usthe.sureness.subject.SubjectSum;
import com.usthe.sureness.util.SurenessContextHolder;
import jakarta.servlet.Filter;
import jakarta.servlet.FilterChain;
import jakarta.servlet.FilterConfig;
import jakarta.servlet.ServletException;
import jakarta.servlet.ServletRequest;
import jakarta.servlet.ServletResponse;
import jakarta.servlet.http.HttpServletResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import java.io.IOException;
import java.io.PrintWriter;
/**
* Override the default servlet filter
*/
public class SurenessJakartaServletFilter implements Filter {
private final SecurityManager securityManager;
public SurenessJakartaServletFilter(SecurityManager securityManager) {
this.securityManager = securityManager;
}
/** logger **/
private static final Logger logger = LoggerFactory.getLogger(SurenessJakartaServletFilter.class);
private static final String UPGRADE = "Upgrade";
private static final String WEBSOCKET = "websocket";
@Override
public void init(FilterConfig filterConfig) {
logger.info("servlet surenessFilter initialized");
}
@Override
public void destroy() {
logger.info("servlet surenessFilter destroyed");
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse,
FilterChain filterChain)
throws IOException, ServletException {
try {
SubjectSum subject = securityManager.checkIn(servletRequest);
// You can consider using SurenessContextHolder to bind subject in threadLocal
// if bind, please remove it when end
if (subject != null) {
SurenessContextHolder.bindSubject(subject);
}
} catch (IncorrectCredentialsException | UnknownAccountException | ExpiredCredentialsException e1) {
logger.debug("this request account info is illegal, {}", e1.getMessage());
responseWrite(ResponseEntity
.status(HttpStatus.UNAUTHORIZED)
.body("Username or password is incorrect or token expired"), servletResponse);
return;
} catch (DisabledAccountException | ExcessiveAttemptsException e2) {
logger.debug("the account is disabled, {}", e2.getMessage());
responseWrite(ResponseEntity
.status(HttpStatus.UNAUTHORIZED).body("Account is disabled"), servletResponse);
return;
} catch (NeedDigestInfoException e3) {
logger.debug("you should try once again with digest auth information");
responseWrite(ResponseEntity
.status(HttpStatus.UNAUTHORIZED)
.header("WWW-Authenticate", e3.getAuthenticate()).build(), servletResponse);
return;
} catch (UnauthorizedException e4) {
logger.debug("this account can not access this resource, {}", e4.getMessage());
responseWrite(ResponseEntity
.status(HttpStatus.FORBIDDEN)
.body("This account has no permission to access this resource"), servletResponse);
return;
} catch (RuntimeException e) {
logger.error("other exception happen: ", e);
responseWrite(ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build(),
servletResponse);
return;
}
try {
// if ok, doFilter and add subject in request
filterChain.doFilter(servletRequest, servletResponse);
} finally {
int statusCode = ((HttpServletResponse) servletResponse).getStatus();
String upgrade = ((HttpServletResponse) servletResponse).getHeader(UPGRADE);
if (statusCode != HttpStatus.SWITCHING_PROTOCOLS.value() || !WEBSOCKET.equals(upgrade)) {
SurenessContextHolder.clear();
}
}
}
/**
* write response json data
* @param content content
* @param response response
*/
private static void responseWrite(ResponseEntity content, ServletResponse response) {
response.setCharacterEncoding("UTF-8");
((HttpServletResponse) response).setStatus(content.getStatusCode().value());
content.getHeaders().forEach((key, value) ->
((HttpServletResponse) response).addHeader(key, value.get(0)));
try (PrintWriter printWriter = response.getWriter()) {
if (content.getBody() != null) {
printWriter.write(content.getBody().toString());
} else {
printWriter.flush();
}
} catch (IOException e) {
logger.error("responseWrite response error: ", e);
}
}
}
@@ -1,47 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.hertzbeat.manager.component.listener;
import com.fasterxml.jackson.databind.ObjectMapper;
import jakarta.annotation.Resource;
import java.text.SimpleDateFormat;
import java.util.TimeZone;
import lombok.extern.slf4j.Slf4j;
import org.apache.hertzbeat.common.support.event.SystemConfigChangeEvent;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Component;
/**
* Listener for config Jackson timezone
*/
@Slf4j
@Component
public class TimeZoneListener {
@Resource
private ObjectMapper objectMapper;
@EventListener(SystemConfigChangeEvent.class)
public void onEvent(SystemConfigChangeEvent event) {
log.info("{} receive system config change event: {}.", this.getClass().getName(), event.getSource());
final SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSX");
simpleDateFormat.setTimeZone(TimeZone.getDefault());
objectMapper.setTimeZone(TimeZone.getDefault())
.setDateFormat(simpleDateFormat);
}
}
@@ -17,7 +17,7 @@
package org.apache.hertzbeat.manager.component.validator.impl;
import com.fasterxml.jackson.core.type.TypeReference;
import tools.jackson.core.type.TypeReference;
import org.apache.hertzbeat.common.entity.manager.Param;
import org.apache.hertzbeat.common.entity.manager.ParamDefine;
import org.apache.hertzbeat.common.util.JsonUtil;
@@ -26,7 +26,7 @@ import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.autoconfigure.template.TemplateAvailabilityProvider;
import org.springframework.boot.autoconfigure.template.TemplateAvailabilityProviders;
import org.springframework.boot.autoconfigure.web.WebProperties;
import org.springframework.boot.autoconfigure.web.servlet.error.ErrorViewResolver;
import org.springframework.boot.webmvc.autoconfigure.error.ErrorViewResolver;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.Ordered;
@@ -6,7 +6,7 @@
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
@@ -17,7 +17,6 @@
package org.apache.hertzbeat.manager.config;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.usthe.sureness.util.JsonWebTokenUtil;
import jakarta.annotation.Resource;
import java.security.SecureRandom;
@@ -29,6 +28,7 @@ import org.apache.commons.lang3.StringUtils;
import org.apache.hertzbeat.common.constants.CommonConstants;
import org.apache.hertzbeat.common.entity.manager.GeneralConfig;
import org.apache.hertzbeat.common.util.AesUtil;
import org.apache.hertzbeat.common.util.JsonUtil;
import org.apache.hertzbeat.common.util.TimeZoneUtil;
import org.apache.hertzbeat.base.dao.GeneralConfigDao;
import org.apache.hertzbeat.manager.pojo.dto.MuteConfig;
@@ -56,9 +56,9 @@ public class ConfigInitializer implements SmartLifecycle {
private boolean running = false;
private static final String DEFAULT_JWT_SECRET = "CyaFv0bwq2Eik0jdrKUtsA6bx3sDJeFV643R "
+ "LnfKefTjsIfJLBa2YkhEqEGtcHDTNe4CU6+9 "
+ "8tVt4bisXQ13rbN0oxhUZR73M6EByXIO+SV5 "
+ "dKhaX0csgOCTlCxq20yhmUea6H6JIpSE2Rwp";
+ "LnfKefTjsIfJLBa2YkhEqEGtcHDTNe4CU6+9 "
+ "8tVt4bisXQ13rbN0oxhUZR73M6EByXIO+SV5 "
+ "dKhaX0csgOCTlCxq20yhmUea6H6JIpSE2Rwp";
@Value("${sureness.jwt.secret:" + DEFAULT_JWT_SECRET + "}")
private String currentJwtSecret;
@@ -84,9 +84,6 @@ public class ConfigInitializer implements SmartLifecycle {
@Resource
protected GeneralConfigDao generalConfigDao;
@Resource
protected ObjectMapper objectMapper;
@SneakyThrows
public void initConfig() {
// for system config
@@ -96,19 +93,17 @@ public class ConfigInitializer implements SmartLifecycle {
final SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSX");
simpleDateFormat.setTimeZone(TimeZone.getDefault());
objectMapper.setTimeZone(TimeZone.getDefault())
.setDateFormat(simpleDateFormat);
} else {
// init system config data
systemConfig = SystemConfig.builder().timeZoneId(TimeZone.getDefault().getID()).theme("default")
.locale(Locale.getDefault().getLanguage() + CommonConstants.LOCALE_SEPARATOR
+ Locale.getDefault().getCountry())
.build();
String contentJson = objectMapper.writeValueAsString(systemConfig);
.locale(Locale.getDefault().getLanguage() + CommonConstants.LOCALE_SEPARATOR
+ Locale.getDefault().getCountry())
.build();
String contentJson = JsonUtil.toJson(systemConfig);
GeneralConfig generalConfig2Save = GeneralConfig.builder()
.type(systemGeneralConfigService.type())
.content(contentJson)
.build();
.type(systemGeneralConfigService.type())
.content(contentJson)
.build();
generalConfigDao.save(generalConfig2Save);
}
// for template config, flush the template config in db to memory
@@ -19,28 +19,35 @@ package org.apache.hertzbeat.manager.config;
import org.flywaydb.core.Flyway;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.autoconfigure.flyway.FlywayMigrationInitializer;
import org.springframework.boot.autoconfigure.flyway.FlywayProperties;
import org.springframework.boot.flyway.autoconfigure.FlywayMigrationInitializer;
import org.springframework.boot.flyway.autoconfigure.FlywayProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.DependsOn;
/**
* flyway database migration config
* Flyway database migration config.
* Delays Flyway execution until after Hibernate has created/updated the schema.
*/
@Configuration
@ConditionalOnProperty(prefix = "spring.flyway", name = "enabled", havingValue = "true")
public class FlywayConfiguration {
/**
* Disable the default FlywayMigrationInitializer by providing an empty callback.
*/
@Bean
public FlywayMigrationInitializer flywayInitializer(Flyway flyway) {
return new FlywayMigrationInitializer(flyway, (f) -> {
// Empty callback - we'll run migrations manually after Hibernate
});
}
static class Dummy {
}
/**
* Delayed Flyway migration that runs after EntityManagerFactory is initialized.
* This ensures Hibernate's ddl-auto runs first to create/update tables,
* then Flyway can perform additional migrations if needed.
*/
@Bean
@DependsOn("entityManagerFactory")
Dummy delayedFlywayInitializer(Flyway flyway, FlywayProperties flywayProperties) {
@@ -49,4 +56,7 @@ public class FlywayConfiguration {
}
return new Dummy();
}
static class Dummy {
}
}
@@ -6,7 +6,7 @@
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
@@ -17,39 +17,32 @@
package org.apache.hertzbeat.manager.config;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import java.text.SimpleDateFormat;
import java.util.TimeZone;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.autoconfigure.jackson.Jackson2ObjectMapperBuilderCustomizer;
import org.springframework.boot.jackson.autoconfigure.JsonMapperBuilderCustomizer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder;
import tools.jackson.databind.DeserializationFeature;
import java.text.SimpleDateFormat;
import java.util.TimeZone;
/**
* jackson config
* Jackson config.
*/
@Slf4j
@Configuration
public class JacksonConfig {
@Bean
public Jackson2ObjectMapperBuilderCustomizer jacksonCustomizer() {
public JsonMapperBuilderCustomizer jsonMapperBuilderCustomizer() {
return builder -> {
JavaTimeModule javaTimeModule = new JavaTimeModule();
final SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSX");
final String dateTimeFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSX";
final SimpleDateFormat simpleDateFormat = new SimpleDateFormat(dateTimeFormat);
simpleDateFormat.setTimeZone(TimeZone.getDefault());
builder.modules(javaTimeModule)
.timeZone(TimeZone.getDefault())
.dateFormat(simpleDateFormat);
builder.defaultTimeZone(TimeZone.getDefault());
builder.defaultDateFormat(simpleDateFormat);
builder.disable(DeserializationFeature.FAIL_ON_NULL_FOR_PRIMITIVES);
builder.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
};
}
@Bean
public ObjectMapper objectMapper(Jackson2ObjectMapperBuilder builder) {
return builder.build();
}
}
@@ -6,7 +6,7 @@
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
@@ -17,24 +17,25 @@
package org.apache.hertzbeat.manager.config;
import java.net.http.HttpClient;
import java.time.Duration;
import java.util.Collections;
import java.util.concurrent.TimeUnit;
import okhttp3.ConnectionPool;
import okhttp3.OkHttpClient;
import org.apache.hertzbeat.common.constants.NetworkConstants;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.client.ClientHttpRequestFactory;
import org.springframework.http.client.OkHttp3ClientHttpRequestFactory;
import org.springframework.http.client.JdkClientHttpRequestFactory;
import org.springframework.web.client.RestTemplate;
/**
* restTemplate config
* todo thread pool
* RestTemplate configuration using JDK native HttpClient for Spring 7.0.
*/
@Configuration
public class RestTemplateConfig {
/**
* Create RestTemplate with JDK native request factory and custom interceptors.
*/
@Bean
public RestTemplate restTemplate(ClientHttpRequestFactory factory) {
RestTemplate restTemplate = new RestTemplate(factory);
@@ -43,19 +44,17 @@ public class RestTemplateConfig {
}
@Bean
public ClientHttpRequestFactory simpleClientHttpRequestFactory() {
public ClientHttpRequestFactory clientHttpRequestFactory() {
HttpClient httpClient = HttpClient.newBuilder()
.connectTimeout(Duration.ofSeconds(NetworkConstants.HttpClientConstants.CONNECT_TIME_OUT))
.followRedirects(HttpClient.Redirect.NORMAL)
.build();
return new OkHttp3ClientHttpRequestFactory(
new OkHttpClient.Builder()
.readTimeout(NetworkConstants.HttpClientConstants.READ_TIME_OUT, TimeUnit.SECONDS)
.writeTimeout(NetworkConstants.HttpClientConstants.WRITE_TIME_OUT, TimeUnit.SECONDS)
.connectTimeout(NetworkConstants.HttpClientConstants.CONNECT_TIME_OUT, TimeUnit.SECONDS)
.connectionPool(new ConnectionPool(
NetworkConstants.HttpClientConstants.MAX_IDLE_CONNECTIONS,
NetworkConstants.HttpClientConstants.KEEP_ALIVE_TIMEOUT,
TimeUnit.SECONDS)
).build()
);
JdkClientHttpRequestFactory factory = new JdkClientHttpRequestFactory(httpClient);
factory.setReadTimeout(Duration.ofSeconds(NetworkConstants.HttpClientConstants.READ_TIME_OUT));
return factory;
}
}
@@ -17,14 +17,13 @@
package org.apache.hertzbeat.manager.service.impl;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.apache.hertzbeat.common.entity.manager.GeneralConfig;
import org.apache.hertzbeat.base.dao.GeneralConfigDao;
import org.apache.hertzbeat.base.service.GeneralConfigService;
import org.apache.hertzbeat.common.entity.manager.GeneralConfig;
import org.apache.hertzbeat.common.util.JsonUtil;
import org.springframework.transaction.annotation.Transactional;
import tools.jackson.core.type.TypeReference;
/**
* <p>Abstract implementation of GeneralConfigService, providing CRUD operations for configurations.</p>
@@ -34,61 +33,35 @@ abstract class AbstractGeneralConfigServiceImpl<T> implements GeneralConfigServi
protected final GeneralConfigDao generalConfigDao;
protected final ObjectMapper objectMapper;
/**
* <p>Constructor, passing in GeneralConfigDao, ObjectMapper and type.</p>
* @param generalConfigDao Dao object
* @param objectMapper JSON tool object
*/
protected AbstractGeneralConfigServiceImpl(GeneralConfigDao generalConfigDao, ObjectMapper objectMapper) {
protected AbstractGeneralConfigServiceImpl(GeneralConfigDao generalConfigDao) {
this.generalConfigDao = generalConfigDao;
this.objectMapper = objectMapper;
}
/**
* <p>Save a configuration.</p>
* @param config need to save configuration object
*/
@Transactional(rollbackFor = Exception.class)
@Override
public void saveConfig(T config) {
try {
String contentJson = objectMapper.writeValueAsString(config);
GeneralConfig generalConfig2Save = GeneralConfig.builder()
.type(type())
.content(contentJson)
.build();
generalConfigDao.save(generalConfig2Save);
log.info("Configuration saved successfully");
handler(getConfig());
} catch (JsonProcessingException e) {
throw new IllegalArgumentException("Configuration saved failed: " + e.getMessage());
String contentJson = JsonUtil.toJson(config);
if (contentJson == null) {
log.error("Failed to serialize configuration for type {}", type());
throw new RuntimeException("Save config failed: serialization error");
}
GeneralConfig generalConfig2Save = GeneralConfig.builder()
.type(type())
.content(contentJson)
.build();
generalConfigDao.save(generalConfig2Save);
log.info("Configuration of type {} saved successfully", type());
handler(getConfig());
}
/**
* <p>Get a configuration.</p>
* @return query configuration object
*/
@Override
public T getConfig() {
GeneralConfig generalConfig = generalConfigDao.findByType(type());
if (generalConfig == null) {
return null;
}
try {
return objectMapper.readValue(generalConfig.getContent(), getTypeReference());
} catch (JsonProcessingException e) {
throw new IllegalArgumentException("Get configuration failed: " + e.getMessage());
}
return JsonUtil.fromJson(generalConfig.getContent(), getTypeReference());
}
/**
* <p>Get TypeReference object of configuration type.</p>
* @return TypeReference object
*/
protected abstract TypeReference<T> getTypeReference();
}
@@ -6,7 +6,7 @@
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
@@ -32,7 +32,6 @@ import org.apache.hertzbeat.common.entity.manager.Param;
import org.apache.hertzbeat.common.entity.manager.ParamDefine;
import org.apache.hertzbeat.common.entity.message.CollectRep;
import org.apache.hertzbeat.common.support.SpringContextHolder;
import org.apache.hertzbeat.common.support.exception.CommonException;
import org.apache.hertzbeat.common.util.CommonUtil;
import org.apache.hertzbeat.common.util.HertzBeatKeywordsUtil;
import org.apache.hertzbeat.common.util.JexlCheckerUtil;
@@ -48,6 +47,7 @@ import org.apache.hertzbeat.manager.service.MonitorService;
import org.apache.hertzbeat.manager.service.ObjectStoreService;
import org.apache.hertzbeat.warehouse.service.WarehouseService;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.annotation.Lazy;
import org.springframework.context.event.EventListener;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
@@ -57,7 +57,6 @@ import org.springframework.util.Assert;
import org.springframework.util.StreamUtils;
import org.yaml.snakeyaml.Yaml;
import javax.annotation.Resource;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
@@ -89,26 +88,31 @@ public class AppServiceImpl implements AppService, InitializingBean {
private static final String PUSH_PROTOCOL_METRICS_NAME = "metrics";
@Resource
private MonitorDao monitorDao;
@Resource
private ObjectStoreConfigServiceImpl objectStoreConfigService;
@Resource
private ParamDao paramDao;
@Resource
private DefineDao defineDao;
@Resource
private WarehouseService warehouseService;
private final MonitorDao monitorDao;
private final ObjectStoreConfigServiceImpl objectStoreConfigService;
private final ParamDao paramDao;
private final DefineDao defineDao;
private final WarehouseService warehouseService;
private final Map<String, Job> appDefines = new ConcurrentHashMap<>();
private AppDefineStore appDefineStore;
private final AppDefineStore jarAppDefineStore = new JarAppDefineStoreImpl();
/**
* warehouseService is marked @Lazy to prevent potential circular dependencies.
*/
public AppServiceImpl(MonitorDao monitorDao,
ObjectStoreConfigServiceImpl objectStoreConfigService,
ParamDao paramDao,
DefineDao defineDao,
@Lazy WarehouseService warehouseService) {
this.monitorDao = monitorDao;
this.objectStoreConfigService = objectStoreConfigService;
this.paramDao = paramDao;
this.defineDao = defineDao;
this.warehouseService = warehouseService;
}
@Override
public List<ParamDefine> getAppParamDefines(String app) {
if (StringUtils.isNotBlank(app)){
@@ -132,8 +136,8 @@ public class AppServiceImpl implements AppService, InitializingBean {
if (PUSH_PROTOCOL_METRICS_NAME.equals(metric.getName())) {
List<Param> params = paramDao.findParamsByMonitorId(monitorId);
List<Configmap> configmaps = params.stream()
.map(param -> new Configmap(param.getField(), param.getParamValue(),
param.getType())).toList();
.map(param -> new Configmap(param.getField(), param.getParamValue(),
param.getType())).toList();
Map<String, Configmap> configmap = configmaps.stream().collect(Collectors.toMap(Configmap::getKey, item -> item, (key1, key2) -> key1));
CollectUtil.replaceFieldsForPushStyleMonitor(metric, configmap);
metricsTmp.add(metric);
@@ -145,7 +149,6 @@ public class AppServiceImpl implements AppService, InitializingBean {
@Override
public Job getAutoGenerateDynamicDefine(Long monitorId) {
// todo now only for prometheus
Job job = getAppDefine(DispatchConstants.PROTOCOL_PROMETHEUS);
List<CollectRep.MetricsData> metricsDataList = warehouseService.queryMonitorMetricsData(monitorId);
Metrics tmpMetrics = job.getMetrics().get(0);
@@ -153,18 +156,18 @@ public class AppServiceImpl implements AppService, InitializingBean {
for (CollectRep.MetricsData metricsData : metricsDataList) {
List<Metrics.Field> fields = metricsData.getFields().stream().map(item ->
Metrics.Field.builder()
.field(item.getName())
.type((byte) item.getType())
.label(item.getLabel())
.unit(item.getUnit())
.build())
.collect(Collectors.toList());
.field(item.getName())
.type((byte) item.getType())
.label(item.getLabel())
.unit(item.getUnit())
.build())
.collect(Collectors.toList());
Metrics metrics = Metrics.builder()
.visible(true)
.name(metricsData.getMetrics())
.fields(fields)
.prometheus(tmpMetrics.getPrometheus())
.build();
.visible(true)
.name(metricsData.getMetrics())
.fields(fields)
.prometheus(tmpMetrics.getPrometheus())
.build();
metricsList.add(metrics);
}
job.setMetrics(metricsList);
@@ -203,7 +206,7 @@ public class AppServiceImpl implements AppService, InitializingBean {
metricNames.addAll(appDefine.getMetrics().stream().map(Metrics::getName).toList());
} else {
appDefines.forEach((k, v) ->
metricNames.addAll(v.getMetrics().stream().map(Metrics::getName).toList()));
metricNames.addAll(v.getMetrics().stream().map(Metrics::getName).toList()));
}
return metricNames;
}
@@ -283,7 +286,6 @@ public class AppServiceImpl implements AppService, InitializingBean {
public List<Hierarchy> getAppHierarchy(String app, String lang) {
LinkedList<Hierarchy> hierarchies = new LinkedList<>();
Job job = appDefines.get(app.toLowerCase());
// TODO temporarily filter out push to solve the front-end problem, and open it after the subsequent design optimization
if (DispatchConstants.PROTOCOL_PUSH.equalsIgnoreCase(job.getApp())) {
return hierarchies;
}
@@ -313,17 +315,16 @@ public class AppServiceImpl implements AppService, InitializingBean {
hierarchyMetric.setValue(metricsData.getMetrics());
hierarchyMetric.setLabel(metricsData.getMetrics());
List<Hierarchy> hierarchyFieldList = metricsData.getFields().stream()
.map(item -> {
var hierarchyField = new Hierarchy();
hierarchyField.setValue(item.getName());
hierarchyField.setLabel(item.getName());
hierarchyField.setIsLeaf(true);
hierarchyField.setType((byte) item.getType());
hierarchyField.setUnit(item.getUnit());
return hierarchyField;
}).collect(Collectors.toList());
.map(item -> {
var hierarchyField = new Hierarchy();
hierarchyField.setValue(item.getName());
hierarchyField.setLabel(item.getName());
hierarchyField.setIsLeaf(true);
hierarchyField.setType((byte) item.getType());
hierarchyField.setUnit(item.getUnit());
return hierarchyField;
}).collect(Collectors.toList());
hierarchyMetric.setChildren(hierarchyFieldList);
// combine Hierarchy Metrics
combineHierarchyMetrics(hierarchyMetricList, hierarchyMetric);
}
}
@@ -344,7 +345,6 @@ public class AppServiceImpl implements AppService, InitializingBean {
var metricI18nName = CommonUtil.getLangMappingValueFromI18nMap(lang, field.getI18n());
hierarchyField.setLabel(metricI18nName != null ? metricI18nName : field.getField());
hierarchyField.setIsLeaf(true);
// for metric
hierarchyField.setType(field.getType());
hierarchyField.setUnit(field.getUnit());
hierarchyFieldList.add(hierarchyField);
@@ -361,15 +361,15 @@ public class AppServiceImpl implements AppService, InitializingBean {
private void combineHierarchyMetrics(List<Hierarchy> hierarchyMetricList, Hierarchy hierarchyMetric) {
Optional<Hierarchy> preHierarchyOptional = hierarchyMetricList.stream()
.filter(item -> item.getValue().equals(hierarchyMetric.getValue()))
.findFirst();
.filter(item -> item.getValue().equals(hierarchyMetric.getValue()))
.findFirst();
if (preHierarchyOptional.isPresent()) {
Hierarchy preHierarchy = preHierarchyOptional.get();
List<Hierarchy> children = preHierarchy.getChildren();
Set<String> childrenKey = children.stream()
.map(Hierarchy::getValue)
.collect(Collectors.toSet());
.map(Hierarchy::getValue)
.collect(Collectors.toSet());
for (Hierarchy child : hierarchyMetric.getChildren()) {
if (!childrenKey.contains(child.getValue())) {
@@ -408,18 +408,14 @@ public class AppServiceImpl implements AppService, InitializingBean {
log.error(e.getMessage());
throw new IllegalArgumentException("parse yml error: " + e.getMessage());
}
// app params verify
verifyDefineAppContent(app, isModify);
appDefineStore.save(app.getApp(), ymlContent);
// get and reset hide value
Job originalJob = appDefines.get(app.getApp().toLowerCase());
if (Objects.nonNull(originalJob)) {
boolean hide = originalJob.isHide();
app.setHide(hide);
}
appDefines.put(app.getApp().toLowerCase(), app);
// resolve: after the template is modified, all monitoring instances of the same type of template need to be reissued in the task status
SpringContextHolder.getBean(MonitorService.class).updateAppCollectJob(app);
}
@@ -442,7 +438,7 @@ public class AppServiceImpl implements AppService, InitializingBean {
}
if (!isModify) {
Assert.isNull(appDefines.get(app.getApp().toLowerCase()),
"monitoring template name " + app.getApp() + " already exists.");
"monitoring template name " + app.getApp() + " already exists.");
}
Set<String> fieldsSet = new HashSet<>(16);
for (Metrics metrics : app.getMetrics()) {
@@ -454,19 +450,19 @@ public class AppServiceImpl implements AppService, InitializingBean {
HertzBeatKeywordsUtil.verifyKeywords(field.getField());
if (fieldsSet.contains(field.getField())) {
throw new IllegalArgumentException(app.getApp() + " " + metrics.getName() + " "
+ field.getField() + " can not duplicated.");
+ field.getField() + " can not duplicated.");
}
if (JexlCheckerUtil.verifyKeywords(field.getField())) {
throw new IllegalArgumentException(app.getApp() + " " + metrics.getName() + " "
+ field.getField() + " prohibited keywords.");
+ field.getField() + " prohibited keywords.");
}
if (JexlCheckerUtil.verifyStartCharacter(field.getField())) {
throw new IllegalArgumentException(app.getApp() + " " + metrics.getName() + " "
+ field.getField() + " illegal start character.");
+ field.getField() + " illegal start character.");
}
if (JexlCheckerUtil.verifySpaces(field.getField())) {
throw new IllegalArgumentException(app.getApp() + " " + metrics.getName() + " "
+ field.getField() + " no spaces allowed.");
+ field.getField() + " no spaces allowed.");
}
fieldsSet.add(field.getField());
}
@@ -475,7 +471,6 @@ public class AppServiceImpl implements AppService, InitializingBean {
@Override
public void deleteMonitorDefine(String app) {
// if app has monitors now, delete failed
var monitors = monitorDao.findMonitorsByAppEquals(app);
if (monitors != null && !monitors.isEmpty()) {
throw new IllegalArgumentException("Can not delete define which has monitoring instances.");
@@ -508,6 +503,7 @@ public class AppServiceImpl implements AppService, InitializingBean {
@Override
public void afterPropertiesSet() throws Exception {
// Guaranteed to be non-null due to constructor injection
var objectStoreConfig = objectStoreConfigService.getConfig();
refreshStore(objectStoreConfig);
}
@@ -517,11 +513,6 @@ public class AppServiceImpl implements AppService, InitializingBean {
refreshStore(event.getConfig());
}
/**
* flush config store
*
* @param objectStoreConfig file service configuration
*/
private void refreshStore(ObjectStoreDTO<?> objectStoreConfig) {
if (objectStoreConfig == null) {
appDefineStore = new DatabaseAppDefineStoreImpl();
@@ -535,7 +526,6 @@ public class AppServiceImpl implements AppService, InitializingBean {
}
}
jarAppDefineStore.loadAppDefines();
// merge define yml files inside jars
appDefineStore.loadAppDefines();
}
@@ -561,7 +551,6 @@ public class AppServiceImpl implements AppService, InitializingBean {
}
private class JarAppDefineStoreImpl implements AppDefineStore {
@Override
public boolean loadAppDefines() {
try {
@@ -575,7 +564,6 @@ public class AppServiceImpl implements AppService, InitializingBean {
appDefines.put(app.getApp().toLowerCase(), app);
} catch (IOException e) {
log.error(e.getMessage(), e);
log.error("Ignore this template file: {}.", resource.getFilename());
}
}
return true;
@@ -587,8 +575,6 @@ public class AppServiceImpl implements AppService, InitializingBean {
@Override
public String loadAppDefine(String app) {
// load define app yml in jar
log.info("load define app yml in internal jar");
var resolver = new PathMatchingResourcePatternResolver();
var resource = resolver.getResource("classpath:define/app-" + app + ".yml");
try (var inputStream = resource.getInputStream()) {
@@ -606,51 +592,25 @@ public class AppServiceImpl implements AppService, InitializingBean {
@Override
public void delete(String app) {
throw new UnsupportedOperationException("define yml inside jars cannot be deleted");
throw new UnsupportedOperationException();
}
}
private class LocalFileAppDefineStoreImpl implements AppDefineStore {
@Override
public boolean loadAppDefines() {
var rootUrl = this.getClass().getClassLoader().getResource("");
if (rootUrl == null) {
return false;
}
var classpath = rootUrl.getPath();
var defineAppPath = classpath + "define";
var directory = new File(defineAppPath);
if (!directory.exists() || directory.listFiles() == null) {
rootUrl = this.getClass().getResource(File.separator);
if (rootUrl == null) {
return false;
}
classpath = rootUrl.getPath();
defineAppPath = classpath + "define";
directory = new File(defineAppPath);
if (!directory.exists() || directory.listFiles() == null) {
return false;
}
}
log.info("load define path {}", defineAppPath);
if (rootUrl == null) return false;
var directory = new File(rootUrl.getPath() + "define");
if (!directory.exists()) return false;
Yaml yaml = new Yaml();
for (var appFile : Objects.requireNonNull(directory.listFiles())) {
if (appFile.exists() && appFile.isFile()) {
if (appFile.isHidden()
|| (!appFile.getName().endsWith("yml") && !appFile.getName().endsWith("yaml"))) {
log.error("Ignore this template file: {}.", appFile.getName());
continue;
}
try (var fileInputStream = new FileInputStream(appFile)) {
var app = yaml.loadAs(fileInputStream, Job.class);
if (app != null) {
appDefines.put(app.getApp().toLowerCase(), app);
}
} catch (IOException e) {
log.error(e.getMessage(), e);
log.error("Ignore this template file: {}.", appFile.getName());
if (appFile.isFile() && (appFile.getName().endsWith("yml") || appFile.getName().endsWith("yaml"))) {
try (var is = new FileInputStream(appFile)) {
var app = yaml.loadAs(is, Job.class);
if (app != null) appDefines.put(app.getApp().toLowerCase(), app);
} catch (Exception e) {
log.error(e.getMessage());
}
}
}
@@ -659,132 +619,93 @@ public class AppServiceImpl implements AppService, InitializingBean {
@Override
public String loadAppDefine(String app) {
var classpath = Objects.requireNonNull(this.getClass().getClassLoader().getResource("")).getPath();
var defineAppPath = classpath + "define" + File.separator + "app-" + app + ".yml";
var defineAppFile = new File(defineAppPath);
if (defineAppFile.exists() && defineAppFile.isFile()) {
log.info("load {} define app yml in file: {}", app, defineAppPath);
try {
return FileUtils.readFileToString(defineAppFile, StandardCharsets.UTF_8);
} catch (Exception e) {
log.error(e.getMessage());
}
var rootUrl = this.getClass().getClassLoader().getResource("");
if (rootUrl == null) return null;
var file = new File(rootUrl.getPath() + "define" + File.separator + "app-" + app + ".yml");
try {
return file.exists() ? FileUtils.readFileToString(file, StandardCharsets.UTF_8) : null;
} catch (Exception e) {
return null;
}
return null;
}
@Override
public void save(String app, String ymlContent) {
var classpath = Objects.requireNonNull(this.getClass().getClassLoader().getResource("")).getPath();
var defineAppPath = classpath + "define" + File.separator + "app-" + app + ".yml";
var defineAppFile = new File(defineAppPath);
var rootUrl = this.getClass().getClassLoader().getResource("");
if (rootUrl == null) return;
var file = new File(rootUrl.getPath() + "define" + File.separator + "app-" + app + ".yml");
try {
FileUtils.writeStringToFile(defineAppFile, ymlContent, StandardCharsets.UTF_8, false);
FileUtils.writeStringToFile(file, ymlContent, StandardCharsets.UTF_8, false);
} catch (Exception e) {
log.error(e.getMessage());
throw new RuntimeException("flush file " + defineAppPath + " error: " + e.getMessage());
throw new RuntimeException(e);
}
}
@Override
public void delete(String app) {
var classpath = Objects.requireNonNull(this.getClass().getClassLoader().getResource("")).getPath();
var defineAppPath = classpath + "define" + File.separator + "app-" + app + ".yml";
var defineAppFile = new File(defineAppPath);
if (!defineAppFile.exists() && appDefines.containsKey(app.toLowerCase())){
throw new CommonException("the app define file is not in current file server provider");
}
if (defineAppFile.exists() && defineAppFile.isFile()) {
defineAppFile.delete();
}
var rootUrl = this.getClass().getClassLoader().getResource("");
if (rootUrl == null) return;
var file = new File(rootUrl.getPath() + "define" + File.separator + "app-" + app + ".yml");
if (file.exists()) file.delete();
appDefines.remove(app.toLowerCase());
}
}
private class ObjectStoreAppDefineStoreImpl implements AppDefineStore {
@Override
public boolean loadAppDefines() {
var objectStoreService = getObjectStoreService();
Yaml yaml = new Yaml();
objectStoreService.list("define")
.forEach(it -> {
if (it.getInputStream() != null) {
var app = yaml.loadAs(it.getInputStream(), Job.class);
if (app != null) {
appDefines.put(app.getApp().toLowerCase(), app);
}
}
});
objectStoreService.list("define").forEach(it -> {
if (it.getInputStream() != null) {
var app = yaml.loadAs(it.getInputStream(), Job.class);
if (app != null) appDefines.put(app.getApp().toLowerCase(), app);
}
});
return true;
}
@Override
public String loadAppDefine(String app) {
var objectStoreService = getObjectStoreService();
var file = objectStoreService.download(getDefineAppPath(app));
if (isNull(file)) {
return null;
}
var file = objectStoreService.download("define/app-" + app + ".yml");
try {
return IOUtils.toString(file.getInputStream(), StandardCharsets.UTF_8);
return file != null ? IOUtils.toString(file.getInputStream(), StandardCharsets.UTF_8) : null;
} catch (IOException e) {
log.error("load app define from object store service error", e);
return null;
}
}
@Override
public void save(String app, String ymlContent) {
var objectStoreService = getObjectStoreService();
objectStoreService.upload(getDefineAppPath(app), IOUtils.toInputStream(ymlContent, StandardCharsets.UTF_8));
getObjectStoreService().upload("define/app-" + app + ".yml", IOUtils.toInputStream(ymlContent, StandardCharsets.UTF_8));
}
@Override
public void delete(String app) {
var objectStoreService = getObjectStoreService();
String defineAppPath = getDefineAppPath(app);
boolean exist = objectStoreService.isExist(defineAppPath);
if (!exist && appDefines.containsKey(app.toLowerCase())){
throw new CommonException("the app define file is not in current file server provider");
}
if (exist){
objectStoreService.remove(defineAppPath);
}
getObjectStoreService().remove("define/app-" + app + ".yml");
appDefines.remove(app.toLowerCase());
}
private ObjectStoreService getObjectStoreService() {
return SpringContextHolder.getBean(ObsObjectStoreServiceImpl.class);
}
private String getDefineAppPath(String app) {
return "define/app-" + app + ".yml";
}
}
private class DatabaseAppDefineStoreImpl implements AppDefineStore {
@Override
public boolean loadAppDefines() {
Yaml yaml = new Yaml();
List<Define> defines = defineDao.findAll();
for (Define define : defines) {
defineDao.findAll().forEach(define -> {
var app = yaml.loadAs(define.getContent(), Job.class);
if (app != null){
appDefines.put(define.getApp().toLowerCase(), app);
}
}
if (app != null) appDefines.put(define.getApp().toLowerCase(), app);
});
return true;
}
@Override
public String loadAppDefine(String app) {
Optional<Define> defineOptional = defineDao.findById(app);
return defineOptional.map(Define::getContent).orElse(null);
return defineDao.findById(app).map(Define::getContent).orElse(null);
}
@Override
@@ -797,13 +718,7 @@ public class AppServiceImpl implements AppService, InitializingBean {
@Override
public void delete(String app) {
Optional<Define> defineOptional = defineDao.findById(app);
if (defineOptional.isEmpty() && appDefines.containsKey(app.toLowerCase())){
throw new CommonException("the app define file is not in current file server provider");
}
if (defineOptional.isPresent()){
defineDao.deleteById(app);
}
defineDao.deleteById(app);
appDefines.remove(app.toLowerCase());
}
}
@@ -19,7 +19,6 @@ package org.apache.hertzbeat.manager.service.impl;
import static org.apache.hertzbeat.common.constants.ExportFileConstants.ExcelFile.FILE_SUFFIX;
import static org.apache.hertzbeat.common.constants.ExportFileConstants.ExcelFile.TYPE;
import com.fasterxml.jackson.core.type.TypeReference;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
@@ -45,6 +44,7 @@ import org.apache.poi.ss.usermodel.WorkbookFactory;
import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.ss.util.RegionUtil;
import org.springframework.stereotype.Service;
import tools.jackson.core.type.TypeReference;
/**
* Configure the import and export EXCEL format
@@ -5,7 +5,9 @@
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -17,44 +19,35 @@ package org.apache.hertzbeat.manager.service.impl;
import static org.apache.hertzbeat.common.constants.ExportFileConstants.JsonFile.FILE_SUFFIX;
import static org.apache.hertzbeat.common.constants.ExportFileConstants.JsonFile.TYPE;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.io.IOException;
import org.apache.hertzbeat.common.util.JsonUtil;
import org.springframework.stereotype.Service;
import tools.jackson.core.type.TypeReference;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.List;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
/**
* Configure the import and export JSON format
*/
@Slf4j
@RequiredArgsConstructor
@Service
public class JsonImExportServiceImpl extends AbstractImExportServiceImpl {
private final ObjectMapper objectMapper;
@Override
public List<ExportMonitorDTO> parseImport(InputStream is) {
try {
return objectMapper.readValue(is, new TypeReference<>(){});
} catch (IOException ex) {
log.error("import monitor failed.", ex);
throw new RuntimeException("import monitor failed");
List<ExportMonitorDTO> result = JsonUtil.fromJson(is, new TypeReference<List<ExportMonitorDTO>>(){});
if (result == null) {
throw new RuntimeException("Parse JSON failed");
}
return result;
}
@Override
public void writeOs(List<ExportMonitorDTO> monitorList, OutputStream os) {
try {
objectMapper.writeValue(os, monitorList);
} catch (IOException ex) {
log.error("export monitor failed.", ex);
throw new RuntimeException("export monitor failed");
}
JsonUtil.toJson(monitorList, os);
}
@Override
@@ -17,8 +17,7 @@
package org.apache.hertzbeat.manager.service.impl;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import tools.jackson.core.type.TypeReference;
import java.lang.reflect.Type;
import org.apache.hertzbeat.common.constants.GeneralConfigTypeEnum;
import org.apache.hertzbeat.base.dao.GeneralConfigDao;
@@ -33,16 +32,8 @@ import org.springframework.stereotype.Service;
@Service
public class MailGeneralConfigServiceImpl extends AbstractGeneralConfigServiceImpl<MailServerConfig> {
/**
* MailGeneralConfigServiceImpl's constructor creates an instance of this class
* through the default constructor or deserialization construction (setBeanProps).
* The parameter generalConfigDao is used for dao layer operation data,
* and objectMapper is used for object mapping.
* @param generalConfigDao dao layer operation data, needed to create an instance of this class
* @param objectMapper object mapping , needed to create an instance of this class
*/
public MailGeneralConfigServiceImpl(GeneralConfigDao generalConfigDao, ObjectMapper objectMapper) {
super(generalConfigDao, objectMapper);
public MailGeneralConfigServiceImpl(GeneralConfigDao generalConfigDao) {
super(generalConfigDao);
}
@Override
@@ -17,8 +17,7 @@
package org.apache.hertzbeat.manager.service.impl;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import tools.jackson.core.type.TypeReference;
import java.lang.reflect.Type;
import org.apache.hertzbeat.common.entity.dto.ModelProviderConfig;
import org.apache.hertzbeat.base.dao.GeneralConfigDao;
@@ -35,15 +34,8 @@ public class ModelProviderConfigServiceImpl extends AbstractGeneralConfigService
private final ApplicationContext applicationContext;
/**
*
* <p>Constructor, passing in GeneralConfigDao, ObjectMapper and type.</p>
*
* @param generalConfigDao ConfigDao object
* @param objectMapper JSON tool object
*/
public ModelProviderConfigServiceImpl(ApplicationContext applicationContext, GeneralConfigDao generalConfigDao, ObjectMapper objectMapper) {
super(generalConfigDao, objectMapper);
public ModelProviderConfigServiceImpl(ApplicationContext applicationContext, GeneralConfigDao generalConfigDao) {
super(generalConfigDao);
this.applicationContext = applicationContext;
}
@@ -18,8 +18,7 @@
package org.apache.hertzbeat.manager.service.impl;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import tools.jackson.core.type.TypeReference;
import java.lang.reflect.Type;
import lombok.extern.slf4j.Slf4j;
import org.apache.hertzbeat.base.dao.GeneralConfigDao;
@@ -37,14 +36,8 @@ import org.springframework.stereotype.Service;
@Slf4j
public class MuteGeneralConfigServiceImpl extends AbstractGeneralConfigServiceImpl<MuteConfig> {
/**
* <p>Constructor, passing in GeneralConfigDao, ObjectMapper and type.</p>
*
* @param generalConfigDao Dao object
* @param objectMapper JSON tool object
*/
protected MuteGeneralConfigServiceImpl(GeneralConfigDao generalConfigDao, ObjectMapper objectMapper) {
super(generalConfigDao, objectMapper);
protected MuteGeneralConfigServiceImpl(GeneralConfigDao generalConfigDao) {
super(generalConfigDao);
}
/**
@@ -17,12 +17,12 @@
package org.apache.hertzbeat.manager.service.impl;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import tools.jackson.core.type.TypeReference;
import com.obs.services.ObsClient;
import lombok.extern.slf4j.Slf4j;
import org.apache.hertzbeat.common.constants.GeneralConfigTypeEnum;
import org.apache.hertzbeat.base.dao.GeneralConfigDao;
import org.apache.hertzbeat.common.util.JsonUtil;
import org.apache.hertzbeat.manager.pojo.dto.ObjectStoreConfigChangeEvent;
import org.apache.hertzbeat.manager.pojo.dto.ObjectStoreDTO;
import org.springframework.beans.factory.InitializingBean;
@@ -33,7 +33,7 @@ import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;
import javax.annotation.Resource;
import jakarta.annotation.Resource;
import java.lang.reflect.Type;
import java.net.URL;
@@ -52,14 +52,8 @@ public class ObjectStoreConfigServiceImpl extends
@Resource
private ApplicationContext ctx;
/**
* <p>Constructor, passing in GeneralConfigDao, ObjectMapper and type.</p>
*
* @param generalConfigDao configDao object
* @param objectMapper JSON tool object
*/
public ObjectStoreConfigServiceImpl(GeneralConfigDao generalConfigDao, ObjectMapper objectMapper) {
super(generalConfigDao, objectMapper);
public ObjectStoreConfigServiceImpl(GeneralConfigDao generalConfigDao) {
super(generalConfigDao);
}
@Override
@@ -94,7 +88,7 @@ public class ObjectStoreConfigServiceImpl extends
* init Huawei Cloud OBS
*/
private void initObs(ObjectStoreDTO<ObjectStoreDTO.ObsConfig> config) {
var obsConfig = objectMapper.convertValue(config.getConfig(), ObjectStoreDTO.ObsConfig.class);
var obsConfig = JsonUtil.convertValue(config.getConfig(), ObjectStoreDTO.ObsConfig.class);
Assert.hasText(obsConfig.getAccessKey(), "cannot find obs accessKey");
Assert.hasText(obsConfig.getSecretKey(), "cannot find obs secretKey");
Assert.hasText(obsConfig.getEndpoint(), "cannot find obs endpoint");
@@ -114,7 +108,7 @@ public class ObjectStoreConfigServiceImpl extends
/**
* Verify Huawei Cloud OBS endpoint domain name
* Only myhuaweicloud.com domain name is allowed
* Refer: https://console-intl.huaweicloud.com/apiexplorer/#/endpoint
* Refer: <a href="https://console-intl.huaweicloud.com/apiexplorer/#/endpoint">...</a>
*/
public void validateObsEndpoint(String endpoint) {
try {
@@ -17,6 +17,7 @@
package org.apache.hertzbeat.manager.service.impl;
import jakarta.annotation.PostConstruct;
import jakarta.persistence.criteria.Predicate;
import java.io.File;
import java.io.FileOutputStream;
@@ -45,7 +46,6 @@ import java.util.function.Consumer;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import java.util.stream.Collectors;
import javax.annotation.PostConstruct;
import lombok.RequiredArgsConstructor;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
@@ -17,8 +17,7 @@
package org.apache.hertzbeat.manager.service.impl;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import tools.jackson.core.type.TypeReference;
import java.lang.reflect.Type;
import jakarta.annotation.Resource;
@@ -40,16 +39,8 @@ public class SmsGeneralConfigServiceImpl extends AbstractGeneralConfigServiceImp
@Resource
private ApplicationContext applicationContext;
/**
* SmsGeneralConfigServiceImpl's constructor creates an instance of this class
* through the default constructor or deserialization construction (setBeanProps).
* The parameter generalConfigDao is used for dao layer operation data,
* and objectMapper is used for object mapping.
* @param generalConfigDao dao layer operation data, needed to create an instance of this class
* @param objectMapper object mapping , needed to create an instance of this class
*/
public SmsGeneralConfigServiceImpl(GeneralConfigDao generalConfigDao, ObjectMapper objectMapper) {
super(generalConfigDao, objectMapper);
public SmsGeneralConfigServiceImpl(GeneralConfigDao generalConfigDao) {
super(generalConfigDao);
}
/**
@@ -17,8 +17,7 @@
package org.apache.hertzbeat.manager.service.impl;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import tools.jackson.core.type.TypeReference;
import jakarta.annotation.Resource;
import java.lang.reflect.Type;
import java.util.Objects;
@@ -38,15 +37,8 @@ public class SystemGeneralConfigServiceImpl extends AbstractGeneralConfigService
@Resource
private ApplicationContext applicationContext;
/**
*
* <p>Constructor, passing in GeneralConfigDao, ObjectMapper and type.</p>
*
* @param generalConfigDao ConfigDao object
* @param objectMapper JSON tool object
*/
public SystemGeneralConfigServiceImpl(GeneralConfigDao generalConfigDao, ObjectMapper objectMapper) {
super(generalConfigDao, objectMapper);
public SystemGeneralConfigServiceImpl(GeneralConfigDao generalConfigDao) {
super(generalConfigDao);
}
@Override
@@ -17,13 +17,12 @@
package org.apache.hertzbeat.manager.service.impl;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.lang.reflect.Type;
import org.apache.hertzbeat.common.constants.GeneralConfigTypeEnum;
import org.apache.hertzbeat.base.dao.GeneralConfigDao;
import org.apache.hertzbeat.manager.pojo.dto.SystemSecret;
import org.springframework.stereotype.Service;
import tools.jackson.core.type.TypeReference;
/**
* system config service impl
@@ -31,15 +30,8 @@ import org.springframework.stereotype.Service;
@Service
public class SystemSecretServiceImpl extends AbstractGeneralConfigServiceImpl<SystemSecret> {
/**
*
* <p>Constructor, passing in GeneralConfigDao, ObjectMapper and type.</p>
*
* @param generalConfigDao ConfigDao object
* @param objectMapper JSON tool object
*/
public SystemSecretServiceImpl(GeneralConfigDao generalConfigDao, ObjectMapper objectMapper) {
super(generalConfigDao, objectMapper);
public SystemSecretServiceImpl(GeneralConfigDao generalConfigDao) {
super(generalConfigDao);
}
@Override
@@ -17,8 +17,7 @@
package org.apache.hertzbeat.manager.service.impl;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import tools.jackson.core.type.TypeReference;
import jakarta.annotation.Resource;
import java.lang.reflect.Type;
import org.apache.hertzbeat.common.constants.GeneralConfigTypeEnum;
@@ -36,15 +35,8 @@ public class TemplateConfigServiceImpl extends AbstractGeneralConfigServiceImpl<
@Resource
private AppService appService;
/**
*
* <p>Constructor, passing in GeneralConfigDao, ObjectMapper and type.</p>
*
* @param generalConfigDao configDao object
* @param objectMapper JSON tool object
*/
public TemplateConfigServiceImpl(GeneralConfigDao generalConfigDao, ObjectMapper objectMapper) {
super(generalConfigDao, objectMapper);
public TemplateConfigServiceImpl(GeneralConfigDao generalConfigDao) {
super(generalConfigDao);
}
@Override
@@ -22,7 +22,7 @@ import static org.apache.hertzbeat.common.constants.CommonConstants.FAIL_CODE;
import static org.apache.hertzbeat.common.constants.CommonConstants.MONITOR_CONFLICT_CODE;
import static org.apache.hertzbeat.common.constants.CommonConstants.PARAM_INVALID_CODE;
import java.util.Objects;
import javax.validation.ConstraintViolationException;
import jakarta.validation.ConstraintViolationException;
import lombok.extern.slf4j.Slf4j;
import org.apache.hertzbeat.common.entity.dto.Message;
import org.apache.hertzbeat.common.support.exception.CommonException;
@@ -1,75 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.hertzbeat.manager.component.listener;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.text.SimpleDateFormat;
import java.util.TimeZone;
import org.apache.hertzbeat.common.support.event.SystemConfigChangeEvent;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import org.springframework.test.util.ReflectionTestUtils;
/**
* test case for {@link TimeZoneListener}
*/
@ExtendWith(MockitoExtension.class)
class TimeZoneListenerTest {
@Mock
private ObjectMapper objectMapper;
@InjectMocks
private TimeZoneListener timeZoneListener;
@Mock
private SystemConfigChangeEvent event;
@BeforeEach
void setUp() {
ReflectionTestUtils.setField(timeZoneListener, "objectMapper", objectMapper);
}
@Test
void testOnEvent() {
when(objectMapper.setTimeZone(any(TimeZone.class))).thenReturn(objectMapper);
when(objectMapper.setDateFormat(any(SimpleDateFormat.class))).thenReturn(objectMapper);
Object eventSource = new Object();
when(event.getSource()).thenReturn(eventSource);
timeZoneListener.onEvent(event);
SimpleDateFormat expectedDateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSX");
expectedDateFormat.setTimeZone(TimeZone.getDefault());
verify(objectMapper).setTimeZone(TimeZone.getDefault());
verify(objectMapper).setDateFormat(expectedDateFormat);
}
}
@@ -91,7 +91,7 @@ class GeneralConfigControllerTest {
mockMvc.perform(put("/api/config/template/appName")
.contentType(MediaType.APPLICATION_JSON)
.content("{\"templateKey\":\"templateValue\"}"))
.content("{\"templateKey\":\"templateValue\",\"hide\":true}"))
.andExpect(status().isOk())
.andExpect(jsonPath("$.code").value((int) CommonConstants.SUCCESS_CODE));
}
@@ -125,7 +125,7 @@ class StatusPageControllerTest {
mockMvc.perform(post("/api/status/page/component")
.contentType(MediaType.APPLICATION_JSON)
.content("{\"name\":\"New Component\"}")
.content("{\"name\":\"New Component\",\"method\":0,\"configState\":0,\"state\":0}")
.accept(MediaType.APPLICATION_JSON))
.andExpect(status().isOk())
.andExpect(jsonPath("$.code").value((int) CommonConstants.SUCCESS_CODE))
@@ -137,7 +137,7 @@ class StatusPageControllerTest {
mockMvc.perform(put("/api/status/page/component")
.contentType(MediaType.APPLICATION_JSON)
.content("{\"name\":\"Updated Component\"}")
.content("{\"name\":\"Updated Component\",\"method\":0,\"configState\":0,\"state\":0}")
.accept(MediaType.APPLICATION_JSON))
.andExpect(status().isOk())
.andExpect(jsonPath("$.code").value((int) CommonConstants.SUCCESS_CODE))

Some files were not shown because too many files have changed in this diff Show More