Merge branch 'opengoofy:develop' into develop

pull/822/head
WuLang 3 years ago committed by GitHub
commit de8402b6b9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -21,7 +21,7 @@
on:
push:
branches:
- develop
- main
jobs:
contrib-readme-job:

@ -0,0 +1,56 @@
<img align="center" width="400" alt="image" src="https://user-images.githubusercontent.com/77398366/181906454-b46f6a14-7c2c-4b8f-8b0a-40432521bed8.png">
# Dynamic and observable thread pool framework
[![Gitee](https://gitee.com/itmachen/hippo4j/badge/star.svg?theme=gvp)](https://gitee.com/itmachen/hippo4j) [![GitHub](https://img.shields.io/github/stars/opengoofy/hippo4j)](https://github.com/opengoofy/hippo4j) [![Docker Pulls](https://img.shields.io/docker/pulls/hippo4j/hippo4j-server.svg)](https://store.docker.com/community/images/hippo4j/hippo4j-server) [![Contributors](https://img.shields.io/github/contributors/opengoofy/hippo4j?color=3ba272)](https://github.com/opengoofy/hippo4j/graphs/contributors) [![License](https://img.shields.io/github/license/opengoofy/hippo4j?color=5470c6)](https://github.com/opengoofy/hippo4j/blob/develop/LICENSE)
-------
## Thread pool pain points
A thread pool is a tool for managing threads based on the idea of pooling.
Using a thread pool reduces the overhead of creating and destroying threads and avoids running out of system resources due to too many threads.
The use of thread pools is essential in highly concurrent and high-volume task processing scenarios.
If you have actually used thread pools in your projects, I believe you may have encountered the following pain points:
- Thread pools are defined randomly, with too many thread resources, causing high server load.
- The thread pool parameters are not easily evaluated and the business is at risk of failure.
- Thread pool task execution time exceeds the average execution cycle and developers are not informed.
- Thread pool tasks pile up and affect business operations.
- Wireless process pool monitoring when the service has timeouts, meltdowns, and other problems.
- Thread pools do not support the passing of runtime variables, such as MDC contexts.
- When a project is closed, a large number of running thread pool tasks are discarded.
- Thread pool running, task execution stopped, don't know the problem.
## What is Hippo-4J
Hippo-4J through the JDK thread pool enhancements, as well as extending the three-party framework underlying thread pools and other features for business systems to improve online operational security capabilities.
The following functional support is provided:
- Global Control - Managing Application Thread Pool Instances.
- Dynamic changes - dynamically changing thread pool parameters at application runtime.
- Notify alarms - Four built-in alarm notification policies.
- Run Monitoring - Real-time view of thread pool runtime data.
- Feature extensions - support for thread pooling task passing contexts, etc.
- Multiple Modes - Two built-in usage modes: Configuration Center Mode and No Middleware Mode.
- Container Management - Tomcat, Jetty, Undertow container thread pool runtime view and thread count changes.
- Framework adaptation - Dubbo, Hystrix, Polaris, RabbitMQ, RocketMQ and other consumer thread pool runtime data view and thread count changes.
## Quick Start
For local presentation purposes, see [Quick start](https://hippo4j.cn/docs/user_docs/user_guide/quick-start).
Demo Environment: [http://console.hippo4j.cn/index.html](http://console.hippo4j.cn/index.html).
## Who is using
More companies with access are welcome to register at [registration address](https://github.com/opengoofy/hippo4j/issues/13), registration is only for product promotion.
## Contributors
Thanks to all the developers who contributed to the project. If interested in contributing, refer to [good first issue](https://github.com/opengoofy/hippo4j/issues?q=is%3Aopen+is%3Aissue+label%3A%22good+first+issue%22).

@ -1,5 +1,7 @@
<img align="center" width="400" alt="image" src="https://user-images.githubusercontent.com/77398366/181906454-b46f6a14-7c2c-4b8f-8b0a-40432521bed8.png">
中文 | [English](https://github.com/opengoofy/hippo4j/blob/develop/README-EN.md)
# 动态可观测线程池框架,提高线上运行保障能力
[![Gitee](https://gitee.com/itmachen/hippo4j/badge/star.svg?theme=gvp)](https://gitee.com/itmachen/hippo4j) [![GitHub](https://img.shields.io/github/stars/opengoofy/hippo4j)](https://github.com/opengoofy/hippo4j) [![Docker Pulls](https://img.shields.io/docker/pulls/hippo4j/hippo4j-server.svg)](https://store.docker.com/community/images/hippo4j/hippo4j-server) [![Contributors](https://img.shields.io/github/contributors/opengoofy/hippo4j?color=3ba272)](https://github.com/opengoofy/hippo4j/graphs/contributors) [![License](https://img.shields.io/github/license/opengoofy/hippo4j?color=5470c6)](https://github.com/opengoofy/hippo4j/blob/develop/LICENSE)
@ -36,7 +38,7 @@ Hippo-4J 通过对 JDK 线程池增强,以及扩展三方框架底层线程池
- 功能扩展 - 支持线程池任务传递上下文;项目关闭时,支持等待线程池在指定时间内完成任务。
- 多种模式 - 内置两种使用模式:[依赖配置中心](https://hippo4j.cn/docs/user_docs/getting_started/config/hippo4j-config-start) 和 [无中间件依赖](https://hippo4j.cn/docs/user_docs/getting_started/server/hippo4j-server-start)。
- 容器管理 - Tomcat、Jetty、Undertow 容器线程池运行时查看和线程数变更。
- 中间件适配 - Dubbo、Hystrix、Polaris、RabbitMQ、RocketMQ 等消费线程池运行时数据查看和线程数变更。
- 框架适配 - Dubbo、Hystrix、RabbitMQ、RocketMQ 等消费线程池运行时数据查看和线程数变更。
## 快速开始
@ -44,6 +46,10 @@ Hippo-4J 通过对 JDK 线程池增强,以及扩展三方框架底层线程池
演示环境: [http://console.hippo4j.cn/index.html](http://console.hippo4j.cn/index.html)
## 接入登记
更多接入的公司,欢迎在 [登记地址](https://github.com/opengoofy/hippo4j/issues/13) 登记,登记仅仅为了产品推广。
## 联系我
![](https://user-images.githubusercontent.com/77398366/185774220-c11951f9-e130-4d60-8204-afb5c51d4401.png)
@ -101,17 +107,17 @@ Hippo-4J 通过对 JDK 线程池增强,以及扩展三方框架底层线程池
</a>
</td>
<td align="center">
<a href="https://github.com/iwangjie">
<img src="https://avatars.githubusercontent.com/u/23075587?v=4" width="50;" alt="iwangjie"/>
<a href="https://github.com/hippo4jbot">
<img src="https://avatars.githubusercontent.com/u/93201205?v=4" width="50;" alt="hippo4jbot"/>
<br />
<sub><b>王杰</b></sub>
<sub><b>Hippo4jbot[bot]</b></sub>
</a>
</td>
<td align="center">
<a href="https://github.com/pizihao">
<img src="https://avatars.githubusercontent.com/u/48643103?v=4" width="50;" alt="pizihao"/>
<a href="https://github.com/iwangjie">
<img src="https://avatars.githubusercontent.com/u/23075587?v=4" width="50;" alt="iwangjie"/>
<br />
<sub><b>Pizihao</b></sub>
<sub><b>王杰</b></sub>
</a>
</td>
<td align="center">
@ -121,14 +127,21 @@ Hippo-4J 通过对 JDK 线程池增强,以及扩展三方框架底层线程池
<sub><b>BigXin0109</b></sub>
</a>
</td>
<td align="center">
<a href="https://github.com/pizihao">
<img src="https://avatars.githubusercontent.com/u/48643103?v=4" width="50;" alt="pizihao"/>
<br />
<sub><b>Pizihao</b></sub>
</a>
</td></tr>
<tr>
<td align="center">
<a href="https://github.com/Gdk666">
<img src="https://avatars.githubusercontent.com/u/22442067?v=4" width="50;" alt="Gdk666"/>
<br />
<sub><b>Null</b></sub>
</a>
</td></tr>
<tr>
</td>
<td align="center">
<a href="https://github.com/xqxyxchy">
<img src="https://avatars.githubusercontent.com/u/21134578?v=4" width="50;" alt="xqxyxchy"/>
@ -164,13 +177,6 @@ Hippo-4J 通过对 JDK 线程池增强,以及扩展三方框架底层线程池
<sub><b>庄昊哲</b></sub>
</a>
</td>
<td align="center">
<a href="https://github.com/hippo4jbot">
<img src="https://avatars.githubusercontent.com/u/93201205?v=4" width="50;" alt="hippo4jbot"/>
<br />
<sub><b>Hippo4jbot[bot]</b></sub>
</a>
</td>
<td align="center">
<a href="https://github.com/liulinfei121">
<img src="https://avatars.githubusercontent.com/u/57127515?v=4" width="50;" alt="liulinfei121"/>
@ -221,6 +227,13 @@ Hippo-4J 通过对 JDK 线程池增强,以及扩展三方框架底层线程池
<sub><b>Null</b></sub>
</a>
</td>
<td align="center">
<a href="https://github.com/wulangcode">
<img src="https://avatars.githubusercontent.com/u/48200100?v=4" width="50;" alt="wulangcode"/>
<br />
<sub><b>WuLang</b></sub>
</a>
</td>
<td align="center">
<a href="https://github.com/gywanghai">
<img src="https://avatars.githubusercontent.com/u/102774648?v=4" width="50;" alt="gywanghai"/>
@ -248,15 +261,15 @@ Hippo-4J 通过对 JDK 线程池增强,以及扩展三方框架底层线程池
<br />
<sub><b>Sean Wu</b></sub>
</a>
</td>
</td></tr>
<tr>
<td align="center">
<a href="https://github.com/HKMV">
<img src="https://avatars.githubusercontent.com/u/26456469?v=4" width="50;" alt="HKMV"/>
<br />
<sub><b>Serenity</b></sub>
</a>
</td></tr>
<tr>
</td>
<td align="center">
<a href="https://github.com/gewuwo">
<img src="https://avatars.githubusercontent.com/u/97213587?v=4" width="50;" alt="gewuwo"/>
@ -312,15 +325,22 @@ Hippo-4J 通过对 JDK 线程池增强,以及扩展三方框架底层线程池
<br />
<sub><b>游祖光</b></sub>
</a>
</td>
</td></tr>
<tr>
<td align="center">
<a href="https://github.com/puppet4">
<img src="https://avatars.githubusercontent.com/u/28887178?v=4" width="50;" alt="puppet4"/>
<br />
<sub><b>Tudo</b></sub>
</a>
</td></tr>
<tr>
</td>
<td align="center">
<a href="https://github.com/yanrongzhen">
<img src="https://avatars.githubusercontent.com/u/106363931?v=4" width="50;" alt="yanrongzhen"/>
<br />
<sub><b>严荣振</b></sub>
</a>
</td>
<td align="center">
<a href="https://github.com/2EXP">
<img src="https://avatars.githubusercontent.com/u/26007713?v=4" width="50;" alt="2EXP"/>
@ -369,7 +389,8 @@ Hippo-4J 通过对 JDK 线程池增强,以及扩展三方框架底层线程池
<br />
<sub><b>Douspeng</b></sub>
</a>
</td>
</td></tr>
<tr>
<td align="center">
<a href="https://github.com/hl1248">
<img src="https://avatars.githubusercontent.com/u/70790953?v=4" width="50;" alt="hl1248"/>
@ -383,14 +404,6 @@ Hippo-4J 通过对 JDK 线程池增强,以及扩展三方框架底层线程池
<br />
<sub><b>Lynn</b></sub>
</a>
</td></tr>
<tr>
<td align="center">
<a href="https://github.com/wulangcode">
<img src="https://avatars.githubusercontent.com/u/48200100?v=4" width="50;" alt="wulangcode"/>
<br />
<sub><b>WuLang</b></sub>
</a>
</td>
<td align="center">
<a href="https://github.com/alexhaoxuan">
@ -440,15 +453,15 @@ Hippo-4J 通过对 JDK 线程池增强,以及扩展三方框架底层线程池
<br />
<sub><b>Guide</b></sub>
</a>
</td>
</td></tr>
<tr>
<td align="center">
<a href="https://github.com/hbw1994">
<img src="https://avatars.githubusercontent.com/u/22744421?v=4" width="50;" alt="hbw1994"/>
<br />
<sub><b>Null</b></sub>
</a>
</td></tr>
<tr>
</td>
<td align="center">
<a href="https://github.com/hncboy">
<img src="https://avatars.githubusercontent.com/u/27755574?v=4" width="50;" alt="hncboy"/>
@ -504,15 +517,15 @@ Hippo-4J 通过对 JDK 线程池增强,以及扩展三方框架底层线程池
<br />
<sub><b>Op-lht</b></sub>
</a>
</td>
</td></tr>
<tr>
<td align="center">
<a href="https://github.com/wangjie-github">
<img src="https://avatars.githubusercontent.com/u/35762878?v=4" width="50;" alt="wangjie-github"/>
<br />
<sub><b>Wangjie</b></sub>
</a>
</td></tr>
<tr>
</td>
<td align="center">
<a href="https://github.com/wangyi123456">
<img src="https://avatars.githubusercontent.com/u/25248959?v=4" width="50;" alt="wangyi123456"/>
@ -568,21 +581,14 @@ Hippo-4J 通过对 JDK 线程池增强,以及扩展三方框架底层线程池
<br />
<sub><b>Zhaojinchao</b></sub>
</a>
</td>
</td></tr>
<tr>
<td align="center">
<a href="https://github.com/zj1997">
<img src="https://avatars.githubusercontent.com/u/31212787?v=4" width="50;" alt="zj1997"/>
<br />
<sub><b>Null</b></sub>
</a>
</td></tr>
<tr>
<td align="center">
<a href="https://github.com/yanrongzhen">
<img src="https://avatars.githubusercontent.com/u/106363931?v=4" width="50;" alt="yanrongzhen"/>
<br />
<sub><b>严荣振</b></sub>
</a>
</td>
<td align="center">
<a href="https://github.com/li-xiao-shuang">

@ -12,7 +12,7 @@ sidebar_position: 3
## 谁在使用 Hippo4J
共计 18+ 家公司生产接入 Hippo4J。按照公司登记时间排序。
共计 19+ 家公司生产接入 Hippo4J。按照公司登记时间排序。
- [身边云](https://serviceshare.com)
- [Medbanks](https://www.medbanks.cn)
@ -32,3 +32,4 @@ sidebar_position: 3
- [斗象科技](https://www.tophant.com/)
- [深圳航天信息有限公司](http://sz.aisino.com/)
- [新东方教育科技集团](https://www.xdf.cn/)
- [远眺网络科技有限公司](https://www.yuantiaokj.com/)

@ -0,0 +1,121 @@
---
sidebar_position: 5
---
# 适配SpringBoot1x
目前已支持 Nacos、Apollo 配置中心适配 SpringBoot 1.5.x 版本。
```xml
<dependency>
<groupId>cn.hippo4j</groupId>
<artifactId>hippo4j-config-spring-boot-1x-starter</artifactId>
<version>1.4.2</version>
</dependency>
```
Nacos SpringBoot 配置如下:
```yaml
spring:
cloud:
nacos:
config:
ext-config:
- data-id: hippo4j-nacos.yaml
group: DEFAULT_GROUP
refresh: true
server-addr: 127.0.0.1:8848
dynamic:
thread-pool:
config-file-type: yml
nacos:
data-id: hippo4j-nacos.yaml
group: DEFAULT_GROUP
```
Apollo SpringBoot 配置如下:
```yaml
apollo:
autoUpdateInjectedSpringProperties: true
bootstrap:
eagerLoad:
enabled: true
enabled: true
namespaces: application
meta: http://127.0.0.1:8080
app:
id: dynamic-threadpool-example
spring:
dynamic:
thread-pool:
apollo:
namespace: application
```
动态线程池通用配置如下:
```yaml
management:
context-path: /actuator
security:
enabled: false
server:
port: 8091
servlet:
context-path: /example
spring:
application:
name: dynamic-threadpool-example
dynamic:
thread-pool:
banner: true
check-state-interval: 5
collect-type: micrometer
config-file-type: properties
enable: true
executors:
- active-alarm: 80
alarm: true
allow-core-thread-time-out: true
blocking-queue: LinkedBlockingQueue
capacity-alarm: 80
core-pool-size: 1
execute-time-out: 1000
keep-alive-time: 6691
maximum-pool-size: 1
notify:
interval: 8
receives: chen.ma
queue-capacity: 1
rejected-handler: AbortPolicy
thread-name-prefix: message-consume
thread-pool-id: message-consume
- active-alarm: 80
alarm: true
allow-core-thread-time-out: true
blocking-queue: LinkedBlockingQueue
capacity-alarm: 80
core-pool-size: 1
execute-time-out: 1000
keep-alive-time: 6691
maximum-pool-size: 1
notify:
interval: 8
receives: chen.ma
queue-capacity: 1
rejected-handler: AbortPolicy
thread-name-prefix: message-produce
thread-pool-id: message-produce
notify-platforms:
- platform: WECHAT
token: ac0426a5-c712-474c-9bff-72b8b8f5caff
profiles:
active: dev
```
具体 Demo 运行请参考以下示例模块,已验证对应线程池动态变更、报警以及运行时监控功能。
- `/hippo4j-config-nacos-spring-boot-1x-starter-example`
- `hippo4j-example/hippo4j-config-apollo-spring-boot-1x-starter-example`

@ -4,7 +4,7 @@ sidebar_position: 1
# 接入流程
Nacos、Apollo、Zookeeper、ETCD 配置中心任选其一。
Nacos、Apollo、Zookeeper、ETCD、Polaris 配置中心任选其一。
## hippo4j 配置
@ -12,7 +12,7 @@ Nacos、Apollo、Zookeeper、ETCD 配置中心任选其一。
<dependency>
<groupId>cn.hippo4j</groupId>
<artifactId>hippo4j-config-spring-boot-starter</artifactId>
<version>1.4.1</version>
<version>1.4.2</version>
</dependency>
```
@ -59,7 +59,7 @@ spring:
secret: xxx # 加签专属
- platform: 'LARK'
token: xxx
# nacos apollo、zookeeper 任选其一
# Nacos、Apollo、Zookeeper、ETCD、Polaris 任选其一
nacos:
data-id: xxx
group: xxx

@ -10,7 +10,7 @@ sidebar_position: 0
### hippo4j-config
**轻量级动态线程池管理**,依赖 Apollo、Nacos、Zookeeper 等三方配置中心(任选其一)完成线程池参数动态变更,支持运行时报警、监控等功能。
**轻量级动态线程池管理**,依赖 Nacos、Apollo、Zookeeper、ETCD、Polaris 等三方配置中心(任选其一)完成线程池参数动态变更,支持运行时报警、监控等功能。
> 监控功能配置详见:[线程池监控](/docs/user_docs/getting_started/config/hippo4j-config-monitor)
@ -28,7 +28,7 @@ sidebar_position: 0
| | hippo4j-config | hippo4j-server |
| ---- | ---------------------------------------------------- | ------------------------------------------------------------ |
| 依赖 | Nacos、Apollo、Zookeeper 配置中心(任选其一) | 部署 Hippo-4J Server内部无依赖中间件 |
| 依赖 | Nacos、Apollo、Zookeeper、ETCD、Polaris 配置中心(任选其一) | 部署 Hippo-4J Server内部无依赖中间件 |
| 使用 | 配置中心补充线程池相关参数 | Hippo-4J Server Web 控制台添加线程池记录 |
| 功能 | 包含基础功能:参数动态化、运行时监控、报警等 | 基础功能之外扩展控制台界面、线程池堆栈查看、线程池运行信息实时查看、历史运行信息查看、线程池配置集群个性化等 |

@ -33,7 +33,7 @@ Hippo4J 目前已支持的三方框架线程池列表:
<artifactId>hippo4j-spring-boot-starter-adapter-spring-cloud-stream-rocketmq</artifactId>
<!-- SpringCloud Stream RabbitMQ -->
<artifactId>hippo4j-spring-boot-starter-adapter-spring-cloud-stream-rabbitmq</artifactId>
<version>1.4.1</version>
<version>1.4.2</version>
</dependency>
```
@ -43,7 +43,7 @@ Hippo4J 目前已支持的三方框架线程池列表:
<dependency>
<groupId>cn.hippo4j</groupId>
<artifactId>hippo4j-spring-boot-starter-adapter-all</artifactId>
<version>1.4.1</version>
<version>1.4.2</version>
</dependency>
```

@ -22,7 +22,7 @@ SpringBoot Pom 引入 Hippo4j Starter Jar。
<dependency>
<groupId>cn.hippo4j</groupId>
<artifactId>hippo4j-spring-boot-starter</artifactId>
<version>1.4.1</version>
<version>1.4.2</version>
</dependency>
```

@ -33,10 +33,10 @@ hippo4j/hippo4j-server
方式一:
```shell
# 进入到 hippo4j-server 工程路径下
# 进入到 hippo4j-server/hippo4j-bootstrap 工程路径下
mvn clean package -Dskip.spotless.apply=true
# 默认打包是打包的 tag 是 latest
docker build -t hippo4j/hippo4j-server ../hippo4j-server
docker build -t hippo4j/hippo4j-server ../hippo4j-bootstrap
```
方式二:

@ -8,7 +8,6 @@ sidebar_position: 2
- <a href="#控制台线程池管理和线程池实例的区别">控制台线程池管理和线程池实例的区别</a>
- <a href="#示例项目为什么会有跨域请求">示例项目为什么会有跨域请求</a>
- <a href="#更新代码后运行时服务端sql报错">更新代码后运行时服务端SQL报错</a>
- <a href="#okhttp3-call-timeout-方法不存在">okHttp3 call.timeout() 方法不存在</a>
- <a href="#生产环境如何不启用动态线程池">生产环境如何不启用动态线程池</a>
- <a href="#server-端宕机会影响-client-运行么">Server 端宕机会影响 Client 运行么</a>
- <a href="#hippo4j-的发布方式是怎样的-如何选择正确的版本">Hippo4J 的发布方式是怎样的?如何选择正确的版本</a>
@ -48,18 +47,6 @@ Hippo4J 按照租户、项目、线程池的维度划分。
> 友情提示:每次执行数据库表或数据变更时,一定要保持提前备份的好习惯。
## okHttp3 call.timeout() 方法不存在
请确保 okHttp3 依赖版本号 >= 3.12.0
```xml
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp</artifactId>
<version>3.12.0</version>
</dependency>
```
## 生产环境如何不启用动态线程池
测试环境已经引入 Hippo4J暂时不打算上线生产环境。

@ -4,6 +4,40 @@ sidebar_position: 4
# 更新日志
## 1.4.2 (Oct 18, 2022)
这是一个功能增强版本,修复了少量 BUG。建议按照当前版本升级。具体信息可查看 Release 标签地址:[1.4.2](https://github.com/opengoofy/hippo4j/milestone/12?closed=1)
**Feature**
- 强制指定客户端注册的 ip + port
- 支持 spring-cloud-tencent Polaris 线程池动态更新 @weihubeats
- 服务启动时加载 MySQL、H2 数据库初始化语句
- Adapter 初始化覆盖核心参数 @pizihao
- Server 端新增是否开启认证模式 @baymax55
**Refactor**
- 替换底层网络工具类 OkHttp @yanrongzhen
- 全局移除 commons-lang3 工具包依赖 @yanrongzhen
- 去除三方工具类依赖 @pizihao
- 全局移除 Guava 工具包依赖 @road2master
- DockerFile 基于 H2 数据库重新构建 @BigXin0109
**Bug**
- Dubbo 2.7.15 无法获取线程池引用 @iwangjie
- 动态线程池报警参数颠倒 @jinlingmei
**Optimize**
- 线程池实例运行数据采集如果线程池id不存在且长度超长会报异常 @Gdk666
- 项目中动态线程池数量为空时,存在 CPU 空转情况
- 客户端注册服务端失败,输出服务端返回信息 @wulangcode
- 调整数据库项目 id 和线程池 id 字段长度
- 增加代码检查工具 maven-checkstyle-plugin
- 调整控制台监控图表颜色展示
## 1.4.1 (Sep 12, 2022)
这是一个功能增强版本,修复了若干 BUG。建议按照当前版本升级。具体信息可查看 Release 标签地址:[1.4.1](https://github.com/opengoofy/hippo4j/milestone/11?closed=1)

@ -1,40 +1 @@
---
sidebar_position: 3
---
# 快速开始
## 服务启动
使用 Docker 运行服务端,默认使用内置 H2 数据库,数据持久化到 Docker 容器存储卷中。
```shell
docker run -d -p 6691:6691 --name hippo4j-server hippo4j/hippo4j-server
```
> 如果没有 Docker可以使用源码编译的方式启动 [Hippo4J-Server](https://github.com/longtai-cn/hippo4j/tree/develop/hippo4j-server) 模块下 ServerApplication 应用类。
启动示例项目,[hippo4j-spring-boot-starter-example](https://github.com/opengoofy/hippo4j/tree/develop/hippo4j-example/hippo4j-spring-boot-starter-example) 模块下 Hippo4JServerExampleApplication 应用类。
访问 Server 控制台,路径 `http://localhost:6691/index.html`默认用户名密码admin / 123456
## 配置变更
访问控制台动态线程池菜单下线程池实例,修改动态线程池相关参数。
![](https://images-machen.oss-cn-beijing.aliyuncs.com/image-20220813173811668.png)
观察 Hippo4j-Example 控制台日志输出,日志输出包括不限于此信息即为成功。
```tex
2022-09-10 00:23:29.783 INFO 50322 --- [change.config_0] c.h.s.s.c.ServerThreadPoolDynamicRefresh : [message-consume] Dynamic thread pool change parameter.
corePoolSize: 2 => 4
maximumPoolSize: 6 => 12
capacity: 1024 => 2048
keepAliveTime: 9999 => 9999
executeTimeOut: 800 => 3000
rejectedType: SyncPutQueuePolicy => RunsOldestTaskPolicy
allowCoreThreadTimeOut: true => true
```
另外,当 Client 集群部署时,可以修改某一个实例,或选择 `全部修改` 按钮,修改所有实例线程池信息。
--- sidebar_position: 3 --- # 快速开始 ## 服务启动 使用 Docker 运行服务端,默认使用内置 H2 数据库,数据持久化到 Docker 容器存储卷中。 ```shell docker run -d -p 6691:6691 --name hippo4j-server hippo4j/hippo4j-server ``` > 如果没有 Docker可以使用源码编译的方式启动 [Hippo4J-Server/Hippo4J-Bootstrap](https://github.com/longtai-cn/hippo4j/tree/develop/hippo4j-server/hippo4j-bootstrap) 模块下 ServerApplication 应用类。 启动示例项目,[hippo4j-spring-boot-starter-example](https://github.com/opengoofy/hippo4j/tree/develop/hippo4j-example/hippo4j-spring-boot-starter-example) 模块下 Hippo4JServerExampleApplication 应用类。 访问 Server 控制台,路径 `http://localhost:6691/index.html`默认用户名密码admin / 123456 ## 配置变更 访问控制台动态线程池菜单下线程池实例,修改动态线程池相关参数。 ![](https://images-machen.oss-cn-beijing.aliyuncs.com/image-20220813173811668.png) 观察 Hippo4j-Example 控制台日志输出,日志输出包括不限于此信息即为成功。 ```tex 2022-09-10 00:23:29.783 INFO 50322 --- [change.config_0] c.h.s.s.c.ServerThreadPoolDynamicRefresh : [message-consume] Dynamic thread pool change parameter. corePoolSize: 2 => 4 maximumPoolSize: 6 => 12 capacity: 1024 => 2048 keepAliveTime: 9999 => 9999 executeTimeOut: 800 => 3000 rejectedType: SyncPutQueuePolicy => RunsOldestTaskPolicy allowCoreThreadTimeOut: true => true ``` 另外,当 Client 集群部署时,可以修改某一个实例,或选择 `全部修改` 按钮,修改所有实例线程池信息。

@ -22,6 +22,7 @@ import cn.hippo4j.common.model.WebIpAndPortInfo;
import cn.hippo4j.common.toolkit.Assert;
import cn.hippo4j.common.toolkit.StringUtil;
import cn.hippo4j.core.toolkit.inet.InetUtils;
import lombok.NoArgsConstructor;
import org.springframework.boot.web.server.WebServer;
import java.util.Arrays;
@ -29,25 +30,35 @@ import java.util.Objects;
import java.util.concurrent.atomic.AtomicReference;
/**
* Ip and port Holder
* Ip and port holder.
*/
@NoArgsConstructor(access = lombok.AccessLevel.PRIVATE)
public class WebIpAndPortHolder {
private static boolean SUPPORT_VERSION = false;
static {
try {
Class.forName("org.springframework.boot.web.server.WebServer");
SUPPORT_VERSION = true;
} catch (Exception ignored) {
}
}
/**
* Application ip and application post
*/
protected static AtomicReference<WebIpAndPortInfo> webIpAndPort = new AtomicReference<>();
protected static AtomicReference<WebIpAndPortInfo> WEB_IP_AND_PORT = new AtomicReference<>();
public static final String ALL = "*";
protected static final String SEPARATOR = ",";
private WebIpAndPortHolder() {
}
protected static void initIpAndPort() {
webIpAndPort.compareAndSet(null, getWebIpAndPortInfo());
if (!SUPPORT_VERSION) {
return;
}
WEB_IP_AND_PORT.compareAndSet(null, getWebIpAndPortInfo());
}
private static WebIpAndPortInfo getWebIpAndPortInfo() {
@ -64,26 +75,26 @@ public class WebIpAndPortHolder {
}
/**
* get WebIpAndPortInfo, If it is null, initialize it
* get WebIpAndPortInfo, If it is null, initialize it.
*
* @return WebIpAndPortInfo
* @return Web ip and port info
*/
public static WebIpAndPortInfo getWebIpAndPort() {
if (webIpAndPort.get() == null) {
if (WEB_IP_AND_PORT.get() == null) {
initIpAndPort();
}
return WebIpAndPortHolder.webIpAndPort.get();
return WebIpAndPortHolder.WEB_IP_AND_PORT.get();
}
/**
* Check the new properties and instance IP and port
* Check the new properties and instance IP and port.
*
* @param nodes nodes in properties
* @return Whether it meets the conditions
*/
public static boolean check(String nodes) {
WebIpAndPortInfo webIpAndPort = WebIpAndPortHolder.getWebIpAndPort();
if (StringUtil.isEmpty(nodes) || ALL.equals(nodes)) {
if (StringUtil.isEmpty(nodes) || ALL.equals(nodes) || webIpAndPort == null) {
return true;
}
String[] splitNodes = nodes.split(SEPARATOR);
@ -93,5 +104,4 @@ public class WebIpAndPortHolder {
.filter(Objects::nonNull)
.anyMatch(each -> each.check(webIpAndPort.getIpSegment(), webIpAndPort.getPort()));
}
}

@ -49,10 +49,6 @@
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-json</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
@ -66,9 +62,5 @@
<groupId>com.github.dozermapper</groupId>
<artifactId>dozer-core</artifactId>
</dependency>
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp</artifactId>
</dependency>
</dependencies>
</project>

@ -0,0 +1,34 @@
/*
* 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 cn.hippo4j.common.api;
import org.springframework.core.env.ConfigurableEnvironment;
/**
* Client network service.
*/
public interface ClientNetworkService {
/**
* Get network ip port. return as an array 127.0.0.1,8080
*
* @param environment environment
* @return network ip port
*/
String[] getNetworkIpPort(ConfigurableEnvironment environment);
}

@ -63,4 +63,12 @@ public interface JsonFacade {
* @return
*/
<T> List<T> parseArray(String text, Class<T> clazz);
/**
* Validate json.
*
* @param text
* @return
*/
boolean isJson(String text);
}

@ -38,11 +38,13 @@ public class Constants {
public static final String DEFAULT_NAMESPACE_ID = "public";
public static final String ENCODE = "UTF-8";
public static final String NULL = "";
public static final String UP = "UP";
public static final String ENCODE = "UTF-8";
public static final String CONTENT_TYPE = "Content-Type";
public static final int CONFIG_LONG_POLL_TIMEOUT = 30000;

@ -15,21 +15,32 @@
* limitations under the License.
*/
package cn.hippo4j.springboot.starter.monitor.micrometer;
import cn.hippo4j.core.executor.state.ThreadPoolRunStateHandler;
import cn.hippo4j.monitor.micrometer.MicrometerMonitorHandler;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
package cn.hippo4j.common.constant;
/**
* Micrometer monitor configuration.
* Http header constants.
*/
@Configuration
public class MicrometerMonitorConfiguration {
public interface HttpHeaderConstants {
@Bean
public MicrometerMonitorHandler micrometerMonitorHandler(ThreadPoolRunStateHandler threadPoolRunStateHandler) {
return new MicrometerMonitorHandler(threadPoolRunStateHandler);
}
String CLIENT_VERSION_HEADER = "Client-Version";
String USER_AGENT_HEADER = "User-Agent";
String REQUEST_SOURCE_HEADER = "Request-Source";
String CONTENT_TYPE = "Content-Type";
String CONTENT_LENGTH = "Content-Length";
String ACCEPT_CHARSET = "Accept-Charset";
String ACCEPT_ENCODING = "Accept-Encoding";
String CONTENT_ENCODING = "Content-Encoding";
String CONNECTION = "Requester";
String REQUEST_ID = "RequestId";
String REQUEST_MODULE = "Request-Module";
}

@ -0,0 +1,111 @@
/*
* 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 cn.hippo4j.common.constant;
import cn.hippo4j.common.toolkit.StringUtil;
/**
* Http media type.
*
* @author Rongzhen Yan
*/
public final class HttpMediaType {
public static final String APPLICATION_ATOM_XML = "application/atom+xml";
public static final String APPLICATION_FORM_URLENCODED = "application/x-www-form-urlencoded;charset=UTF-8";
public static final String APPLICATION_OCTET_STREAM = "application/octet-stream";
public static final String APPLICATION_SVG_XML = "application/svg+xml";
public static final String APPLICATION_XHTML_XML = "application/xhtml+xml";
public static final String APPLICATION_XML = "application/xml;charset=UTF-8";
public static final String APPLICATION_JSON = "application/json;charset=UTF-8";
public static final String MULTIPART_FORM_DATA = "multipart/form-data;charset=UTF-8";
public static final String TEXT_HTML = "text/html;charset=UTF-8";
public static final String TEXT_PLAIN = "text/plain;charset=UTF-8";
private HttpMediaType(String type, String charset) {
this.type = type;
this.charset = charset;
}
/**
* content type.
*/
private final String type;
/**
* content type charset.
*/
private final String charset;
/**
* Parse the given String contentType into a {@code MediaType} object.
*
* @param contentType mediaType
* @return MediaType
*/
public static HttpMediaType valueOf(String contentType) {
if (StringUtil.isEmpty(contentType)) {
throw new IllegalArgumentException("MediaType must not be empty");
}
String[] values = contentType.split(";");
String charset = Constants.ENCODE;
for (String value : values) {
if (value.startsWith("charset=")) {
charset = value.substring("charset=".length());
}
}
return new HttpMediaType(values[0], charset);
}
/**
* Use the given contentType and charset to assemble into a {@code MediaType} object.
*
* @param contentType contentType
* @param charset charset
* @return MediaType
*/
public static HttpMediaType valueOf(String contentType, String charset) {
if (StringUtil.isEmpty(contentType)) {
throw new IllegalArgumentException("MediaType must not be empty");
}
String[] values = contentType.split(";");
return new HttpMediaType(values[0], StringUtil.isEmpty(charset) ? Constants.ENCODE : charset);
}
public String getType() {
return type;
}
public String getCharset() {
return charset;
}
@Override
public String toString() {
return type + ";charset=" + charset;
}
}

@ -0,0 +1,42 @@
/*
* 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 cn.hippo4j.common.constant;
/**
* Http method constants.
*
* @author Rongzhen Yan
*/
public class HttpMethod {
public static final String GET = "GET";
public static final String HEAD = "HEAD";
public static final String POST = "POST";
public static final String PUT = "PUT";
public static final String PATCH = "PATCH";
public static final String DELETE = "DELETE";
public static final String OPTIONS = "OPTIONS";
public static final String TRACE = "TRACE";
}

@ -0,0 +1,108 @@
/*
* 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 cn.hippo4j.common.constant;
/**
* Http response code.
*
* @author Rongzhen Yan
*/
public interface HttpResponseCode {
int SC_CONTINUE = 100;
int SC_SWITCHING_PROTOCOLS = 101;
int SC_OK = 200;
int SC_CREATED = 201;
int SC_ACCEPTED = 202;
int SC_NON_AUTHORITATIVE_INFORMATION = 203;
int SC_NO_CONTENT = 204;
int SC_RESET_CONTENT = 205;
int SC_PARTIAL_CONTENT = 206;
int SC_MULTIPLE_CHOICES = 300;
int SC_MOVED_PERMANENTLY = 301;
int SC_MOVED_TEMPORARILY = 302;
int SC_FOUND = 302;
int SC_SEE_OTHER = 303;
int SC_NOT_MODIFIED = 304;
int SC_USE_PROXY = 305;
int SC_TEMPORARY_REDIRECT = 307;
int SC_BAD_REQUEST = 400;
int SC_UNAUTHORIZED = 401;
int SC_PAYMENT_REQUIRED = 402;
int SC_FORBIDDEN = 403;
int SC_NOT_FOUND = 404;
int SC_METHOD_NOT_ALLOWED = 405;
int SC_NOT_ACCEPTABLE = 406;
int SC_PROXY_AUTHENTICATION_REQUIRED = 407;
int SC_REQUEST_TIMEOUT = 408;
int SC_CONFLICT = 409;
int SC_GONE = 410;
int SC_LENGTH_REQUIRED = 411;
int SC_PRECONDITION_FAILED = 412;
int SC_REQUEST_ENTITY_TOO_LARGE = 413;
int SC_REQUEST_URI_TOO_LONG = 414;
int SC_UNSUPPORTED_MEDIA_TYPE = 415;
int SC_REQUESTED_RANGE_NOT_SATISFIABLE = 416;
int SC_EXPECTATION_FAILED = 417;
int SC_INTERNAL_SERVER_ERROR = 500;
int SC_NOT_IMPLEMENTED = 501;
int SC_BAD_GATEWAY = 502;
int SC_SERVICE_UNAVAILABLE = 503;
int SC_GATEWAY_TIMEOUT = 504;
int SC_HTTP_VERSION_NOT_SUPPORTED = 505;
}

@ -17,30 +17,39 @@
package cn.hippo4j.common.enums;
/**
* Enumeration of thread pool audit status.
*/
public enum VerifyEnum {
/**
* unVerify
* To verify
*/
TO_VERIFY(0, "待审核"),
/**
* accept
* Verify accept
*/
VERIFY_ACCEPT(1, "审核通过"),
/**
* reject
* Verify reject
*/
VERIFY_REJECT(2, "审核拒绝"),
/**
* invalid
* Verify invalid
*/
VERIFY_INVALID(3, "失效");
/**
* Verify status
*/
private final Integer verifyStatus;
/**
* Desc
*/
private final String desc;
VerifyEnum(Integer verifyStatus, String desc) {

@ -42,6 +42,9 @@ public class ThreadPoolManager {
return INSTANCE;
}
private ThreadPoolManager() {
}
static {
INSTANCE.init();
}

@ -1,299 +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 cn.hippo4j.common.toolkit;
import cn.hippo4j.common.web.exception.ServiceException;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import okhttp3.*;
import org.springframework.util.CollectionUtils;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReference;
/**
* HttpClient util.
*/
@Slf4j
public class HttpClientUtil {
private OkHttpClient hippo4JOkHttpClient;
private static AtomicReference<HttpClientUtil> reference = new AtomicReference<>();
private MediaType jsonMediaType = MediaType.parse("application/json; charset=utf-8");
private static int HTTP_OK_CODE = 200;
private HttpClientUtil() {
OkHttpClient.Builder build = new OkHttpClient.Builder();
build.connectTimeout(10, TimeUnit.SECONDS)
.readTimeout(30, TimeUnit.SECONDS)
.build();
supportHttps(build);
this.hippo4JOkHttpClient = build.build();
}
public static HttpClientUtil build() {
if (reference.get() == null) {
reference.compareAndSet(null, new HttpClientUtil());
}
return reference.get();
}
/**
* Get.
*
* @param url
* @return
*/
@SneakyThrows
public String get(String url) {
try {
return new String(doGet(url), "utf-8");
} catch (Exception e) {
log.error("HttpGet call failed. {}", url, e);
throw e;
}
}
/**
* Get request, supports adding query string.
*
* @param url
* @param queryString
* @return
*/
public String get(String url, Map<String, String> queryString) {
String fullUrl = buildUrl(url, queryString);
return get(fullUrl);
}
/**
* Deserialize directly after getting Json.
*
* @param url
* @param clazz
* @return
*/
public <T> T restApiGet(String url, Class<T> clazz) {
String resp = get(url);
return JSONUtil.parseObject(resp, clazz);
}
/**
* Call health check.
*
* @param url
* @param clazz
* @param <T>
* @return
*/
@SneakyThrows
public <T> T restApiGetHealth(String url, Class<T> clazz) {
String resp = new String(doGet(url), "utf-8");
return JSONUtil.parseObject(resp, clazz);
}
/**
* Get request, supports query string.
*
* @param url
* @param queryString
* @param clazz
* @param <T>
* @return
*/
public <T> T restApiGet(String url, Map<String, String> queryString, Class<T> clazz) {
String fullUrl = buildUrl(url, queryString);
String resp = get(fullUrl);
return JSONUtil.parseObject(resp, clazz);
}
/**
* Rest interface Post call.
*
* @param url
* @param body
* @return
*/
public String restApiPost(String url, Object body) {
try {
return doPost(url, body);
} catch (Exception e) {
log.error("HttpPost call failed. {} message: {}", url, e.getMessage());
throw e;
}
}
/**
* Rest interface Post call. Deserialize the return value directly.
*
* @param url
* @param body
* @return
*/
public <T> T restApiPost(String url, Object body, Class<T> clazz) {
String resp = restApiPost(url, body);
return JSONUtil.parseObject(resp, clazz);
}
/**
* Constructs a complete Url from the query string.
*
* @param url
* @param queryString
* @return
*/
public String buildUrl(String url, Map<String, String> queryString) {
if (null == queryString) {
return url;
}
StringBuilder builder = new StringBuilder(url);
boolean isFirst = true;
for (Map.Entry<String, String> entry : queryString.entrySet()) {
String key = entry.getKey();
if (key != null && entry.getValue() != null) {
if (isFirst) {
isFirst = false;
builder.append("?");
} else {
builder.append("&");
}
builder.append(key)
.append("=")
.append(queryString.get(key));
}
}
return builder.toString();
}
@SneakyThrows
private String doPost(String url, Object body) {
String bodyContent;
if (body instanceof String) {
bodyContent = (String) body;
} else {
bodyContent = JSONUtil.toJSONString(body);
}
RequestBody requestBody = RequestBody.create(jsonMediaType, bodyContent);
Request request = new Request.Builder()
.url(url)
.post(requestBody)
.build();
try (Response resp = hippo4JOkHttpClient.newCall(request).execute()) {
try (ResponseBody responseBody = resp.body()) {
if (resp.code() != HTTP_OK_CODE) {
String msg = String.format("HttpPost response code error. [code] %s [url] %s [body] %s", resp.code(), url, bodyContent);
throw new ServiceException(msg);
}
return responseBody.string();
}
}
}
@SneakyThrows
private byte[] doGet(String url) {
Request request = new Request.Builder().get().url(url).build();
try (Response resp = hippo4JOkHttpClient.newCall(request).execute()) {
try (ResponseBody responseBody = resp.body()) {
if (resp.code() != HTTP_OK_CODE) {
String msg = String.format("HttpGet response code error. [code] %s [url] %s", resp.code(), url);
throw new ServiceException(msg);
}
return responseBody.bytes();
}
}
}
@SneakyThrows
public <T> T restApiGetByThreadPool(String url, Map<String, String> headers, Map<String, String> paramValues, Long readTimeoutMs, Class<T> clazz) {
String buildUrl = buildUrl(url, paramValues);
Request.Builder builder = new Request.Builder().get();
if (!CollectionUtils.isEmpty(headers)) {
builder.headers(Headers.of(headers));
}
Request request = builder.url(buildUrl).build();
Call call = hippo4JOkHttpClient.newCall(request);
// TODO Plan to optimize the timout api because its version is too high.
call.timeout().timeout(readTimeoutMs, TimeUnit.MILLISECONDS);
try (Response resp = call.execute()) {
try (ResponseBody responseBody = resp.body()) {
if (resp.code() != HTTP_OK_CODE) {
String msg = String.format("HttpGet response code error. [code] %s [url] %s", resp.code(), url);
log.error(msg);
throw new ServiceException(msg);
}
return JSONUtil.parseObject(responseBody.string(), clazz);
}
}
}
@SneakyThrows
public <T> T restApiPostByThreadPool(String url, Map<String, String> headers, Map<String, String> paramValues, Long readTimeoutMs, Class<T> clazz) {
String buildUrl = buildUrl(url, paramValues);
Request request = new Request.Builder()
.url(buildUrl)
.headers(Headers.of(headers))
.post(RequestBody.create(jsonMediaType, ""))
.build();
Call call = hippo4JOkHttpClient.newCall(request);
// TODO Plan to optimize the timout api because its version is too high.
call.timeout().timeout(readTimeoutMs, TimeUnit.MILLISECONDS);
try (Response resp = call.execute()) {
try (ResponseBody responseBody = resp.body()) {
if (resp.code() != HTTP_OK_CODE) {
String msg = String.format("HttpPost response code error. [code] %s [url] %s.", resp.code(), url);
log.error(msg);
throw new ServiceException(msg);
}
return JSONUtil.parseObject(responseBody.string(), clazz);
}
}
}
@SneakyThrows
private void supportHttps(OkHttpClient.Builder builder) {
final TrustManager[] trustAllCerts = new TrustManager[]{new X509TrustManager() {
@Override
public void checkClientTrusted(java.security.cert.X509Certificate[] chain, String authType) {
}
@Override
public void checkServerTrusted(java.security.cert.X509Certificate[] chain, String authType) {
}
@Override
public java.security.cert.X509Certificate[] getAcceptedIssuers() {
return new java.security.cert.X509Certificate[]{};
}
}};
final SSLContext sslContext = SSLContext.getInstance("SSL");
sslContext.init(null, trustAllCerts, new java.security.SecureRandom());
final SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory();
builder.sslSocketFactory(sslSocketFactory, (X509TrustManager) trustAllCerts[0]);
builder.hostnameVerifier((hostname, session) -> true);
}
}

@ -0,0 +1,341 @@
/*
* 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 cn.hippo4j.common.toolkit;
import cn.hippo4j.common.constant.Constants;
import lombok.SneakyThrows;
import java.io.*;
import java.net.HttpURLConnection;
import java.nio.channels.FileChannel;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.zip.GZIPInputStream;
import java.util.zip.GZIPOutputStream;
/**
* IO related tool methods.
*
* @author nacos
*/
public class IoUtil {
/**
* Try decompress by GZIP from stream.
*
* @param raw compress stream
* @return byte array after decompress
*/
public static byte[] tryDecompress(InputStream raw) throws IOException {
try (
GZIPInputStream gis = new GZIPInputStream(raw);
ByteArrayOutputStream out = new ByteArrayOutputStream()) {
copy(gis, out);
return out.toByteArray();
}
}
/**
* Try decompress by GZIP from byte array.
*
* @param raw compressed byte array
* @return byte array after decompress
* @throws Exception exception
*/
public static byte[] tryDecompress(byte[] raw) throws Exception {
if (!isGzipStream(raw)) {
return raw;
}
try (
GZIPInputStream gis = new GZIPInputStream(new ByteArrayInputStream(raw));
ByteArrayOutputStream out = new ByteArrayOutputStream()) {
copy(gis, out);
return out.toByteArray();
}
}
/**
* Try compress by GZIP for string.
*
* @param str strings to be compressed.
* @param encoding encoding.
* @return byte[]
*/
public static byte[] tryCompress(String str, String encoding) {
if (str == null || str.length() == 0) {
return new byte[0];
}
ByteArrayOutputStream out = new ByteArrayOutputStream();
try (GZIPOutputStream gzip = new GZIPOutputStream(out)) {
gzip.write(str.getBytes(encoding));
} catch (Exception e) {
e.printStackTrace();
}
return out.toByteArray();
}
private static BufferedReader toBufferedReader(Reader reader) {
return reader instanceof BufferedReader ? (BufferedReader) reader : new BufferedReader(reader);
}
/**
* Write string to a file.
*
* @param file file
* @param data string
* @param encoding encoding of string
* @throws IOException io exception
*/
public static void writeStringToFile(File file, String data, String encoding) throws IOException {
try (OutputStream os = new FileOutputStream(file)) {
os.write(data.getBytes(encoding));
os.flush();
}
}
/**
* Read lines.
*
* @param input reader
* @return list of line
* @throws IOException io exception
*/
public static List<String> readLines(Reader input) throws IOException {
BufferedReader reader = toBufferedReader(input);
List<String> list = new ArrayList<>();
while (true) {
String line = reader.readLine();
if (null != line) {
if (StringUtil.isNotEmpty(line)) {
list.add(line.trim());
}
} else {
break;
}
}
return list;
}
/**
* To string from stream.
*
* @param input stream
* @param encoding charset of stream
* @return string
* @throws IOException io exception
*/
@SneakyThrows
public static String toString(InputStream input, String encoding) {
if (input == null) {
return StringUtil.EMPTY;
}
return (null == encoding) ? toString(new InputStreamReader(input, Constants.ENCODE))
: toString(new InputStreamReader(input, encoding));
}
/**
* To string from reader.
*
* @param reader reader
* @return string
* @throws IOException io exception
*/
public static String toString(Reader reader) throws IOException {
CharArrayWriter sw = new CharArrayWriter();
copy(reader, sw);
return sw.toString();
}
/**
* Copy data.
*
* @param input source
* @param output target
* @return copy size
* @throws IOException io exception
*/
public static long copy(Reader input, Writer output) throws IOException {
char[] buffer = new char[1 << 12];
long count = 0;
for (int n = 0; (n = input.read(buffer)) >= 0;) {
output.write(buffer, 0, n);
count += n;
}
return count;
}
/**
* Copy data.
*
* @param input source
* @param output target
* @return copy size
* @throws IOException io exception
*/
public static long copy(InputStream input, OutputStream output) throws IOException {
byte[] buffer = new byte[1024];
int bytesRead;
int totalBytes = 0;
while ((bytesRead = input.read(buffer)) != -1) {
output.write(buffer, 0, bytesRead);
totalBytes += bytesRead;
}
return totalBytes;
}
/**
* Delete file or dir.
*
* <p>If is dir, clean directory, do not delete dir.
*
* <p>If is file, delete file.
*
* @param fileOrDir file or dir
* @throws IOException io exception
*/
public static void delete(File fileOrDir) throws IOException {
if (fileOrDir == null) {
return;
}
if (fileOrDir.isDirectory()) {
cleanDirectory(fileOrDir);
} else {
if (fileOrDir.exists()) {
boolean isDeleteOk = fileOrDir.delete();
if (!isDeleteOk) {
throw new IOException("delete fail");
}
}
}
}
/**
* . Clean content under directory.
*
* @param directory directory
* @throws IOException io exception
*/
public static void cleanDirectory(File directory) throws IOException {
if (!directory.exists()) {
String message = directory + " does not exist";
throw new IllegalArgumentException(message);
}
if (!directory.isDirectory()) {
String message = directory + " is not a directory";
throw new IllegalArgumentException(message);
}
File[] files = directory.listFiles();
// null if security restricted
if (files == null) {
throw new IOException("Failed to list contents of " + directory);
}
IOException exception = null;
for (File file : files) {
try {
delete(file);
} catch (IOException ioe) {
exception = ioe;
}
}
if (null != exception) {
throw exception;
}
}
/**
* Copy File.
*
* @param source source file path
* @param target target file path
* @throws IOException io exception
*/
public static void copyFile(String source, String target) throws IOException {
File sf = new File(source);
if (!sf.exists()) {
throw new IllegalArgumentException("source file does not exist.");
}
File tf = new File(target);
if (!tf.getParentFile().mkdirs()) {
throw new RuntimeException("failed to create parent directory.");
}
if (!tf.exists() && !tf.createNewFile()) {
throw new RuntimeException("failed to create target file.");
}
try (
FileChannel sc = new FileInputStream(sf).getChannel();
FileChannel tc = new FileOutputStream(tf).getChannel()) {
sc.transferTo(0, sc.size(), tc);
}
}
/**
* Judge whether is Gzip stream.
*
* @param bytes byte array
* @return true if is gzip, otherwise false
*/
public static boolean isGzipStream(byte[] bytes) {
int minByteArraySize = 2;
if (bytes == null || bytes.length < minByteArraySize) {
return false;
}
return GZIPInputStream.GZIP_MAGIC == ((bytes[1] << 8 | bytes[0]) & 0xFFFF);
}
/**
* Close http connection quietly.
*
* @param connection http connection
*/
public static void closeQuietly(HttpURLConnection connection) {
if (connection != null) {
try {
closeQuietly(connection.getInputStream());
} catch (Exception ignore) {
}
}
}
/**
* Close closable object quietly.
*
* @param closeable http connection
*/
public static void closeQuietly(Closeable closeable) {
try {
if (closeable != null) {
closeable.close();
}
} catch (IOException ignored) {
}
}
public static void closeQuietly(Closeable... closeable) {
Arrays.stream(closeable).forEach(IoUtil::closeQuietly);
}
}

@ -56,4 +56,11 @@ public class JSONUtil {
}
return JSON_FACADE.parseArray(text, clazz);
}
public static boolean isJson(String json) {
if (StringUtil.isBlank(json)) {
return false;
}
return JSON_FACADE.isJson(json);
}
}

@ -20,11 +20,9 @@ package cn.hippo4j.common.toolkit;
import cn.hippo4j.common.api.JsonFacade;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.databind.*;
import com.fasterxml.jackson.databind.type.CollectionType;
import lombok.SneakyThrows;
@ -74,4 +72,14 @@ public class JacksonHandler implements JsonFacade {
CollectionType collectionType = MAPPER.getTypeFactory().constructCollectionType(ArrayList.class, clazz);
return MAPPER.readValue(text, collectionType);
}
@Override
public boolean isJson(String text) {
try {
MAPPER.readTree(text);
return true;
} catch (JsonProcessingException ignored) {
}
return false;
}
}

@ -0,0 +1,167 @@
/*
* 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 cn.hippo4j.common.toolkit;
import java.util.Collection;
import java.util.Dictionary;
import java.util.Map;
import java.util.Objects;
import java.util.function.BiFunction;
import java.util.function.Predicate;
/**
* Map util.
*/
public class MapUtil {
/**
* Null-safe check if the specified Dictionary is empty.
*
* <p>Null returns true.
*
* @param map the collection to check, may be null
* @return true if empty or null
*/
public static boolean isEmpty(Map map) {
return (map == null || map.isEmpty());
}
/**
* Null-safe check if the specified Dictionary is empty.
*
* <p>Null returns true.
*
* @param coll the collection to check, may be null
* @return true if empty or null
*/
public static boolean isEmpty(Dictionary coll) {
return (coll == null || coll.isEmpty());
}
/**
* Null-safe check if the specified Dictionary is not empty.
*
* <p>Null returns false.
*
* @param map the collection to check, may be null
* @return true if non-null and non-empty
*/
public static boolean isNotEmpty(Map map) {
return !isEmpty(map);
}
/**
* Null-safe check if the specified Dictionary is not empty.
*
* <p>Null returns false.
*
* @param coll the collection to check, may be null
* @return true if non-null and non-empty
*/
public static boolean isNotEmpty(Dictionary coll) {
return !isEmpty(coll);
}
/**
* Put into map if value is not null.
*
* @param target target map
* @param key key
* @param value value
*/
public static void putIfValNoNull(Map target, Object key, Object value) {
Objects.requireNonNull(key, "key");
if (value != null) {
target.put(key, value);
}
}
/**
* Put into map if value is not empty.
*
* @param target target map
* @param key key
* @param value value
*/
public static void putIfValNoEmpty(Map target, Object key, Object value) {
Objects.requireNonNull(key, "key");
if (value instanceof String) {
if (StringUtil.isNotEmpty((String) value)) {
target.put(key, value);
}
return;
}
if (value instanceof Collection) {
if (CollectionUtil.isNotEmpty((Collection) value)) {
target.put(key, value);
}
return;
}
if (value instanceof Map) {
if (isNotEmpty((Map) value)) {
target.put(key, value);
}
return;
}
if (value instanceof Dictionary) {
if (isNotEmpty((Dictionary) value)) {
target.put(key, value);
}
}
}
/**
* ComputeIfAbsent lazy load.
*
* @param target target Map data.
* @param key map key.
* @param mappingFunction function which is need to be executed.
* @param param1 function's parameter value1.
* @param param2 function's parameter value1.
* @return
*/
public static <K, C, V, T> V computeIfAbsent(Map<K, V> target, K key, BiFunction<C, T, V> mappingFunction, C param1,
T param2) {
Objects.requireNonNull(target, "target");
Objects.requireNonNull(key, "key");
Objects.requireNonNull(mappingFunction, "mappingFunction");
Objects.requireNonNull(param1, "param1");
Objects.requireNonNull(param2, "param2");
V val = target.get(key);
if (val == null) {
V ret = mappingFunction.apply(param1, param2);
target.put(key, ret);
return ret;
}
return val;
}
/**
* remove value, Thread safety depends on whether the Map is a thread-safe Map.
*
* @param map map
* @param key key
* @param removeJudge judge this key can be remove
* @param <K> key type
* @param <V> value type
* @return value
*/
public static <K, V> V removeKey(Map<K, V> map, K key, Predicate<V> removeJudge) {
return map.computeIfPresent(key, (k, v) -> removeJudge.test(v) ? null : v);
}
}

@ -0,0 +1,199 @@
/*
* 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 cn.hippo4j.common.toolkit.http;
import cn.hippo4j.common.constant.Constants;
import cn.hippo4j.common.constant.HttpHeaderConstants;
import cn.hippo4j.common.constant.HttpMediaType;
import cn.hippo4j.common.toolkit.MapUtil;
import cn.hippo4j.common.toolkit.StringUtil;
import java.util.*;
/**
* Http header.
*
* @author <a href="mailto:liaochuntao@live.com">liaochuntao</a>
*/
public class Header {
public static final Header EMPTY = Header.newInstance();
private final Map<String, String> header;
private final Map<String, List<String>> originalResponseHeader;
private static final String DEFAULT_CHARSET = "UTF-8";
private static final String DEFAULT_ENCODING = "gzip";
private Header() {
header = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
originalResponseHeader = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
addParam(HttpHeaderConstants.CONTENT_TYPE, HttpMediaType.APPLICATION_JSON);
addParam(HttpHeaderConstants.ACCEPT_CHARSET, DEFAULT_CHARSET);
}
public static Header newInstance() {
return new Header();
}
/**
* Add the key and value to the header.
*
* @param key the key
* @param value the value
* @return header
*/
public Header addParam(String key, String value) {
if (StringUtil.isNotEmpty(key)) {
header.put(key, value);
}
return this;
}
public Header setContentType(String contentType) {
if (contentType == null) {
contentType = HttpMediaType.APPLICATION_JSON;
}
return addParam(HttpHeaderConstants.CONTENT_TYPE, contentType);
}
public Header build() {
return this;
}
public String getValue(String key) {
return header.get(key);
}
public Map<String, String> getHeader() {
return header;
}
public Iterator<Map.Entry<String, String>> iterator() {
return header.entrySet().iterator();
}
/**
* Transfer to KV part list. The odd index is key and the even index is value.
*
* @return KV string list
*/
public List<String> toList() {
List<String> list = new ArrayList<>(header.size() * 2);
Iterator<Map.Entry<String, String>> iterator = iterator();
while (iterator.hasNext()) {
Map.Entry<String, String> entry = iterator.next();
list.add(entry.getKey());
list.add(entry.getValue());
}
return list;
}
/**
* Add all KV list to header. The odd index is key and the even index is value.
*
* @param list KV list
* @return header
*/
public Header addAll(List<String> list) {
if ((list.size() & 1) != 0) {
throw new IllegalArgumentException("list size must be a multiple of 2");
}
for (int i = 0; i < list.size();) {
String key = list.get(i++);
if (StringUtil.isNotEmpty(key)) {
header.put(key, list.get(i++));
}
}
return this;
}
/**
* Add all parameters to header.
*
* @param params parameters
*/
public void addAll(Map<String, String> params) {
if (MapUtil.isNotEmpty(params)) {
for (Map.Entry<String, String> entry : params.entrySet()) {
addParam(entry.getKey(), entry.getValue());
}
}
}
/**
* set original format response header.
*
* <p>Currently only corresponds to the response header of JDK.
*
* @param key original response header key
* @param values original response header values
*/
public void addOriginalResponseHeader(String key, List<String> values) {
if (StringUtil.isNotEmpty(key)) {
this.originalResponseHeader.put(key, values);
addParam(key, values.get(0));
}
}
/**
* get original format response header.
*
* <p>Currently only corresponds to the response header of JDK.
*
* @return Map original response header
*/
public Map<String, List<String>> getOriginalResponseHeader() {
return this.originalResponseHeader;
}
public String getCharset() {
String acceptCharset = getValue(HttpHeaderConstants.ACCEPT_CHARSET);
if (acceptCharset == null) {
String contentType = getValue(HttpHeaderConstants.CONTENT_TYPE);
acceptCharset = StringUtil.isNotBlank(contentType) ? analysisCharset(contentType) : Constants.ENCODE;
}
return acceptCharset;
}
private String analysisCharset(String contentType) {
String[] values = contentType.split(";");
String charset = Constants.ENCODE;
if (values.length == 0) {
return charset;
}
for (String value : values) {
if (value.startsWith("charset=")) {
charset = value.substring("charset=".length());
}
}
return charset;
}
public void clear() {
header.clear();
originalResponseHeader.clear();
}
@Override
public String toString() {
return "Header{" + "headerToMap=" + header + '}';
}
}

@ -0,0 +1,70 @@
/*
* 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 cn.hippo4j.common.toolkit.http;
import java.io.Closeable;
import java.io.InputStream;
/**
* Represents a client-side HTTP response.
*
* @author mai.jh
*/
public interface HttpClientResponse extends Closeable {
/**
* Return the headers of this message.
*
* @return a corresponding HttpHeaders object (never {@code null})
*/
Header getHeaders();
/**
* Return the body of the message as an input stream.
*
* @return String response body
*/
InputStream getBody();
/**
* Return the HTTP status code.
*
* @return the HTTP status as an integer
*/
int getStatusCode();
/**
* Return the HTTP status text of the response.
*
* @return the HTTP status text
*/
String getStatusText();
/**
* Return the body As string.
*
* @return
*/
String getBodyString();
/**
* close response InputStream.
*/
@Override
void close();
}

@ -0,0 +1,360 @@
/*
* 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 cn.hippo4j.common.toolkit.http;
import cn.hippo4j.common.constant.Constants;
import cn.hippo4j.common.constant.HttpMediaType;
import cn.hippo4j.common.constant.HttpMethod;
import cn.hippo4j.common.constant.HttpResponseCode;
import cn.hippo4j.common.toolkit.CollectionUtil;
import cn.hippo4j.common.toolkit.IoUtil;
import cn.hippo4j.common.toolkit.JSONUtil;
import cn.hippo4j.common.toolkit.StringUtil;
import cn.hippo4j.common.toolkit.logtracing.LogMessage;
import cn.hippo4j.common.web.exception.ServiceException;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
import java.util.Map;
import java.util.Optional;
import static cn.hippo4j.common.constant.HttpHeaderConstants.CONTENT_LENGTH;
/**
* Http request utilities.
*
* @author Rongzhen Yan
*/
@Slf4j
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public class HttpUtil {
/**
* Default connect timeout
*/
private static final int DEFAULT_CONNECT_TIMEOUT = 10000;
/**
* Default read timeout
*/
private static final int DEFAULT_READ_TIMEOUT = 30000;
/**
* Send a get network request.
*
* @param url target url
* @param headers headers
* @param params form data
* @param timeout request timeout
* @param clazz return the target data type
* @param <T> return the target data type
* @return
*/
public static <T> T get(String url, Map<String, String> headers, Map<String, String> params, long timeout, Class<T> clazz) {
return execute(buildUrl(url, params), HttpMethod.GET, null, headers, timeout, clazz);
}
/**
* Send a get network request.
*
* @param url target url
* @param params form data
* @return
*/
public static String get(String url, Map<String, String> params) {
return execute(buildUrl(url, params), HttpMethod.GET, null, null);
}
/**
* Send a get network request.
*
* @param url target url
* @return
*/
public static String get(String url) {
return execute(url, HttpMethod.GET, null, null);
}
/**
* Send a get network request.
*
* @param url target url
* @param clazz return the target data type
* @param <T> return the target data type
* @return
*/
public static <T> T get(String url, Class<T> clazz) {
return JSONUtil.parseObject(get(url), clazz);
}
/**
* Send a post network request.
*
* @param url target url
* @param body request body
* @param clazz return the target data type
* @param <T> return the target data type
* @return
*/
public static <T> T post(String url, Object body, Class<T> clazz) {
String result = post(url, body);
return JSONUtil.parseObject(result, clazz);
}
/**
* Send a post network request.
*
* @param url target url
* @param body request body
* @param timeout request timeout
* @param clazz return the target data type
* @param <T> return the target data type
* @return
*/
public static <T> T post(String url, Object body, long timeout, Class<T> clazz) {
String result = post(url, body, timeout);
return JSONUtil.parseObject(result, clazz);
}
/**
* Send a post network request.
*
* @param url target url
* @param headers headers
* @param params form data
* @param timeout request timeout
* @param clazz return the target data type
* @param <T> return the target data type
* @return
*/
public static <T> T post(String url, Map<String, String> headers, Map<String, String> params, long timeout, Class<T> clazz) {
return execute(buildUrl(url, params), HttpMethod.POST, null, headers, timeout, clazz);
}
/**
* Send a post network request.
*
* @param url target url
* @param headers headers
* @param body request body
* @param timeout request timeout
* @param clazz return the target data type
* @param <T> return the target data type
* @return
*/
public static <T> T post(String url, Map<String, String> headers, Object body, long timeout, Class<T> clazz) {
return execute(url, HttpMethod.POST, body, headers, timeout, clazz);
}
/**
* Send a post network request.
*
* @param url target url
* @param body request body
* @return
*/
public static String post(String url, Object body) {
return execute(url, HttpMethod.POST, body, null);
}
/**
* Send a post network request.
*
* @param url target url
* @param body request body
* @param timeout request timeout
* @return
*/
public static String post(String url, Object body, long timeout) {
return execute(url, HttpMethod.POST, body, null, timeout, String.class);
}
/**
* Send a post network request.
*
* @param url target url
* @param json json data
* @return
*/
public static String postJson(String url, String json) {
return executeJson(url, HttpMethod.POST, json, null);
}
/**
* Send a put network request.
*
* @param url target url
* @param body request body
* @return
*/
public static String put(String url, Object body) {
return execute(url, HttpMethod.PUT, body, null);
}
/**
* Send a put network request.
*
* @param url target url
* @param body request body
* @param headers headers
* @return
*/
public static String put(String url, Object body, Map<String, String> headers) {
return execute(url, HttpMethod.PUT, body, headers);
}
/**
* Constructs a complete Url from the query string.
*
* @param url target url
* @param queryParams query params
* @return
*/
@SneakyThrows
public static String buildUrl(String url, Map<String, String> queryParams) {
if (CollectionUtil.isEmpty(queryParams)) {
return url;
}
boolean isFirst = true;
StringBuilder builder = new StringBuilder(url);
for (Map.Entry<String, String> entry : queryParams.entrySet()) {
String key = entry.getKey();
if (key != null && entry.getValue() != null) {
if (isFirst) {
isFirst = false;
builder.append("?");
} else {
builder.append("&");
}
String value = URLEncoder.encode(queryParams.get(key), Constants.ENCODE)
.replaceAll("\\+", "%20");
builder.append(key)
.append("=")
.append(value);
}
}
return builder.toString();
}
private static String executeJson(String url, String method, String json, Map<String, String> headers) {
if (!JSONUtil.isJson(json)) {
log.error(LogMessage.getInstance().setMsg("Http Call error.")
.kv("url", url)
.kv("method", method)
.kv("json", json)
.kv2String("headers", JSONUtil.toJSONString(headers)));
throw new ServiceException("Invalid http json body, please check it again.");
}
return execute(url, method, json, headers);
}
private static String execute(String url, String method, Object param, Map<String, String> headers) {
HttpURLConnection connection = createConnection(url, method);
HttpClientResponse response = null;
try {
response = doExecute(connection, param, headers);
return response.getBodyString();
} finally {
Optional.ofNullable(response).ifPresent(each -> each.close());
}
}
private static <T> T execute(String url, String method, Object body, Map<String, String> headers, long timeout, Class<T> clazz) {
HttpURLConnection connection = createConnection(url, method, timeout);
HttpClientResponse response = null;
try {
response = doExecute(connection, body, headers);
if (clazz == String.class) {
return (T) response.getBodyString();
}
return JSONUtil.parseObject(response.getBodyString(), clazz);
} finally {
Optional.ofNullable(response).ifPresent(each -> each.close());
}
}
@SneakyThrows
private static HttpClientResponse doExecute(HttpURLConnection connection, Object body, Map<String, String> headers) {
try {
if (headers != null && headers.size() > 0) {
for (Map.Entry<String, String> entry : headers.entrySet()) {
connection.setRequestProperty(entry.getKey(), entry.getValue());
}
}
String bodyString;
if (body instanceof String) {
bodyString = (String) body;
} else {
bodyString = JSONUtil.toJSONString(body);
}
if (!StringUtil.isEmpty(bodyString)) {
connection.setDoOutput(true);
byte[] b = bodyString.getBytes();
connection.setRequestProperty(CONTENT_LENGTH, String.valueOf(b.length));
OutputStream outputStream = connection.getOutputStream();
outputStream.write(b, 0, b.length);
outputStream.flush();
IoUtil.closeQuietly(outputStream);
}
connection.connect();
JdkHttpClientResponse response = new JdkHttpClientResponse(connection);
if (HttpResponseCode.SC_OK != response.getStatusCode()) {
String msg = String.format("HttpPost response code error. [code] %s [url] %s [body] %s", response.getStatusCode(), connection.getURL(), response.getBodyString());
throw new ServiceException(msg);
}
return response;
} catch (Throwable ex) {
log.error(LogMessage.getInstance().setMsg("Http call error. ")
.kv("url", connection.getURL())
.kv("method", connection.getRequestMethod())
.kv("body", JSONUtil.toJSONString(body))
.kv2String("headers", JSONUtil.toJSONString(headers)), ex);
throw ex;
}
}
@SneakyThrows
private static HttpURLConnection createConnection(String url, String method) {
HttpURLConnection connection = (HttpURLConnection) new URL(url).openConnection();
connection.setDoInput(true);
connection.setDoOutput(true);
connection.setConnectTimeout(DEFAULT_CONNECT_TIMEOUT);
connection.setReadTimeout(DEFAULT_READ_TIMEOUT);
connection.setRequestMethod(method);
connection.setRequestProperty(Constants.CONTENT_TYPE, HttpMediaType.APPLICATION_JSON);
return connection;
}
@SneakyThrows
private static HttpURLConnection createConnection(String url, String method, long timeout) {
HttpURLConnection connection = (HttpURLConnection) new URL(url).openConnection();
connection.setDoInput(true);
connection.setDoOutput(true);
connection.setConnectTimeout(Integer.parseInt(String.valueOf(timeout)));
connection.setReadTimeout(Integer.parseInt(String.valueOf(timeout)));
connection.setRequestMethod(method);
connection.setRequestProperty(Constants.CONTENT_TYPE, HttpMediaType.APPLICATION_JSON);
return connection;
}
}

@ -0,0 +1,97 @@
/*
* 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 cn.hippo4j.common.toolkit.http;
import cn.hippo4j.common.constant.Constants;
import cn.hippo4j.common.constant.HttpHeaderConstants;
import cn.hippo4j.common.toolkit.IoUtil;
import lombok.SneakyThrows;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.util.List;
import java.util.Map;
/**
* Represents a client-side HTTP response with JDK implementation
*
* @author Rongzhen Yan
*/
public class JdkHttpClientResponse implements HttpClientResponse {
private final HttpURLConnection conn;
private InputStream responseStream;
private Header responseHeader;
private static final String CONTENT_ENCODING = "gzip";
public JdkHttpClientResponse(HttpURLConnection conn) {
this.conn = conn;
}
@Override
public Header getHeaders() {
if (this.responseHeader == null) {
this.responseHeader = Header.newInstance();
}
for (Map.Entry<String, List<String>> entry : conn.getHeaderFields().entrySet()) {
this.responseHeader.addOriginalResponseHeader(entry.getKey(), entry.getValue());
}
return this.responseHeader;
}
@Override
@SneakyThrows
public InputStream getBody() {
Header headers = getHeaders();
InputStream errorStream = this.conn.getErrorStream();
this.responseStream = (errorStream != null ? errorStream : this.conn.getInputStream());
String contentEncoding = headers.getValue(HttpHeaderConstants.CONTENT_ENCODING);
// Used to process http content_encoding, when content_encoding is GZIP, use GZIPInputStream
if (CONTENT_ENCODING.equals(contentEncoding)) {
byte[] bytes = IoUtil.tryDecompress(this.responseStream);
return new ByteArrayInputStream(bytes);
}
return this.responseStream;
}
@Override
@SneakyThrows
public int getStatusCode() {
return this.conn.getResponseCode();
}
@Override
@SneakyThrows
public String getStatusText() {
return this.conn.getResponseMessage();
}
@Override
public String getBodyString() {
return IoUtil.toString(this.getBody(), Constants.ENCODE);
}
@Override
public void close() {
IoUtil.closeQuietly(this.responseStream);
}
}

@ -0,0 +1,100 @@
/*
* 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 cn.hippo4j.common.toolkit.logtracing;
import cn.hippo4j.common.toolkit.StringUtil;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;
import org.slf4j.helpers.FormattingTuple;
import org.slf4j.helpers.MessageFormatter;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/**
* Log message.
*
* @author Rongzhen Yan
*/
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public class LogMessage {
private Map<String, Object> kvs = new ConcurrentHashMap<>();
private String msg = "";
public static LogMessage getInstance() {
return new LogMessage();
}
public LogMessage setMsg(String msg) {
this.msg = msg;
return this;
}
public String msg(String msg, Object... args) {
LogMessage l = new LogMessage();
l.kvs = this.kvs;
return l.setMsgString(msg, args);
}
public LogMessage setMsg(String msg, Object... args) {
FormattingTuple ft = MessageFormatter.arrayFormat(msg, args);
this.msg = ft.getThrowable() == null ? ft.getMessage() : ft.getMessage() + "||_fmt_throw=" + ft.getThrowable();
return this;
}
public String setMsgString(String msg, Object... args) {
FormattingTuple ft = MessageFormatter.arrayFormat(msg, args);
this.msg = ft.getThrowable() == null ? ft.getMessage() : ft.getMessage() + "||_fmt_throw=" + ft.getThrowable();
return toString();
}
public LogMessage kv(String k, Object v) {
this.kvs.put(k, v == null ? "" : v);
return this;
}
public String kv2String(String k, Object v) {
this.kvs.put(k, v == null ? "" : v);
return toString();
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
if (StringUtil.isNotEmpty(msg)) {
sb.append(msg);
}
int tempCount = 0;
for (Map.Entry<String, Object> kv : kvs.entrySet()) {
tempCount++;
Object value = kv.getValue();
if (value != null) {
if (value instanceof String && StringUtil.isEmpty((String) value)) {
continue;
}
sb.append(kv.getKey() + "=").append(kv.getValue());
if (tempCount != kvs.size()) {
sb.append("||");
}
}
}
return sb.toString();
}
}

@ -17,5 +17,58 @@
package cn.hippo4j.common.executor;
public final class ThreadPoolManagerTest {
import cn.hippo4j.common.toolkit.ReflectUtil;
import org.junit.Assert;
import org.junit.Test;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
public class ThreadPoolManagerTest {
// tenantId = schedulegroup = schedule
ScheduledExecutorService executorService1 = Executors.newScheduledThreadPool(1);
// tenantId = schedulegroup = schedule
ScheduledExecutorService executorService2 = Executors.newScheduledThreadPool(10);
// tenantId = executorgroup = executor
ExecutorService executorService3 = Executors.newFixedThreadPool(8);
// tenantId = executorgroup = executor
ExecutorService executorService4 = Executors.newFixedThreadPool(16);
static final String schedule = "schedule";
static final String executor = "executor";
@Test
public void getInstance() {
ThreadPoolManager poolManager = ThreadPoolManager.getInstance();
Assert.assertNotNull(poolManager);
}
@Test
public void register() {
ThreadPoolManager poolManager = ThreadPoolManager.getInstance();
poolManager.register(schedule, schedule, executorService1);
poolManager.register(schedule, schedule, executorService2);
poolManager.register(executor, executor, executorService3);
poolManager.register(executor, executor, executorService4);
Map<String, Map<String, Set<ExecutorService>>> manager = (Map<String, Map<String, Set<ExecutorService>>>) ReflectUtil.getFieldValue(poolManager, "resourcesManager");
Map<String, Set<ExecutorService>> scheduleMap = manager.get(schedule);
Assert.assertEquals(1, scheduleMap.size());
Set<ExecutorService> scheduleSet = scheduleMap.get(schedule);
Assert.assertEquals(2, scheduleSet.size());
Map<String, Set<ExecutorService>> executorMap = manager.get(executor);
Assert.assertEquals(1, executorMap.size());
Set<ExecutorService> executorSet = executorMap.get(executor);
Assert.assertEquals(2, executorSet.size());
}
}

@ -15,17 +15,19 @@
* limitations under the License.
*/
package cn.hippo4j.common.toolkit;
package cn.hippo4j.common.toolkit.http;
import cn.hippo4j.common.toolkit.JSONUtil;
import lombok.Getter;
import lombok.Setter;
import org.junit.Assert;
import org.junit.Test;
import java.net.SocketTimeoutException;
import java.util.HashMap;
import java.util.Map;
public class HttpClientUtilTest {
public class HttpUtilsTest {
/**
* test post url
@ -37,11 +39,9 @@ public class HttpClientUtilTest {
*/
static String getUrl = "https://hippo4j.cn/";
HttpClientUtil httpClientUtil = HttpClientUtil.build();
@Test
public void get() {
String s = httpClientUtil.get(getUrl);
String s = HttpUtil.get(getUrl);
Assert.assertNotNull(s);
}
@ -52,7 +52,7 @@ public class HttpClientUtilTest {
loginInfo.setPassword("hippo4j");
loginInfo.setUsername("hippo4j");
loginInfo.setRememberMe(1);
String s = httpClientUtil.restApiPost(loginUrl, loginInfo);
String s = HttpUtil.post(loginUrl, loginInfo);
Result result = JSONUtil.parseObject(s, Result.class);
Assert.assertNotNull(result);
String data = result.getData().getData();
@ -66,18 +66,28 @@ public class HttpClientUtilTest {
loginInfo.setPassword("hippo4j");
loginInfo.setUsername("hippo4j");
loginInfo.setRememberMe(1);
Result result = httpClientUtil.restApiPost(loginUrl, loginInfo, Result.class);
Result result = HttpUtil.post(loginUrl, loginInfo, Result.class);
Assert.assertNotNull(result);
String data = result.getData().getData();
Assert.assertNotNull(data);
}
@Test
public void testRestApiPostTimeout() {
String loginUrl = postUrl + "auth/login";
LoginInfo loginInfo = new LoginInfo();
loginInfo.setPassword("hippo4j");
loginInfo.setUsername("hippo4j");
loginInfo.setRememberMe(1);
Assert.assertThrows(SocketTimeoutException.class, () -> HttpUtil.post(loginUrl, loginInfo, 1, Result.class));
}
@Test
public void buildUrl() {
Map<String, String> map = new HashMap<>();
map.put("password", "hippo4j");
map.put("username", "hippo4j");
String s = httpClientUtil.buildUrl(getUrl, map);
String s = HttpUtil.buildUrl(getUrl, map);
Assert.assertEquals(getUrl + "?password=hippo4j&username=hippo4j", s);
}
@ -86,7 +96,9 @@ public class HttpClientUtilTest {
private static class LoginInfo {
private String username;
private String password;
private Integer rememberMe;
}
@ -95,6 +107,7 @@ public class HttpClientUtilTest {
private static class Result {
private String code;
private ResultData data;
}
@ -103,6 +116,7 @@ public class HttpClientUtilTest {
private static class ResultData {
private String data;
private String[] roles;
}
}

File diff suppressed because one or more lines are too long

@ -1 +0,0 @@
.editor-container[data-v-7505e034]{height:82vh;overflow:auto}

File diff suppressed because one or more lines are too long

@ -1,893 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="216"
height="144"
id="svg4136"
version="1.1"
inkscape:version="0.91 r"
sodipodi:docname="jsoneditor-icons.svg">
<title
id="title6512">JSON Editor Icons</title>
<metadata
id="metadata4148">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title>JSON Editor Icons</dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<defs
id="defs4146" />
<sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1920"
inkscape:window-height="1028"
id="namedview4144"
showgrid="true"
inkscape:zoom="4"
inkscape:cx="97.217248"
inkscape:cy="59.950227"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="1"
inkscape:current-layer="svg4136"
showguides="false"
borderlayer="false"
inkscape:showpageshadow="true"
showborder="true">
<inkscape:grid
type="xygrid"
id="grid4640"
empspacing="24" />
</sodipodi:namedview>
<!-- Created with SVG-edit - http://svg-edit.googlecode.com/ -->
<g
id="g4394">
<rect
x="4"
y="4"
width="16"
height="16"
id="svg_1"
style="fill:#1aae1c;fill-opacity:1;stroke:none;stroke-width:0" />
<rect
style="fill:#ec3f29;fill-opacity:0.94117647;stroke:none;stroke-width:0"
x="28.000006"
y="3.999995"
width="16"
height="16"
id="svg_1-7" />
<rect
id="rect4165"
height="16"
width="16"
y="3.999995"
x="52.000004"
style="fill:#4c4c4c;fill-opacity:1;stroke:none;stroke-width:0" />
<rect
style="fill:#4c4c4c;fill-opacity:1;stroke:none;stroke-width:0"
x="172.00002"
y="3.9999852"
width="16"
height="16"
id="rect4175" />
<rect
style="fill:#4c4c4c;fill-opacity:1;stroke:none;stroke-width:0"
x="196"
y="3.999995"
width="16"
height="16"
id="rect4175-3" />
<g
style="stroke:none"
id="g4299">
<rect
style="fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:0"
id="svg_1-1"
height="1.9999986"
width="9.9999924"
y="10.999998"
x="7.0000048" />
<rect
style="fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:0"
id="svg_1-1-1"
height="9.9999838"
width="1.9999955"
y="7.0000114"
x="11.000005" />
</g>
<g
style="stroke:none"
transform="matrix(0.70710678,-0.70710678,0.70710678,0.70710678,19.029435,12.000001)"
id="g4299-3">
<rect
style="fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:0"
id="svg_1-1-0"
height="1.9999986"
width="9.9999924"
y="10.999998"
x="7.0000048" />
<rect
style="fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:0"
id="svg_1-1-1-9"
height="9.9999838"
width="1.9999955"
y="7.0000114"
x="11.000005" />
</g>
<rect
style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:0"
x="55.000004"
y="7.0000048"
width="6.9999909"
height="6.9999905"
id="svg_1-7-5" />
<rect
id="rect4354"
height="6.9999905"
width="6.9999909"
y="10.00001"
x="58"
style="fill:#ffffff;fill-opacity:1;stroke:#4c4c4c;stroke-width:2;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
<rect
style="fill:#ffffff;fill-opacity:1;stroke:#3c80df;stroke-width:0;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:0.94117647"
x="58.000004"
y="10.000005"
width="6.9999909"
height="6.9999905"
id="svg_1-7-5-7" />
<g
id="g4378">
<rect
id="svg_1-7-5-3"
height="1.9999965"
width="7.9999909"
y="10.999999"
x="198"
style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:0" />
<rect
style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:0"
x="198"
y="7.0000005"
width="11.999995"
height="1.9999946"
id="rect4374" />
<rect
style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:0"
x="198"
y="14.999996"
width="3.9999928"
height="1.9999995"
id="rect4376" />
</g>
<g
id="g4383"
transform="matrix(1,0,0,-1,-23.999995,23.999995)">
<rect
style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:0"
x="198"
y="10.999999"
width="7.9999909"
height="1.9999965"
id="rect4385" />
<rect
id="rect4387"
height="1.9999946"
width="11.999995"
y="7.0000005"
x="198"
style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:0" />
<rect
id="rect4389"
height="1.9999995"
width="3.9999928"
y="14.999996"
x="198"
style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:0" />
</g>
<rect
y="3.9999199"
x="76"
height="16"
width="16"
id="rect3754-4"
style="fill:#4c4c4c;fill-opacity:1;stroke:none" />
<path
sodipodi:nodetypes="cccccccc"
inkscape:connector-curvature="0"
id="path4351"
d="m 85.10447,6.0157384 -0.0156,1.4063 c 3.02669,-0.2402 0.33008,3.6507996 2.48438,4.5780996 -2.18694,1.0938 0.49191,4.9069 -2.45313,4.5781 l -0.0156,1.4219 c 5.70828,0.559 1.03264,-5.1005 4.70313,-5.2656 l 0,-1.4063 c -3.61303,-0.027 1.11893,-5.7069996 -4.70313,-5.3124996 z"
style="fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:0.2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
<path
sodipodi:nodetypes="cccccccc"
inkscape:connector-curvature="0"
id="path4351-9"
d="m 82.78125,5.9984384 0.0156,1.4063 c -3.02668,-0.2402 -0.33007,3.6506996 -2.48437,4.5780996 2.18694,1.0938 -0.49192,4.9069 2.45312,4.5781 l 0.0156,1.4219 c -5.70827,0.559 -1.03263,-5.1004 -4.70312,-5.2656 l 0,-1.4063 c 3.61303,-0.027 -1.11894,-5.7070996 4.70312,-5.3124996 z"
style="fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:0.2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
<rect
y="3.9999199"
x="100"
height="16"
width="16"
id="rect3754-25"
style="fill:#4c4c4c;fill-opacity:1;stroke:none" />
<path
inkscape:connector-curvature="0"
id="path2987"
d="m 103.719,5.6719384 0,12.7187996 3.03125,0 0,-1.5313 -1.34375,0 0,-9.6249996 1.375,0 0,-1.5625 z"
style="fill:#ffffff;fill-opacity:1;stroke:none" />
<path
inkscape:connector-curvature="0"
id="path2987-1"
d="m 112.2185,5.6721984 0,12.7187996 -3.03125,0 0,-1.5313 1.34375,0 0,-9.6249996 -1.375,0 0,-1.5625 z"
style="fill:#ffffff;fill-opacity:1;stroke:none" />
<rect
y="3.9999199"
x="124"
height="16"
width="16"
id="rect3754-73"
style="fill:#4c4c4c;fill-opacity:1;stroke:none" />
<path
sodipodi:nodetypes="ccccccccc"
inkscape:connector-curvature="0"
id="path3780"
d="m 126.2824,17.602938 1.78957,0 1.14143,-2.8641 5.65364,0 1.14856,2.8641 1.76565,0 -4.78687,-11.1610996 -1.91903,0 z"
style="fill:#ffffff;fill-opacity:1;stroke:none" />
<path
inkscape:connector-curvature="0"
id="path3782"
d="m 129.72704,13.478838 4.60852,0.01 -2.30426,-5.5497996 z"
style="fill:#4c4c4c;fill-opacity:1;stroke:none" />
<rect
y="3.9999199"
x="148"
height="16"
width="16"
id="rect3754-35"
style="fill:#4c4c4c;fill-opacity:1;stroke:none" />
<path
sodipodi:nodetypes="ccccccc"
inkscape:connector-curvature="0"
id="path5008-2"
d="m 156.47655,5.8917384 0,2.1797 0.46093,2.3983996 1.82813,0 0.39844,-2.3983996 0,-2.1797 z"
style="fill:#ffffff;fill-opacity:1;stroke:none" />
<path
sodipodi:nodetypes="ccccccc"
inkscape:connector-curvature="0"
id="path5008-2-8"
d="m 152.51561,5.8906384 0,2.1797 0.46094,2.3983996 1.82812,0 0.39844,-2.3983996 0,-2.1797 z"
style="fill:#ffffff;fill-opacity:1;stroke:none" />
</g>
<rect
x="4"
y="27.999994"
width="16"
height="16"
id="rect4432"
style="fill:#d3d3d3;fill-opacity:1;stroke:none;stroke-width:0" />
<rect
style="fill:#d3d3d3;fill-opacity:1;stroke:none;stroke-width:0"
x="28.000006"
y="27.99999"
width="16"
height="16"
id="rect4434" />
<rect
id="rect4436"
height="16"
width="16"
y="27.99999"
x="52.000004"
style="fill:#d3d3d3;fill-opacity:1;stroke:#000000;stroke-width:0" />
<rect
style="fill:#d3d3d3;stroke:#000000;stroke-width:0"
x="172.00002"
y="27.999981"
width="16"
height="16"
id="rect4446" />
<rect
style="fill:#d3d3d3;stroke:#000000;stroke-width:0"
x="196"
y="27.99999"
width="16"
height="16"
id="rect4448" />
<g
id="g4466"
style="stroke:none"
transform="translate(0,23.999995)">
<rect
style="fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:0"
id="rect4468"
height="1.9999986"
width="9.9999924"
y="10.999998"
x="7.0000048" />
<rect
style="fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:0"
id="rect4470"
height="9.9999838"
width="1.9999955"
y="7.0000114"
x="11.000005" />
</g>
<g
transform="matrix(0.70710678,-0.70710678,0.70710678,0.70710678,19.029435,35.999996)"
id="g4472"
style="stroke:none">
<rect
style="fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:0"
id="rect4474"
height="1.9999986"
width="9.9999924"
y="10.999998"
x="7.0000048" />
<rect
style="fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:0"
id="rect4476"
height="9.9999838"
width="1.9999955"
y="7.0000114"
x="11.000005" />
</g>
<rect
style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:0"
x="55.000004"
y="31"
width="6.9999909"
height="6.9999905"
id="rect4478" />
<rect
id="rect4480"
height="6.9999905"
width="6.9999909"
y="34.000008"
x="58"
style="fill:#ffffff;fill-opacity:1;stroke:#d3d3d3;stroke-width:2;stroke-miterlimit:4;stroke-dasharray:none" />
<rect
style="fill:#ffffff;fill-opacity:1;stroke:#d3d3d3;stroke-width:0;stroke-miterlimit:4;stroke-dasharray:none"
x="58.000004"
y="34.000004"
width="6.9999909"
height="6.9999905"
id="rect4482" />
<g
id="g4484"
transform="translate(0,23.999995)">
<rect
id="rect4486"
height="1.9999965"
width="7.9999909"
y="10.999999"
x="198"
style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:0" />
<rect
style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:0"
x="198"
y="7.0000005"
width="11.999995"
height="1.9999946"
id="rect4488" />
<rect
style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:0"
x="198"
y="14.999996"
width="3.9999928"
height="1.9999995"
id="rect4490" />
</g>
<g
id="g4492"
transform="matrix(1,0,0,-1,-23.999995,47.99999)">
<rect
style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:0"
x="198"
y="10.999999"
width="7.9999909"
height="1.9999965"
id="rect4494" />
<rect
id="rect4496"
height="1.9999946"
width="11.999995"
y="7.0000005"
x="198"
style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:0" />
<rect
id="rect4498"
height="1.9999995"
width="3.9999928"
y="14.999996"
x="198"
style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:0" />
</g>
<rect
style="fill:#d3d3d3;fill-opacity:1;stroke:none"
id="rect3754-8"
width="16"
height="16"
x="76"
y="27.99992" />
<path
style="fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:0.2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 85.10448,30.015537 -0.0156,1.4063 c 3.02668,-0.2402 0.33007,3.6508 2.48438,4.5781 -2.18695,1.0938 0.49191,4.90688 -2.45313,4.57808 l -0.0156,1.4219 c 5.70827,0.559 1.03263,-5.10048 4.70313,-5.26558 l 0,-1.4063 c -3.61304,-0.027 1.11893,-5.707 -4.70313,-5.3125 z"
id="path4351-1"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cccccccc" />
<path
style="fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:0.2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 82.78126,29.998237 0.0156,1.4063 c -3.02668,-0.2402 -0.33008,3.6507 -2.48438,4.5781 2.18694,1.0938 -0.49191,4.90688 2.45313,4.57808 l 0.0156,1.4219 c -5.70828,0.559 -1.03264,-5.10038 -4.70313,-5.26558 l 0,-1.4063 c 3.61303,-0.027 -1.11893,-5.7071 4.70313,-5.3125 z"
id="path4351-9-5"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cccccccc" />
<rect
style="fill:#d3d3d3;fill-opacity:1;stroke:none"
id="rect3754-65"
width="16"
height="16"
x="100"
y="27.99992" />
<path
style="fill:#ffffff;fill-opacity:1;stroke:none"
d="m 103.719,29.671937 0,12.71878 3.03125,0 0,-1.5313 -1.34375,0 0,-9.62498 1.375,0 0,-1.5625 z"
id="path2987-8"
inkscape:connector-curvature="0" />
<path
style="fill:#ffffff;fill-opacity:1;stroke:none"
d="m 112.2185,29.671937 0,12.71878 -3.03125,0 0,-1.5313 1.34375,0 0,-9.62498 -1.375,0 0,-1.5625 z"
id="path2987-1-9"
inkscape:connector-curvature="0" />
<rect
style="fill:#d3d3d3;fill-opacity:1;stroke:none"
id="rect3754-92"
width="16"
height="16"
x="124"
y="27.99992" />
<path
style="fill:#ffffff;fill-opacity:1;stroke:none"
d="m 126.2824,41.602917 1.78957,0 1.14143,-2.86408 5.65364,0 1.14856,2.86408 1.76565,0 -4.78687,-11.16108 -1.91902,0 z"
id="path3780-9"
inkscape:connector-curvature="0"
sodipodi:nodetypes="ccccccccc" />
<path
style="fill:#d3d3d3;fill-opacity:1;stroke:none"
d="m 129.72704,37.478837 4.60852,0.01 -2.30426,-5.5498 z"
id="path3782-2"
inkscape:connector-curvature="0" />
<rect
style="fill:#d3d3d3;fill-opacity:1;stroke:none"
id="rect3754-47"
width="16"
height="16"
x="148"
y="27.99992" />
<path
style="fill:#ffffff;fill-opacity:1;stroke:none"
d="m 156.47656,29.891737 0,2.1797 0.46093,2.3984 1.82813,0 0.39844,-2.3984 0,-2.1797 z"
id="path5008-2-1"
inkscape:connector-curvature="0"
sodipodi:nodetypes="ccccccc" />
<path
style="fill:#ffffff;fill-opacity:1;stroke:none"
d="m 152.51562,29.890637 0,2.1797 0.46094,2.3984 1.82812,0 0.39844,-2.3984 0,-2.1797 z"
id="path5008-2-8-8"
inkscape:connector-curvature="0"
sodipodi:nodetypes="ccccccc" />
<rect
id="svg_1-7-2"
height="1.9999961"
width="11.999996"
y="64"
x="54"
style="fill:#4c4c4c;fill-opacity:0.98431373;stroke:none;stroke-width:0" />
<rect
id="svg_1-7-2-2"
height="2.9999905"
width="2.9999907"
y="52"
x="80.000008"
style="fill:#4c4c4c;fill-opacity:0.98431373;stroke:none;stroke-width:0" />
<rect
style="fill:#4c4c4c;fill-opacity:0.98431373;stroke:none;stroke-width:0"
x="85.000008"
y="52"
width="2.9999907"
height="2.9999905"
id="rect4561" />
<rect
style="fill:#4c4c4c;fill-opacity:0.98431373;stroke:none;stroke-width:0"
x="80.000008"
y="58"
width="2.9999907"
height="2.9999905"
id="rect4563" />
<rect
id="rect4565"
height="2.9999905"
width="2.9999907"
y="58"
x="85.000008"
style="fill:#4c4c4c;fill-opacity:0.98431373;stroke:none;stroke-width:0" />
<rect
id="rect4567"
height="2.9999905"
width="2.9999907"
y="64"
x="80.000008"
style="fill:#4c4c4c;fill-opacity:0.98431373;stroke:none;stroke-width:0" />
<rect
style="fill:#4c4c4c;fill-opacity:0.98431373;stroke:none;stroke-width:0"
x="85.000008"
y="64"
width="2.9999907"
height="2.9999905"
id="rect4569" />
<circle
style="opacity:1;fill:none;fill-opacity:1;stroke:#4c4c4c;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none"
id="path4571"
cx="110.06081"
cy="57.939209"
r="4.7438836" />
<rect
style="fill:#4c4c4c;fill-opacity:0.98431373;stroke:none;stroke-width:0"
x="116.64566"
y="-31.79752"
width="4.229713"
height="6.4053884"
id="rect4563-2"
transform="matrix(0.70710678,0.70710678,-0.70710678,0.70710678,0,0)" />
<path
style="fill:#4c4c4c;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="M 125,56 138.77027,56.095 132,64 Z"
id="path4613"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cccc" />
<path
sodipodi:nodetypes="cccc"
inkscape:connector-curvature="0"
id="path4615"
d="M 149,64 162.77027,63.905 156,56 Z"
style="fill:#4c4c4c;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
<rect
style="fill:#4c4c4c;fill-opacity:0.98431373;stroke:none;stroke-width:0"
x="54"
y="53"
width="11.999996"
height="1.9999961"
id="rect4638" />
<rect
id="svg_1-7-2-24"
height="1.9999957"
width="12.99999"
y="-56"
x="53"
style="fill:#4c4c4c;fill-opacity:0.98431373;stroke:none;stroke-width:0"
transform="matrix(0,1,-1,0,0,0)" />
<rect
transform="matrix(0,1,-1,0,0,0)"
style="fill:#4c4c4c;fill-opacity:0.98431373;stroke:none;stroke-width:0"
x="53"
y="-66"
width="12.99999"
height="1.9999957"
id="rect4657" />
<rect
id="rect4659"
height="0.99999291"
width="11.999999"
y="57"
x="54"
style="fill:#4c4c4c;fill-opacity:0.98431373;stroke:none;stroke-width:0" />
<rect
style="fill:#d3d3d3;fill-opacity:1;stroke:none;stroke-width:0;stroke-opacity:1"
x="54"
y="88.000122"
width="11.999996"
height="1.9999961"
id="rect4661" />
<rect
style="fill:#d3d3d3;fill-opacity:1;stroke:none;stroke-width:0;stroke-opacity:1"
x="80.000008"
y="76.000122"
width="2.9999907"
height="2.9999905"
id="rect4663" />
<rect
id="rect4665"
height="2.9999905"
width="2.9999907"
y="76.000122"
x="85.000008"
style="fill:#d3d3d3;fill-opacity:1;stroke:none;stroke-width:0;stroke-opacity:1" />
<rect
id="rect4667"
height="2.9999905"
width="2.9999907"
y="82.000122"
x="80.000008"
style="fill:#d3d3d3;fill-opacity:1;stroke:none;stroke-width:0;stroke-opacity:1" />
<rect
style="fill:#d3d3d3;fill-opacity:1;stroke:none;stroke-width:0;stroke-opacity:1"
x="85.000008"
y="82.000122"
width="2.9999907"
height="2.9999905"
id="rect4669" />
<rect
style="fill:#d3d3d3;fill-opacity:1;stroke:none;stroke-width:0;stroke-opacity:1"
x="80.000008"
y="88.000122"
width="2.9999907"
height="2.9999905"
id="rect4671" />
<rect
id="rect4673"
height="2.9999905"
width="2.9999907"
y="88.000122"
x="85.000008"
style="fill:#d3d3d3;fill-opacity:1;stroke:none;stroke-width:0;stroke-opacity:1" />
<circle
r="4.7438836"
cy="81.939331"
cx="110.06081"
id="circle4675"
style="opacity:1;fill:none;fill-opacity:1;stroke:#d3d3d3;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
<rect
transform="matrix(0.70710678,0.70710678,-0.70710678,0.70710678,0,0)"
id="rect4677"
height="6.4053884"
width="4.229713"
y="-14.826816"
x="133.6163"
style="fill:#d3d3d3;fill-opacity:1;stroke:#d3d3d3;stroke-width:0;stroke-opacity:1" />
<path
sodipodi:nodetypes="cccc"
inkscape:connector-curvature="0"
id="path4679"
d="m 125,80.000005 13.77027,0.09499 L 132,87.999992 Z"
style="fill:#d3d3d3;fill-opacity:1;fill-rule:evenodd;stroke:#d3d3d3;stroke-width:0;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
<path
style="fill:#d3d3d3;fill-opacity:1;fill-rule:evenodd;stroke:#d3d3d3;stroke-width:0;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="M 149,88.0002 162.77027,87.9052 156,80.0002 Z"
id="path4681"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cccc" />
<rect
id="rect4683"
height="1.9999961"
width="11.999996"
y="77.000122"
x="54"
style="fill:#d3d3d3;fill-opacity:1;stroke:none;stroke-width:0;stroke-opacity:1" />
<rect
transform="matrix(0,1,-1,0,0,0)"
style="fill:#d3d3d3;fill-opacity:1;stroke:none;stroke-width:0;stroke-opacity:1"
x="77.000122"
y="-56"
width="12.99999"
height="1.9999957"
id="rect4685" />
<rect
id="rect4687"
height="1.9999957"
width="12.99999"
y="-66"
x="77.000122"
style="fill:#d3d3d3;fill-opacity:1;stroke:none;stroke-width:0;stroke-opacity:1"
transform="matrix(0,1,-1,0,0,0)" />
<rect
style="fill:#d3d3d3;fill-opacity:1;stroke:none;stroke-width:0;stroke-opacity:1"
x="54"
y="81.000122"
width="11.999999"
height="0.99999291"
id="rect4689" />
<rect
id="rect4761-1"
height="1.9999945"
width="15.99999"
y="101"
x="76.000008"
style="fill:#ffffff;fill-opacity:0.80000007;stroke:none;stroke-width:0" />
<rect
id="rect4761-0"
height="1.9999945"
width="15.99999"
y="105"
x="76.000008"
style="fill:#ffffff;fill-opacity:0.80000007;stroke:none;stroke-width:0" />
<rect
id="rect4761-7"
height="1.9999945"
width="9"
y="109"
x="76.000008"
style="fill:#ffffff;fill-opacity:0.80000007;stroke:none;stroke-width:0" />
<rect
id="rect4761-1-1"
height="1.9999945"
width="12"
y="125"
x="76.000008"
style="fill:#ffffff;fill-opacity:0.80000007;stroke:none;stroke-width:0" />
<rect
id="rect4761-1-1-4"
height="1.9999945"
width="10"
y="137"
x="76.000008"
style="fill:#ffffff;fill-opacity:0.80000007;stroke:none;stroke-width:0" />
<rect
id="rect4761-1-1-4-4"
height="1.9999945"
width="10"
y="129"
x="82"
style="fill:#ffffff;fill-opacity:0.80000007;stroke:none;stroke-width:0" />
<rect
id="rect4761-1-1-4-4-3"
height="1.9999945"
width="9"
y="133"
x="82"
style="fill:#ffffff;fill-opacity:0.80000007;stroke:none;stroke-width:0" />
<path
inkscape:connector-curvature="0"
style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;baseline-shift:baseline;text-anchor:start;white-space:normal;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.8;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2.66157866;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
d="m 36.398438,100.0254 c -0.423362,-0.013 -0.846847,0.01 -1.265626,0.062 -1.656562,0.2196 -3.244567,0.9739 -4.507812,2.2266 L 29,100.5991 l -2.324219,7.7129 7.826172,-1.9062 -1.804687,-1.9063 c 1.597702,-1.5308 4.048706,-1.8453 5.984375,-0.7207 1.971162,1.1452 2.881954,3.3975 2.308593,5.5508 -0.573361,2.1533 -2.533865,3.6953 -4.830078,3.6953 l 0,3.0742 c 3.550756,0 6.710442,-2.4113 7.650391,-5.9414 0.939949,-3.5301 -0.618463,-7.2736 -3.710938,-9.0703 -1.159678,-0.6738 -2.431087,-1.0231 -3.701171,-1.0625 z"
id="path4138" />
<path
inkscape:connector-curvature="0"
style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;baseline-shift:baseline;text-anchor:start;white-space:normal;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.8;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2.66157866;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
d="m 59.722656,99.9629 c -1.270084,0.039 -2.541493,0.3887 -3.701172,1.0625 -3.092475,1.7967 -4.650886,5.5402 -3.710937,9.0703 0.939949,3.5301 4.09768,5.9414 7.648437,5.9414 l 0,-3.0742 c -2.296214,0 -4.256717,-1.542 -4.830078,-3.6953 -0.573361,-2.1533 0.337432,-4.4056 2.308594,-5.5508 1.935731,-1.1246 4.38863,-0.8102 5.986326,0.7207 l -1.806638,1.9063 7.828128,1.9062 -2.32422,-7.7129 -1.62696,1.7168 c -1.26338,-1.2531 -2.848917,-2.0088 -4.505855,-2.2285 -0.418778,-0.055 -0.842263,-0.076 -1.265625,-0.062 z"
id="path4138-1" />
<path
inkscape:connector-curvature="0"
style="opacity:0.8;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1.966;stroke-miterlimit:4;stroke-dasharray:none"
d="m 10.5,100 0,2 -2.4999996,0 L 12,107 l 4,-5 -2.5,0 0,-2 -3,0 z"
id="path3055-0-77" />
<path
style="opacity:0.8;fill:none;stroke:#ffffff;stroke-width:1.966;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 4.9850574,108.015 14.0298856,-0.03"
id="path5244-5-0-5"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cc" />
<path
style="opacity:0.8;fill:none;stroke:#ffffff;stroke-width:1.966;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 4.9849874,132.015 14.0298866,-0.03"
id="path5244-5-0-5-8"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cc" />
<path
inkscape:connector-curvature="0"
style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;baseline-shift:baseline;text-anchor:start;white-space:normal;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.4;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#4d4d4d;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2.66157866;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
d="m 36.398438,123.9629 c -0.423362,-0.013 -0.846847,0.01 -1.265626,0.062 -1.656562,0.2196 -3.244567,0.9739 -4.507812,2.2266 L 29,124.5366 l -2.324219,7.7129 7.826172,-1.9062 -1.804687,-1.9063 c 1.597702,-1.5308 4.048706,-1.8453 5.984375,-0.7207 1.971162,1.1453 2.881954,3.3975 2.308593,5.5508 -0.573361,2.1533 -2.533864,3.6953 -4.830078,3.6953 l 0,3.0742 c 3.550757,0 6.710442,-2.4093 7.650391,-5.9394 0.939949,-3.5301 -0.618463,-7.2756 -3.710938,-9.0723 -1.159678,-0.6737 -2.431087,-1.0231 -3.701171,-1.0625 z"
id="path4138-12" />
<path
inkscape:connector-curvature="0"
style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;baseline-shift:baseline;text-anchor:start;white-space:normal;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.4;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#4d4d4d;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2.66157866;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
d="m 59.722656,123.9629 c -1.270084,0.039 -2.541493,0.3888 -3.701172,1.0625 -3.092475,1.7967 -4.650886,5.5422 -3.710937,9.0723 0.939949,3.5301 4.09768,5.9394 7.648437,5.9394 l 0,-3.0742 c -2.296214,0 -4.256717,-1.542 -4.830078,-3.6953 -0.573361,-2.1533 0.337432,-4.4055 2.308594,-5.5508 1.935731,-1.1246 4.38863,-0.8102 5.986326,0.7207 l -1.806638,1.9063 7.828128,1.9062 -2.32422,-7.7129 -1.62696,1.7168 c -1.26338,-1.2531 -2.848917,-2.0088 -4.505855,-2.2285 -0.418778,-0.055 -0.842263,-0.076 -1.265625,-0.062 z"
id="path4138-1-3" />
<path
id="path6191"
d="m 10.5,116 0,-2 -2.4999996,0 L 12,109 l 4,5 -2.5,0 0,2 -3,0 z"
style="opacity:0.8;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1.966;stroke-miterlimit:4;stroke-dasharray:none"
inkscape:connector-curvature="0" />
<path
inkscape:connector-curvature="0"
style="opacity:0.8;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1.966;stroke-miterlimit:4;stroke-dasharray:none"
d="m 10.5,129 0,-2 -2.4999996,0 L 12,122 l 4,5 -2.5,0 0,2 -3,0 z"
id="path6193" />
<path
id="path6195"
d="m 10.5,135 0,2 -2.4999996,0 L 12,142 l 4,-5 -2.5,0 0,-2 -3,0 z"
style="opacity:0.8;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1.966;stroke-miterlimit:4;stroke-dasharray:none"
inkscape:connector-curvature="0" />
<path
sodipodi:type="star"
style="fill:#4d4d4d;fill-opacity:0.90196078;stroke:#d3d3d3;stroke-width:0;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none"
id="path4500"
sodipodi:sides="3"
sodipodi:cx="11.55581"
sodipodi:cy="60.073242"
sodipodi:r1="5.1116104"
sodipodi:r2="2.5558052"
sodipodi:arg1="0"
sodipodi:arg2="1.0471976"
inkscape:flatsided="false"
inkscape:rounded="0"
inkscape:randomized="0"
d="m 16.66742,60.073242 -3.833708,2.213392 -3.8337072,2.213393 0,-4.426785 0,-4.426784 3.8337082,2.213392 z"
inkscape:transform-center-x="-1.2779026" />
<path
inkscape:transform-center-x="1.277902"
d="m -31.500004,60.073242 -3.833708,2.213392 -3.833707,2.213393 0,-4.426785 0,-4.426784 3.833707,2.213392 z"
inkscape:randomized="0"
inkscape:rounded="0"
inkscape:flatsided="false"
sodipodi:arg2="1.0471976"
sodipodi:arg1="0"
sodipodi:r2="2.5558052"
sodipodi:r1="5.1116104"
sodipodi:cy="60.073242"
sodipodi:cx="-36.611614"
sodipodi:sides="3"
id="path4502"
style="fill:#4d4d4d;fill-opacity:0.90196078;stroke:#d3d3d3;stroke-width:0;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none"
sodipodi:type="star"
transform="scale(-1,1)" />
<path
d="m 16.66742,60.073212 -3.833708,2.213392 -3.8337072,2.213392 0,-4.426784 0,-4.426785 3.8337082,2.213392 z"
inkscape:randomized="0"
inkscape:rounded="0"
inkscape:flatsided="false"
sodipodi:arg2="1.0471976"
sodipodi:arg1="0"
sodipodi:r2="2.5558052"
sodipodi:r1="5.1116104"
sodipodi:cy="60.073212"
sodipodi:cx="11.55581"
sodipodi:sides="3"
id="path4504"
style="fill:#4d4d4d;fill-opacity:0.90196078;stroke:#d3d3d3;stroke-width:0;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none"
sodipodi:type="star"
transform="matrix(0,1,-1,0,72.0074,71.7877)"
inkscape:transform-center-y="1.2779029" />
<path
inkscape:transform-center-y="-1.2779026"
transform="matrix(0,-1,-1,0,96,96)"
sodipodi:type="star"
style="fill:#4d4d4d;fill-opacity:0.90196078;stroke:#d3d3d3;stroke-width:0;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none"
id="path4506"
sodipodi:sides="3"
sodipodi:cx="11.55581"
sodipodi:cy="60.073212"
sodipodi:r1="5.1116104"
sodipodi:r2="2.5558052"
sodipodi:arg1="0"
sodipodi:arg2="1.0471976"
inkscape:flatsided="false"
inkscape:rounded="0"
inkscape:randomized="0"
d="m 16.66742,60.073212 -3.833708,2.213392 -3.8337072,2.213392 0,-4.426784 0,-4.426785 3.8337082,2.213392 z" />
<path
sodipodi:nodetypes="cccc"
inkscape:connector-curvature="0"
id="path4615-5"
d="m 171.82574,65.174193 16.34854,0 -8.17427,-13.348454 z"
style="fill:#fbb917;fill-opacity:1;fill-rule:evenodd;stroke:#fbb917;stroke-width:1.65161395;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
<path
style="opacity:1;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 179,55 0,6 2,0 0,-6"
id="path4300"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cccc" />
<path
style="opacity:1;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 179,62 0,2 2,0 0,-2"
id="path4300-6"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cccc" />
</svg>

Before

Width:  |  Height:  |  Size: 35 KiB

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

@ -1 +0,0 @@
(window["webpackJsonp"]=window["webpackJsonp"]||[]).push([["chunk-2fd02e04"],{"64b7":function(e,t,n){"use strict";n("de5f")},ab3b:function(e,t,n){"use strict";n.r(t);var a=function(){var e=this,t=e.$createElement,n=e._self._c||t;return n("div",{staticClass:"app-container"},[n("split-pane",{attrs:{split:"vertical"},on:{resize:e.resize}},[n("template",{slot:"paneL"},[n("el-input",{attrs:{type:"textarea",rows:36,placeholder:"请输入内容",clearable:""},on:{change:e.originChange},model:{value:e.originText,callback:function(t){e.originText=t},expression:"originText"}})],1),e._v(" "),n("template",{slot:"paneR"},[n("div",{staticClass:"editor-container"},[n("JSONEditor",{attrs:{json:e.formatedValue}})],1)])],2)],1)},i=[],o=n("19ab"),r=n.n(o),s=n("33c3"),c={name:"JsonFormat",components:{splitPane:r.a,JSONEditor:s["a"]},data:function(){return{originText:"",formatedValue:""}},watch:{originText:function(e){try{this.formatedValue=JSON.parse(e)}catch(t){}}},methods:{resize:function(){},originChange:function(e){}}},l=c,u=(n("64b7"),n("2877")),p=Object(u["a"])(l,a,i,!1,null,"7505e034",null);t["default"]=p.exports},de5f:function(e,t,n){}}]);

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

@ -17,13 +17,18 @@
package cn.hippo4j.core.toolkit;
import cn.hippo4j.common.api.ClientNetworkService;
import cn.hippo4j.common.config.ApplicationContextHolder;
import cn.hippo4j.common.toolkit.*;
import cn.hippo4j.common.spi.DynamicThreadPoolServiceLoader;
import cn.hippo4j.common.toolkit.CollectionUtil;
import cn.hippo4j.common.toolkit.IdUtil;
import cn.hippo4j.common.toolkit.Joiner;
import cn.hippo4j.common.toolkit.StringUtil;
import cn.hippo4j.common.toolkit.ThreadUtil;
import cn.hippo4j.core.toolkit.inet.InetUtils;
import org.springframework.core.env.ConfigurableEnvironment;
import java.util.ArrayList;
import java.util.UUID;
import static cn.hippo4j.common.constant.Constants.GROUP_KEY_DELIMITER;
import static cn.hippo4j.common.constant.Constants.IDENTIFY_SLICER_SYMBOL;
@ -37,34 +42,47 @@ public class IdentifyUtil {
public static final String CLIENT_IDENTIFICATION_VALUE = IdUtil.simpleUUID();
static {
DynamicThreadPoolServiceLoader.register(ClientNetworkService.class);
}
/**
* Generate identify.
*
* @param environment
* @param hippo4JInetUtils
* @return
* @param environment environment
* @param inetUtil inet util
* @return identify
*/
public static synchronized String generate(ConfigurableEnvironment environment, InetUtils hippo4JInetUtils) {
public static synchronized String generate(ConfigurableEnvironment environment, InetUtils inetUtil) {
if (StringUtil.isNotBlank(IDENTIFY)) {
return IDENTIFY;
}
String ip = hippo4JInetUtils.findFirstNonLoopBackHostInfo().getIpAddress();
String port = environment.getProperty("server.port", "8080");
String identification = new StringBuilder()
String[] customerNetwork = DynamicThreadPoolServiceLoader.getSingletonServiceInstances(ClientNetworkService.class)
.stream().findFirst().map(each -> each.getNetworkIpPort(environment)).orElse(null);
String ip;
String port;
if (customerNetwork != null && customerNetwork.length > 0) {
ip = customerNetwork[0];
port = customerNetwork[1];
} else {
ip = inetUtil.findFirstNonLoopBackHostInfo().getIpAddress();
port = environment.getProperty("server.port", "8080");
}
String identify = new StringBuilder()
.append(ip)
.append(":")
.append(port)
.append(IDENTIFY_SLICER_SYMBOL)
.append(CLIENT_IDENTIFICATION_VALUE)
.toString();
IDENTIFY = identification;
return identification;
IDENTIFY = identify;
return identify;
}
/**
* Get identify.
*
* @return
* @return identify
*/
public static String getIdentify() {
while (StringUtil.isBlank(IDENTIFY)) {
@ -82,10 +100,10 @@ public class IdentifyUtil {
/**
* Get thread pool identify.
*
* @param threadPoolId
* @param itemId
* @param namespace
* @return
* @param threadPoolId thread pool id
* @param itemId item id
* @param namespace namespace
* @return identify
*/
public static String getThreadPoolIdentify(String threadPoolId, String itemId, String namespace) {
ArrayList<String> params = CollectionUtil.newArrayList(threadPoolId, itemId, namespace, getIdentify());

@ -0,0 +1,81 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>cn.hippo4j</groupId>
<artifactId>hippo4j-example</artifactId>
<version>${revision}</version>
</parent>
<artifactId>hippo4j-config-apollo-spring-boot-1x-starter-example</artifactId>
<properties>
<maven.deploy.skip>true</maven.deploy.skip>
<spring-boot.version>1.5.22.RELEASE</spring-boot.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>cn.hippo4j</groupId>
<artifactId>hippo4j-example-core</artifactId>
<version>${revision}</version>
</dependency>
<dependency>
<groupId>cn.hippo4j</groupId>
<artifactId>hippo4j-config-spring-boot-1x-starter</artifactId>
<version>${revision}</version>
</dependency>
<dependency>
<groupId>com.ctrip.framework.apollo</groupId>
<artifactId>apollo-client</artifactId>
<version>${apollo.version}</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.21</version>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-context</artifactId>
<version>1.3.6.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-registry-prometheus</artifactId>
<version>1.1.3</version>
</dependency>
<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-spring-legacy</artifactId>
<version>1.1.3</version>
</dependency>
</dependencies>
</project>

@ -0,0 +1,31 @@
/*
* 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 cn.hippo4j.example.config.apollo;
import cn.hippo4j.core.enable.EnableDynamicThreadPool;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@EnableDynamicThreadPool
@SpringBootApplication(scanBasePackages = "cn.hippo4j.example.core")
public class ConfigApolloSpringBoot1xExampleApplication {
public static void main(String[] args) {
SpringApplication.run(ConfigApolloSpringBoot1xExampleApplication.class, args);
}
}

@ -0,0 +1,57 @@
server.port=8091
server.servlet.context-path=/example
app.id=dynamic-threadpool-example
apollo.meta=http://127.0.0.1:8080
apollo.autoUpdateInjectedSpringProperties=true
apollo.bootstrap.enabled=true
apollo.bootstrap.namespaces=application
apollo.bootstrap.eagerLoad.enabled=true
spring.profiles.active=dev
spring.application.name=dynamic-threadpool-example
management.security.enabled=false
management.context-path=/actuator
spring.dynamic.thread-pool.enable=true
spring.dynamic.thread-pool.banner=true
spring.dynamic.thread-pool.check-state-interval=5
spring.dynamic.thread-pool.collect-type=micrometer
spring.dynamic.thread-pool.notify-platforms[0].platform=WECHAT
spring.dynamic.thread-pool.notify-platforms[0].token=ac0426a5-c712-474c-9bff-72b8b8f5caff
spring.dynamic.thread-pool.apollo.namespace=application
spring.dynamic.thread-pool.config-file-type=properties
spring.dynamic.thread-pool.executors[0].active-alarm = 80
spring.dynamic.thread-pool.executors[0].alarm = true
spring.dynamic.thread-pool.executors[0].allow-core-thread-time-out = true
spring.dynamic.thread-pool.executors[0].blocking-queue = LinkedBlockingQueue
spring.dynamic.thread-pool.executors[0].capacity-alarm = 80
spring.dynamic.thread-pool.executors[0].core-pool-size = 1
spring.dynamic.thread-pool.executors[0].execute-time-out = 1000
spring.dynamic.thread-pool.executors[0].keep-alive-time = 6691
spring.dynamic.thread-pool.executors[0].maximum-pool-size = 1
spring.dynamic.thread-pool.executors[0].notify.interval = 8
spring.dynamic.thread-pool.executors[0].notify.receives = chen.ma
spring.dynamic.thread-pool.executors[0].queue-capacity = 1
spring.dynamic.thread-pool.executors[0].rejected-handler = AbortPolicy
spring.dynamic.thread-pool.executors[0].thread-name-prefix = message-consume
spring.dynamic.thread-pool.executors[0].thread-pool-id = message-consume
spring.dynamic.thread-pool.executors[1].active-alarm = 80
spring.dynamic.thread-pool.executors[1].alarm = true
spring.dynamic.thread-pool.executors[1].allow-core-thread-time-out = true
spring.dynamic.thread-pool.executors[1].blocking-queue = LinkedBlockingQueue
spring.dynamic.thread-pool.executors[1].capacity-alarm = 80
spring.dynamic.thread-pool.executors[1].core-pool-size = 1
spring.dynamic.thread-pool.executors[1].execute-time-out = 1000
spring.dynamic.thread-pool.executors[1].keep-alive-time = 6691
spring.dynamic.thread-pool.executors[1].maximum-pool-size = 1
spring.dynamic.thread-pool.executors[1].notify.interval = 8
spring.dynamic.thread-pool.executors[1].notify.receives = chen.ma
spring.dynamic.thread-pool.executors[1].queue-capacity = 1
spring.dynamic.thread-pool.executors[1].rejected-handler = AbortPolicy
spring.dynamic.thread-pool.executors[1].thread-name-prefix = message-produce
spring.dynamic.thread-pool.executors[1].thread-pool-id = message-produce

@ -0,0 +1,70 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>cn.hippo4j</groupId>
<artifactId>hippo4j-example</artifactId>
<version>${revision}</version>
</parent>
<artifactId>hippo4j-config-nacos-spring-boot-1x-starter-example</artifactId>
<properties>
<maven.deploy.skip>true</maven.deploy.skip>
<spring-boot.version>1.5.22.RELEASE</spring-boot.version>
<nacos-client.version>1.1.4</nacos-client.version>
</properties>
<dependencies>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
<version>1.5.1.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>cn.hippo4j</groupId>
<artifactId>hippo4j-example-core</artifactId>
<version>${revision}</version>
</dependency>
<dependency>
<groupId>cn.hippo4j</groupId>
<artifactId>hippo4j-config-spring-boot-1x-starter</artifactId>
<version>${revision}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-registry-prometheus</artifactId>
<version>1.1.3</version>
</dependency>
<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-spring-legacy</artifactId>
<version>1.1.3</version>
</dependency>
</dependencies>
</project>

@ -0,0 +1,31 @@
/*
* 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 cn.hippo4j.example.config.nacos;
import cn.hippo4j.core.enable.EnableDynamicThreadPool;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@EnableDynamicThreadPool
@SpringBootApplication(scanBasePackages = "cn.hippo4j.example.core")
public class ConfigNacosSpringBoot15ExampleApplication {
public static void main(String[] args) {
SpringApplication.run(ConfigNacosSpringBoot15ExampleApplication.class, args);
}
}

@ -0,0 +1,31 @@
#debug=true
server.port=8089
server.servlet.context-path=/example
management.security.enabled=false
management.context-path=/actuator
spring.profiles.active=dev
spring.application.name=dynamic-threadpool-example
spring.cloud.nacos.config.server-addr=127.0.0.1:8848
spring.cloud.nacos.config.ext-config[0].data-id=hippo4j-nacos.yaml
spring.cloud.nacos.config.ext-config[0].group=DEFAULT_GROUP
spring.cloud.nacos.config.ext-config[0].refresh=true
spring.dynamic.thread-pool.enable=true
spring.dynamic.thread-pool.banner=true
spring.dynamic.thread-pool.collect=true
spring.dynamic.thread-pool.collect-type=micrometer
spring.dynamic.thread-pool.check-state-interval=5
spring.dynamic.thread-pool.notify-platforms[0].platform=WECHAT
spring.dynamic.thread-pool.notify-platforms[0].secret-key=ac0426a5-c712-474c-9bff-72b8b8f5caff
spring.dynamic.thread-pool.notify-platforms[1].platform=DING
spring.dynamic.thread-pool.notify-platforms[1].secret-key=56417ebba6a27ca352f0de77a2ae9da66d01f39610b5ee8a6033c60ef9071c55
spring.dynamic.thread-pool.notify-platforms[2].platform=LARK
spring.dynamic.thread-pool.notify-platforms[2].secret-key=2cbf2808-3839-4c26-a04d-fd201dd51f9e
spring.dynamic.thread-pool.nacos.data-id=hippo4j-nacos.yaml
spring.dynamic.thread-pool.nacos.group=DEFAULT_GROUP
spring.dynamic.thread-pool.config-file-type=yml

@ -0,0 +1,35 @@
/*
* 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 cn.hippo4j.example.core.handler;
import cn.hippo4j.common.api.ClientNetworkService;
import org.springframework.core.env.ConfigurableEnvironment;
/**
* Customer client network service.
*/
public class CustomerClientNetworkService implements ClientNetworkService {
@Override
public String[] getNetworkIpPort(ConfigurableEnvironment environment) {
String[] network = new String[2];
network[0] = "127.0.0.1";
network[1] = environment.getProperty("server.port", "1994");
return network;
}
}

@ -18,7 +18,6 @@
package cn.hippo4j.example.core.inittest;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.MDC;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
@ -29,8 +28,6 @@ import java.util.concurrent.SynchronousQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import static cn.hippo4j.common.constant.Constants.EXECUTE_TIMEOUT_TRACE;
/**
* Run state handler test.
*/
@ -81,7 +78,7 @@ public class RunStateHandlerTest {
/**
* When the execution of the thread pool task times out, the Trace flag is put into the MDC, and it is printed out when an alarm occurs.
*/
MDC.put(EXECUTE_TIMEOUT_TRACE, "39948722194639841.251.16612352194691531");
// MDC.put(EXECUTE_TIMEOUT_TRACE, "39948722194639841.251.16612352194691531");
try {
Thread.sleep(5000);
} catch (InterruptedException e) {

@ -1,6 +1,7 @@
server.port=8090
spring.profiles.active=dev
spring.application.name=springcloud-rocketmq-stream-example
spring.dynamic.thread-pool.server-addr=http://localhost:6691
spring.dynamic.thread-pool.namespace=prescription
spring.dynamic.thread-pool.item-id=dynamic-threadpool-example

@ -10,6 +10,10 @@
<artifactId>hippo4j-example</artifactId>
<packaging>pom</packaging>
<properties>
<maven.deploy.skip>true</maven.deploy.skip>
</properties>
<modules>
<module>hippo4j-example-core</module>
<module>hippo4j-spring-boot-starter-example</module>
@ -23,9 +27,7 @@
<module>hippo4j-spring-boot-starter-adapter-spring-cloud-stream-rocketmq-example</module>
<module>hippo4j-spring-boot-starter-adapter-rocketmq-example</module>
<module>hippo4j-config-etcd-spring-boot-starter-example</module>
<module>hippo4j-config-nacos-spring-boot-1x-starter-example</module>
<module>hippo4j-config-apollo-spring-boot-1x-starter-example</module>
</modules>
<properties>
<maven.deploy.skip>true</maven.deploy.skip>
</properties>
</project>

@ -30,7 +30,7 @@ public interface NotifyConfigBuilder {
/**
* Build notify.
*
* @return
* @return notify info
*/
Map<String, List<NotifyConfigDTO>> buildNotify();
}

@ -60,8 +60,8 @@ public class DingSendMessageHandler extends AbstractRobotSendMessageHandler {
RobotMessageActualContent robotMessageActualContent = RobotMessageActualContent.builder()
.receiveSeparator(", @")
.changeSeparator(" -> ")
.replaceTxt(DING_ALARM_TIMOUT_REPLACE_TXT)
.traceReplaceTxt(DING_ALARM_TIMOUT_TRACE_REPLACE_TXT)
.replaceTxt(DING_ALARM_TIMEOUT_REPLACE_TXT)
.traceReplaceTxt(DING_ALARM_TIMEOUT_TRACE_REPLACE_TXT)
.alarmMessageContent(Singleton.get(dingAlarmTxtKey, () -> FileUtil.readUtf8String(dingAlarmTxtKey)))
.configMessageContent(Singleton.get(dingConfigTxtKey, () -> FileUtil.readUtf8String(dingConfigTxtKey)))
.build();

@ -17,8 +17,8 @@
package cn.hippo4j.message.platform;
import cn.hippo4j.common.toolkit.HttpClientUtil;
import cn.hippo4j.common.toolkit.Singleton;
import cn.hippo4j.common.toolkit.http.HttpUtil;
import cn.hippo4j.message.dto.NotifyConfigDTO;
import cn.hippo4j.message.enums.NotifyPlatformEnum;
import cn.hippo4j.message.enums.NotifyTypeEnum;
@ -46,8 +46,6 @@ import static cn.hippo4j.message.platform.constant.LarkAlarmConstants.*;
@RequiredArgsConstructor
public class LarkSendMessageHandler implements SendMessageHandler<AlarmNotifyRequest, ChangeParameterNotifyRequest> {
private HttpClientUtil httpClientUtil = HttpClientUtil.build();
@Override
public String getType() {
return NotifyPlatformEnum.LARK.name();
@ -57,67 +55,46 @@ public class LarkSendMessageHandler implements SendMessageHandler<AlarmNotifyReq
@SneakyThrows
public void sendAlarmMessage(NotifyConfigDTO notifyConfig, AlarmNotifyRequest alarmNotifyRequest) {
String afterReceives = getReceives(notifyConfig.getReceives());
String larkAlarmTimoutReplaceTxt;
String larkAlarmTimeoutReplaceTxt;
String larkAlarmTxtKey = "message/robot/dynamic-thread-pool/lark-alarm.json";
String larkAlarmTxt = Singleton.get(larkAlarmTxtKey, () -> FileUtil.readUtf8String(larkAlarmTxtKey));
String larkAlarmTimoutReplaceJsonKey = "message/robot/dynamic-thread-pool/lark-alarm-timeout-replace.json";
String larkAlarmTimoutReplaceJson = Singleton.get(larkAlarmTimoutReplaceJsonKey, () -> FileUtil.readUtf8String(larkAlarmTimoutReplaceJsonKey));
String larkAlarmTimeoutReplaceJsonKey = "message/robot/dynamic-thread-pool/lark-alarm-timeout-replace.json";
String larkAlarmTimeoutReplaceJson = Singleton.get(larkAlarmTimeoutReplaceJsonKey, () -> FileUtil.readUtf8String(larkAlarmTimeoutReplaceJsonKey));
if (Objects.equals(alarmNotifyRequest.getNotifyTypeEnum(), NotifyTypeEnum.TIMEOUT)) {
String executeTimeoutTrace = alarmNotifyRequest.getExecuteTimeoutTrace();
String larkAlarmTimoutTraceReplaceJsonKey = "message/robot/dynamic-thread-pool/lark-alarm-trace-replace.json";
String larkAlarmTimoutTraceReplaceJson = Singleton.get(larkAlarmTimoutTraceReplaceJsonKey, () -> FileUtil.readUtf8String(larkAlarmTimoutTraceReplaceJsonKey));
if (StringUtil.isNotBlank(executeTimeoutTrace)) {
String larkAlarmTimoutTraceReplaceTxt = String.format(larkAlarmTimoutTraceReplaceJson, executeTimeoutTrace);
larkAlarmTimoutReplaceTxt = StringUtil.replace(larkAlarmTimoutReplaceJson, larkAlarmTimoutTraceReplaceJson, larkAlarmTimoutTraceReplaceTxt);
larkAlarmTimeoutReplaceTxt = StringUtil.replace(larkAlarmTimeoutReplaceJson, larkAlarmTimoutTraceReplaceJson, larkAlarmTimoutTraceReplaceTxt);
} else {
larkAlarmTimoutReplaceTxt = StringUtil.replace(larkAlarmTimoutReplaceJson, larkAlarmTimoutTraceReplaceJson, "");
larkAlarmTimeoutReplaceTxt = StringUtil.replace(larkAlarmTimeoutReplaceJson, larkAlarmTimoutTraceReplaceJson, "");
}
larkAlarmTimoutReplaceTxt = String.format(larkAlarmTimoutReplaceTxt, alarmNotifyRequest.getExecuteTime(), alarmNotifyRequest.getExecuteTimeOut());
larkAlarmTxt = StringUtil.replace(larkAlarmTxt, larkAlarmTimoutReplaceJson, larkAlarmTimoutReplaceTxt);
larkAlarmTimeoutReplaceTxt = String.format(larkAlarmTimeoutReplaceTxt, alarmNotifyRequest.getExecuteTime(), alarmNotifyRequest.getExecuteTimeOut());
larkAlarmTxt = StringUtil.replace(larkAlarmTxt, larkAlarmTimeoutReplaceJson, larkAlarmTimeoutReplaceTxt);
} else {
larkAlarmTxt = StringUtil.replace(larkAlarmTxt, larkAlarmTimoutReplaceJson, "");
larkAlarmTxt = StringUtil.replace(larkAlarmTxt, larkAlarmTimeoutReplaceJson, "");
}
String text = String.format(larkAlarmTxt,
// 环境
alarmNotifyRequest.getActive(),
// 报警类型
alarmNotifyRequest.getNotifyTypeEnum(),
// 线程池ID
alarmNotifyRequest.getThreadPoolId(),
// 应用名称
alarmNotifyRequest.getAppName(),
// 实例信息
alarmNotifyRequest.getIdentify(),
// 核心线程数
alarmNotifyRequest.getCorePoolSize(),
// 最大线程数
alarmNotifyRequest.getMaximumPoolSize(),
// 当前线程数
alarmNotifyRequest.getPoolSize(),
// 活跃线程数
alarmNotifyRequest.getActiveCount(),
// 最大任务数
alarmNotifyRequest.getLargestPoolSize(),
// 线程池任务总量
alarmNotifyRequest.getCompletedTaskCount(),
// 队列类型名称
alarmNotifyRequest.getQueueName(),
// 队列容量
alarmNotifyRequest.getCapacity(),
// 队列元素个数
alarmNotifyRequest.getQueueSize(),
// 队列剩余个数
alarmNotifyRequest.getRemainingCapacity(),
// 拒绝策略名称
alarmNotifyRequest.getRejectedExecutionHandlerName(),
// 拒绝策略次数
alarmNotifyRequest.getRejectCountNum(),
// 告警手机号
afterReceives,
// 当前时间
LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")),
// 报警频率
notifyConfig.getInterval());
execute(notifyConfig.getSecretKey(), text);
}
@ -130,34 +107,20 @@ public class LarkSendMessageHandler implements SendMessageHandler<AlarmNotifyReq
String larkNoticeJsonKey = "message/robot/dynamic-thread-pool/lark-config.json";
String larkNoticeJson = Singleton.get(larkNoticeJsonKey, () -> FileUtil.readUtf8String(larkNoticeJsonKey));
String text = String.format(larkNoticeJson,
// 环境
changeParameterNotifyRequest.getActive(),
// 线程池名称
threadPoolId,
// 应用名称
changeParameterNotifyRequest.getAppName(),
// 实例信息
changeParameterNotifyRequest.getIdentify(),
// 核心线程数
changeParameterNotifyRequest.getBeforeCorePoolSize() + " ➲ " + changeParameterNotifyRequest.getNowCorePoolSize(),
// 最大线程数
changeParameterNotifyRequest.getBeforeMaximumPoolSize() + " ➲ " + changeParameterNotifyRequest.getNowMaximumPoolSize(),
// 核心线程超时
changeParameterNotifyRequest.getBeforeAllowsCoreThreadTimeOut() + " ➲ " + changeParameterNotifyRequest.getNowAllowsCoreThreadTimeOut(),
// 线程存活时间
changeParameterNotifyRequest.getBeforeKeepAliveTime() + " ➲ " + changeParameterNotifyRequest.getNowKeepAliveTime(),
// 阻塞队列
changeParameterNotifyRequest.getBlockingQueueName(),
// 阻塞队列容量
changeParameterNotifyRequest.getBeforeQueueCapacity() + " ➲ " + changeParameterNotifyRequest.getNowQueueCapacity(),
// 执行超时时间
changeParameterNotifyRequest.getBeforeExecuteTimeOut() + " ➲ " + changeParameterNotifyRequest.getNowExecuteTimeOut(),
// 拒绝策略
changeParameterNotifyRequest.getBeforeRejectedName(),
changeParameterNotifyRequest.getNowRejectedName(),
// 告警手机号
afterReceives,
// 当前时间
LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
execute(notifyConfig.getSecretKey(), text);
}
@ -174,7 +137,7 @@ public class LarkSendMessageHandler implements SendMessageHandler<AlarmNotifyReq
private void execute(String secretKey, String text) {
String serverUrl = LARK_BOT_URL + secretKey;
try {
httpClientUtil.restApiPost(serverUrl, text, Object.class);
HttpUtil.postJson(serverUrl, text);
} catch (Exception ex) {
log.error("Lark failed to send message", ex);
}

@ -18,8 +18,8 @@
package cn.hippo4j.message.platform;
import cn.hippo4j.common.toolkit.FileUtil;
import cn.hippo4j.common.toolkit.HttpClientUtil;
import cn.hippo4j.common.toolkit.Singleton;
import cn.hippo4j.common.toolkit.http.HttpUtil;
import cn.hippo4j.message.enums.NotifyPlatformEnum;
import cn.hippo4j.message.platform.base.AbstractRobotSendMessageHandler;
import cn.hippo4j.message.platform.base.RobotMessageActualContent;
@ -36,8 +36,6 @@ import static cn.hippo4j.message.platform.constant.WeChatAlarmConstants.*;
@Slf4j
public class WeChatSendMessageHandler extends AbstractRobotSendMessageHandler {
private final HttpClientUtil httpClientUtil = HttpClientUtil.build();
@Override
public String getType() {
return NotifyPlatformEnum.WECHAT.name();
@ -66,7 +64,7 @@ public class WeChatSendMessageHandler extends AbstractRobotSendMessageHandler {
Markdown markdown = new Markdown();
markdown.setContent(robotMessageExecuteDTO.getText());
weChatReq.setMarkdown(markdown);
httpClientUtil.restApiPost(serverUrl, weChatReq, Object.class);
HttpUtil.post(serverUrl, weChatReq);
} catch (Exception ex) {
log.error("WeChat failed to send message", ex);
}

@ -37,22 +37,22 @@ public abstract class AbstractRobotSendMessageHandler implements SendMessageHand
/**
* Build message actual content.
*
* @return
* @return robot message actual content
*/
protected abstract RobotMessageActualContent buildMessageActualContent();
/**
* Execute.
*
* @param robotMessageExecuteDTO
* @param robotMessageExecuteDTO robot message execute dto
*/
protected abstract void execute(RobotMessageExecuteDTO robotMessageExecuteDTO);
/**
* Send alarm message.
*
* @param notifyConfig
* @param alarmNotifyRequest
* @param notifyConfig notify config
* @param alarmNotifyRequest alarm notify request
*/
public void sendAlarmMessage(NotifyConfigDTO notifyConfig, AlarmNotifyRequest alarmNotifyRequest) {
RobotMessageActualContent robotMessageActualContent = buildMessageActualContent();
@ -75,45 +75,25 @@ public abstract class AbstractRobotSendMessageHandler implements SendMessageHand
alarmContentTxt = StringUtil.replace(alarmContentTxt, "${timout-content}", replaceTxt);
String text = String.format(
alarmContentTxt,
// 环境
alarmNotifyRequest.getActive(),
// 报警类型
alarmNotifyRequest.getNotifyTypeEnum(),
// 线程池ID
alarmNotifyRequest.getThreadPoolId(),
// 应用名称
alarmNotifyRequest.getAppName(),
// 实例信息
alarmNotifyRequest.getIdentify(),
// 核心线程数
alarmNotifyRequest.getCorePoolSize(),
// 最大线程数
alarmNotifyRequest.getMaximumPoolSize(),
// 当前线程数
alarmNotifyRequest.getPoolSize(),
// 活跃线程数
alarmNotifyRequest.getActiveCount(),
// 最大任务数
alarmNotifyRequest.getLargestPoolSize(),
// 线程池任务总量
alarmNotifyRequest.getCompletedTaskCount(),
// 队列类型名称
alarmNotifyRequest.getQueueName(),
// 队列容量
alarmNotifyRequest.getCapacity(),
// 队列元素个数
alarmNotifyRequest.getQueueSize(),
// 队列剩余个数
alarmNotifyRequest.getRemainingCapacity(),
// 拒绝策略名称
alarmNotifyRequest.getRejectedExecutionHandlerName(),
// 拒绝策略次数
alarmNotifyRequest.getRejectCountNum(),
// 告警手机号
Joiner.on(robotMessageActualContent.getReceiveSeparator()).join(notifyConfig.getReceives().split(",")),
// 报警频率
notifyConfig.getInterval(),
// 当前时间
LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
execute(RobotMessageExecuteDTO.builder().text(text).notifyConfig(notifyConfig).build());
}
@ -121,8 +101,8 @@ public abstract class AbstractRobotSendMessageHandler implements SendMessageHand
/**
* Send change message.
*
* @param notifyConfig
* @param changeParameterNotifyRequest
* @param notifyConfig notify config
* @param changeParameterNotifyRequest change parameter notify request
*/
public void sendChangeMessage(NotifyConfigDTO notifyConfig, ChangeParameterNotifyRequest changeParameterNotifyRequest) {
RobotMessageActualContent robotMessageActualContent = buildMessageActualContent();
@ -130,34 +110,20 @@ public abstract class AbstractRobotSendMessageHandler implements SendMessageHand
String changeSeparator = robotMessageActualContent.getChangeSeparator();
String text = String.format(
robotMessageActualContent.getConfigMessageContent(),
// 环境
changeParameterNotifyRequest.getActive(),
// 线程池名称
threadPoolId,
// 应用名称
changeParameterNotifyRequest.getAppName(),
// 实例信息
changeParameterNotifyRequest.getIdentify(),
// 核心线程数
changeParameterNotifyRequest.getBeforeCorePoolSize() + changeSeparator + changeParameterNotifyRequest.getNowCorePoolSize(),
// 最大线程数
changeParameterNotifyRequest.getBeforeMaximumPoolSize() + changeSeparator + changeParameterNotifyRequest.getNowMaximumPoolSize(),
// 核心线程超时
changeParameterNotifyRequest.getBeforeAllowsCoreThreadTimeOut() + changeSeparator + changeParameterNotifyRequest.getNowAllowsCoreThreadTimeOut(),
// 线程存活时间
changeParameterNotifyRequest.getBeforeKeepAliveTime() + changeSeparator + changeParameterNotifyRequest.getNowKeepAliveTime(),
// 执行超时时间
changeParameterNotifyRequest.getBeforeExecuteTimeOut() + changeSeparator + changeParameterNotifyRequest.getNowExecuteTimeOut(),
// 阻塞队列
changeParameterNotifyRequest.getBlockingQueueName(),
// 阻塞队列容量
changeParameterNotifyRequest.getBeforeQueueCapacity() + changeSeparator + changeParameterNotifyRequest.getNowQueueCapacity(),
// 拒绝策略
changeParameterNotifyRequest.getBeforeRejectedName(),
changeParameterNotifyRequest.getNowRejectedName(),
// 告警手机号
Joiner.on(robotMessageActualContent.getReceiveSeparator()).join(notifyConfig.getReceives().split(",")),
// 当前时间
LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
execute(RobotMessageExecuteDTO.builder().text(text).notifyConfig(notifyConfig).build());
}

@ -40,14 +40,14 @@ public class DingAlarmConstants {
/**
* Trace info
*/
public static final String DING_ALARM_TIMOUT_TRACE_REPLACE_TXT = "<font color=#708090 size=2>链路信息:%s</font> \n\n ";
public static final String DING_ALARM_TIMEOUT_TRACE_REPLACE_TXT = "<font color=#708090 size=2>链路信息:%s</font> \n\n ";
/**
* Replace task timeout template
*/
public static final String DING_ALARM_TIMOUT_REPLACE_TXT =
public static final String DING_ALARM_TIMEOUT_REPLACE_TXT =
"<font color=#708090 size=2>任务执行时间:%d / ms </font> \n\n " +
"<font color=#708090 size=2>超时时间:%d / ms</font> \n\n " +
DING_ALARM_TIMOUT_TRACE_REPLACE_TXT +
DING_ALARM_TIMEOUT_TRACE_REPLACE_TXT +
" --- \n\n ";
}

@ -17,12 +17,6 @@
package cn.hippo4j.message.service;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantLock;
import cn.hippo4j.common.constant.Constants;
import cn.hippo4j.common.toolkit.IdUtil;
import cn.hippo4j.common.toolkit.StringUtil;
@ -30,6 +24,12 @@ import cn.hippo4j.message.dto.AlarmControlDTO;
import com.github.benmanes.caffeine.cache.Cache;
import com.github.benmanes.caffeine.cache.Caffeine;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantLock;
/**
* Alarm control assembly.
*/
@ -42,8 +42,8 @@ public class AlarmControlHandler {
/**
* Control message push alarm frequency.
*
* @param alarmControl
* @return
* @param alarmControl alarm control
* @return is it possible to send
*/
public boolean isSendAlarm(AlarmControlDTO alarmControl) {
String threadPoolKey = alarmControl.buildPk();
@ -72,9 +72,9 @@ public class AlarmControlHandler {
/**
* Init cache and lock.
*
* @param threadPoolId
* @param platform
* @param interval
* @param threadPoolId thread-pool id
* @param platform platform
* @param interval interval
*/
public void initCacheAndLock(String threadPoolId, String platform, Integer interval) {
String threadPoolKey = threadPoolId + Constants.GROUP_KEY_DELIMITER + platform;

@ -109,9 +109,9 @@ public class Hippo4jBaseSendMessageService implements Hippo4jSendMessageService,
/**
* Is send alarm.
*
* @param threadPoolId
* @param platform
* @param typeEnum
* @param threadPoolId thread-pool id
* @param platform platform
* @param typeEnum type enum
* @return
*/
private boolean isSendAlarm(String threadPoolId, String platform, NotifyTypeEnum typeEnum) {
@ -123,6 +123,15 @@ public class Hippo4jBaseSendMessageService implements Hippo4jSendMessageService,
return alarmControlHandler.isSendAlarm(alarmControl);
}
/**
* Put platform.
*
* @param notifyConfigs notify configs
*/
public synchronized void putPlatform(Map<String, List<NotifyConfigDTO>> notifyConfigs) {
this.notifyConfigs.putAll(notifyConfigs);
}
@Override
public void run(String... args) throws Exception {
Map<String, SendMessageHandler> sendMessageHandlerMap =
@ -131,13 +140,4 @@ public class Hippo4jBaseSendMessageService implements Hippo4jSendMessageService,
Map<String, List<NotifyConfigDTO>> buildNotify = notifyConfigBuilder.buildNotify();
notifyConfigs.putAll(buildNotify);
}
/**
* Put platform.
*
* @param notifyConfigs
*/
public synchronized void putPlatform(Map<String, List<NotifyConfigDTO>> notifyConfigs) {
this.notifyConfigs.putAll(notifyConfigs);
}
}

@ -29,15 +29,15 @@ public interface Hippo4jSendMessageService {
/**
* Send dynamic thread pool alert notifications.
*
* @param typeEnum
* @param alarmNotifyRequest
* @param typeEnum type enum
* @param alarmNotifyRequest alarm notify request
*/
void sendAlarmMessage(NotifyTypeEnum typeEnum, AlarmNotifyRequest alarmNotifyRequest);
/**
* Send dynamic thread pool parameter change notification.
*
* @param changeParameterNotifyRequest
* @param changeParameterNotifyRequest change parameter notify request
*/
void sendChangeMessage(ChangeParameterNotifyRequest changeParameterNotifyRequest);
}

@ -26,25 +26,25 @@ import cn.hippo4j.message.request.base.NotifyRequest;
public interface SendMessageHandler<T extends NotifyRequest, R extends NotifyRequest> {
/**
* Get type.
* Get the message send type.
*
* @return
* @return message type
*/
String getType();
/**
* Send alarm message.
*
* @param notifyConfig
* @param alarmNotifyRequest
* @param notifyConfig notify config
* @param alarmNotifyRequest alarm notify request
*/
void sendAlarmMessage(NotifyConfigDTO notifyConfig, T alarmNotifyRequest);
/**
* Send change message.
*
* @param notifyConfig
* @param changeParameterNotifyRequest
* @param notifyConfig notify config
* @param changeParameterNotifyRequest change parameter notify request
*/
void sendChangeMessage(NotifyConfigDTO notifyConfig, R changeParameterNotifyRequest);
}

@ -14,8 +14,8 @@
"content": "** 超时时间:** %s",
"tag": "lark_md"
}
},
{
}
,{
"is_short": true,
"text": {
"content": "** 链路信息:** %s",

@ -1,5 +1,5 @@
{
,{
"is_short": true,
"text": {
"content": "** 链路信息:** %s",

@ -142,8 +142,8 @@
"content": "** 超时时间:** %s",
"tag": "lark_md"
}
},
{
}
,{
"is_short": true,
"text": {
"content": "** 链路信息:** %s",

@ -22,7 +22,7 @@ import cn.hippo4j.message.enums.NotifyTypeEnum;
import org.junit.Assert;
import org.junit.Test;
public class AlarmControlHandlerTest {
public final class AlarmControlHandlerTest {
@Test
public void assertIsNotSendAlarm() {

@ -13,6 +13,17 @@
<dependency>
<groupId>cn.hippo4j</groupId>
<artifactId>hippo4j-core</artifactId>
<version>${revision}</version>
</dependency>
<dependency>
<groupId>cn.hippo4j</groupId>
<artifactId>hippo4j-adapter-web</artifactId>
<version>${revision}</version>
</dependency>
<dependency>
<groupId>cn.hippo4j</groupId>
<artifactId>hippo4j-adapter-base</artifactId>
<version>${revision}</version>
</dependency>
</dependencies>
</project>

@ -0,0 +1,43 @@
/*
* 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 cn.hippo4j.monitor.base;
import cn.hippo4j.adapter.base.ThreadPoolAdapter;
import cn.hippo4j.adapter.base.ThreadPoolAdapterState;
import cn.hippo4j.common.config.ApplicationContextHolder;
import java.util.Map;
/**
* Abstract adapter thread-pool monitor.
*/
public abstract class AbstractAdapterThreadPoolMonitor implements AdapterThreadPoolMonitor {
/**
* Execute collection thread pool running data.
*
* @param threadPoolAdapterState thread-pool adapter state
*/
protected abstract void execute(ThreadPoolAdapterState threadPoolAdapterState);
@Override
public void collect() {
Map<String, ThreadPoolAdapter> threadPoolAdapterMap = ApplicationContextHolder.getBeansOfType(ThreadPoolAdapter.class);
threadPoolAdapterMap.forEach((beanName, bean) -> bean.getThreadPoolStates().forEach(each -> execute(each)));
}
}

@ -20,24 +20,24 @@ package cn.hippo4j.monitor.base;
import cn.hippo4j.common.model.ThreadPoolRunStateInfo;
import cn.hippo4j.core.executor.manage.GlobalThreadPoolManage;
import cn.hippo4j.core.executor.state.ThreadPoolRunStateHandler;
import lombok.RequiredArgsConstructor;
import javax.annotation.Resource;
import java.util.List;
/**
* Abstract dynamic thread-pool monitor.
*/
@RequiredArgsConstructor
public abstract class AbstractDynamicThreadPoolMonitor implements DynamicThreadPoolMonitor {
private final ThreadPoolRunStateHandler threadPoolRunStateHandler;
@Resource
private ThreadPoolRunStateHandler threadPoolRunStateHandler;
/**
* Execute collection thread pool running data.
*
* @param poolRunStateInfo
* @param dynamicThreadPoolRunStateInfo dynamic thread-pool run state info
*/
protected abstract void execute(ThreadPoolRunStateInfo poolRunStateInfo);
protected abstract void execute(ThreadPoolRunStateInfo dynamicThreadPoolRunStateInfo);
@Override
public void collect() {

@ -0,0 +1,45 @@
/*
* 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 cn.hippo4j.monitor.base;
import cn.hippo4j.adapter.web.WebThreadPoolService;
import cn.hippo4j.common.model.ThreadPoolRunStateInfo;
import javax.annotation.Resource;
/**
* Abstract web thread-pool monitor.
*/
public abstract class AbstractWebThreadPoolMonitor implements WebThreadPoolMonitor {
@Resource
private WebThreadPoolService webThreadPoolService;
/**
* Execute collection thread pool running data.
*
* @param webThreadPoolRunStateInfo web thread-pool run state info
*/
protected abstract void execute(ThreadPoolRunStateInfo webThreadPoolRunStateInfo);
@Override
public void collect() {
ThreadPoolRunStateInfo webThreadPoolRunStateInfo = webThreadPoolService.getWebRunStateInfo();
execute(webThreadPoolRunStateInfo);
}
}

@ -0,0 +1,25 @@
/*
* 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 cn.hippo4j.monitor.base;
/**
* Adapter thread-pool monitor.
*/
public interface AdapterThreadPoolMonitor extends ThreadPoolMonitor {
}

@ -0,0 +1,39 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.hippo4j.monitor.base;
/**
* Monitor thread-pool type enum.
*/
public enum MonitorThreadPoolTypeEnum {
/**
* Dynamic thread-pool
*/
DYNAMIC,
/**
* Web thread-pool
*/
WEB,
/**
* Adapter thread-pool
*/
ADAPTER
}

@ -18,19 +18,19 @@
package cn.hippo4j.monitor.base;
/**
* Thread-pool monitor.
* Thread-pool runtime monitor.
*/
public interface ThreadPoolMonitor {
/**
* Get type.
* Get thread-pool monitoring type.
*
* @return
* @return monitoring type
*/
String getType();
/**
* Collect data.
* Collect thread-pool runtime data.
*/
void collect();
}

@ -15,7 +15,11 @@
* limitations under the License.
*/
package cn.hippo4j.auth.secuity;
package cn.hippo4j.monitor.base;
/**
* Web thread-pool monitor.
*/
public interface WebThreadPoolMonitor extends ThreadPoolMonitor {
public final class JwtTokenManagerTest {
}

@ -0,0 +1,40 @@
/*
* 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 cn.hippo4j.monitor.elasticsearch;
import cn.hippo4j.common.model.ThreadPoolRunStateInfo;
import cn.hippo4j.monitor.base.AbstractDynamicThreadPoolMonitor;
import cn.hippo4j.monitor.base.MonitorTypeEnum;
import lombok.extern.slf4j.Slf4j;
/**
* Adapter thread-pool elastic-search monitor handler.
*/
@Slf4j
public class AdapterThreadPoolElasticSearchMonitorHandler extends AbstractDynamicThreadPoolMonitor {
@Override
protected void execute(ThreadPoolRunStateInfo poolRunStateInfo) {
// TODO
}
@Override
public String getType() {
return MonitorTypeEnum.ELASTICSEARCH.name().toLowerCase();
}
}

@ -15,26 +15,25 @@
* limitations under the License.
*/
package cn.hippo4j.monitor.es;
package cn.hippo4j.monitor.elasticsearch;
import cn.hippo4j.common.config.ApplicationContextHolder;
import cn.hippo4j.common.model.ThreadPoolRunStateInfo;
import cn.hippo4j.common.toolkit.BeanUtil;
import cn.hippo4j.common.toolkit.FileUtil;
import cn.hippo4j.common.toolkit.JSONUtil;
import cn.hippo4j.core.executor.state.ThreadPoolRunStateHandler;
import cn.hippo4j.monitor.es.model.EsThreadPoolRunStateInfo;
import cn.hippo4j.monitor.base.AbstractDynamicThreadPoolMonitor;
import cn.hippo4j.monitor.base.MonitorTypeEnum;
import cn.hippo4j.monitor.elasticsearch.model.ElasticSearchThreadPoolRunStateInfo;
import lombok.extern.slf4j.Slf4j;
import org.elasticsearch.action.admin.indices.alias.Alias;
import org.elasticsearch.action.admin.indices.create.CreateIndexRequest;
import org.elasticsearch.action.admin.indices.create.CreateIndexResponse;
import org.elasticsearch.client.indices.GetIndexRequest;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.index.IndexResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.client.indices.GetIndexRequest;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.xcontent.XContentType;
import org.springframework.core.env.Environment;
@ -47,20 +46,16 @@ import java.util.Objects;
import java.util.concurrent.atomic.AtomicBoolean;
/**
* Elastic-search monitor handler.
* Dynamic thread-pool elastic-search monitor handler.
*/
@Slf4j
public class EsMonitorHandler extends AbstractDynamicThreadPoolMonitor {
public EsMonitorHandler(ThreadPoolRunStateHandler threadPoolRunStateHandler) {
super(threadPoolRunStateHandler);
}
public class DynamicThreadPoolElasticSearchMonitorHandler extends AbstractDynamicThreadPoolMonitor {
private AtomicBoolean isIndexExist = null;
@Override
protected void execute(ThreadPoolRunStateInfo poolRunStateInfo) {
EsThreadPoolRunStateInfo esThreadPoolRunStateInfo = BeanUtil.convert(poolRunStateInfo, EsThreadPoolRunStateInfo.class);
ElasticSearchThreadPoolRunStateInfo esThreadPoolRunStateInfo = BeanUtil.convert(poolRunStateInfo, ElasticSearchThreadPoolRunStateInfo.class);
Environment environment = ApplicationContextHolder.getInstance().getEnvironment();
String indexName = environment.getProperty("es.thread-pool-state.index.name", "thread-pool-state");
String applicationName = environment.getProperty("spring.application.name", "application");
@ -75,8 +70,8 @@ public class EsMonitorHandler extends AbstractDynamicThreadPoolMonitor {
this.log2Es(esThreadPoolRunStateInfo, indexName);
}
public void log2Es(EsThreadPoolRunStateInfo esThreadPoolRunStateInfo, String indexName) {
RestHighLevelClient client = EsClientHolder.getClient();
public void log2Es(ElasticSearchThreadPoolRunStateInfo esThreadPoolRunStateInfo, String indexName) {
RestHighLevelClient client = ElasticSearchClientHolder.getClient();
try {
IndexRequest request = new IndexRequest(indexName, "_doc");
request.id(esThreadPoolRunStateInfo.getId());
@ -99,7 +94,7 @@ public class EsMonitorHandler extends AbstractDynamicThreadPoolMonitor {
boolean exists = false;
GetIndexRequest request = new GetIndexRequest(index);
try {
RestHighLevelClient client = EsClientHolder.getClient();
RestHighLevelClient client = ElasticSearchClientHolder.getClient();
exists = client.indices().exists(request, RequestOptions.DEFAULT);
} catch (IOException e) {
log.error("check es index fail");
@ -110,7 +105,7 @@ public class EsMonitorHandler extends AbstractDynamicThreadPoolMonitor {
}
public void createIndex(String index, String type, String mapping, Integer shards, Integer replicas, String alias) {
RestHighLevelClient client = EsClientHolder.getClient();
RestHighLevelClient client = ElasticSearchClientHolder.getClient();
boolean acknowledged = false;
CreateIndexRequest request = new CreateIndexRequest(index);
if (StringUtils.hasText(mapping)) {

@ -15,7 +15,7 @@
* limitations under the License.
*/
package cn.hippo4j.monitor.es;
package cn.hippo4j.monitor.elasticsearch;
import cn.hippo4j.common.config.ApplicationContextHolder;
import cn.hippo4j.common.toolkit.StringUtil;
@ -37,7 +37,7 @@ import java.util.List;
* Elastic-search client holder.
*/
@Slf4j
public class EsClientHolder {
public class ElasticSearchClientHolder {
private static String host;

@ -0,0 +1,40 @@
/*
* 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 cn.hippo4j.monitor.elasticsearch;
import cn.hippo4j.common.model.ThreadPoolRunStateInfo;
import cn.hippo4j.monitor.base.AbstractDynamicThreadPoolMonitor;
import cn.hippo4j.monitor.base.MonitorTypeEnum;
import lombok.extern.slf4j.Slf4j;
/**
* Web thread-pool elastic-search monitor handler.
*/
@Slf4j
public class WebThreadPoolElasticSearchMonitorHandler extends AbstractDynamicThreadPoolMonitor {
@Override
protected void execute(ThreadPoolRunStateInfo poolRunStateInfo) {
// TODO
}
@Override
public String getType() {
return MonitorTypeEnum.ELASTICSEARCH.name().toLowerCase();
}
}

@ -15,7 +15,7 @@
* limitations under the License.
*/
package cn.hippo4j.monitor.es.model;
package cn.hippo4j.monitor.elasticsearch.model;
import cn.hippo4j.common.model.ThreadPoolRunStateInfo;
import lombok.Getter;
@ -26,7 +26,7 @@ import lombok.Setter;
*/
@Getter
@Setter
public class EsThreadPoolRunStateInfo extends ThreadPoolRunStateInfo {
public class ElasticSearchThreadPoolRunStateInfo extends ThreadPoolRunStateInfo {
private String Id;

@ -0,0 +1,41 @@
/*
* 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 cn.hippo4j.monitor.local.log;
import cn.hippo4j.adapter.base.ThreadPoolAdapterState;
import cn.hippo4j.common.toolkit.JSONUtil;
import cn.hippo4j.monitor.base.AbstractAdapterThreadPoolMonitor;
import cn.hippo4j.monitor.base.MonitorTypeEnum;
import lombok.extern.slf4j.Slf4j;
/**
* Adapter thread-pool local log monitor handler.
*/
@Slf4j
public class AdapterThreadPoolLocalLogMonitorHandler extends AbstractAdapterThreadPoolMonitor {
@Override
protected void execute(ThreadPoolAdapterState threadPoolAdapterState) {
log.info("{}", JSONUtil.toJSONString(threadPoolAdapterState));
}
@Override
public String getType() {
return MonitorTypeEnum.LOG.name().toLowerCase();
}
}

@ -19,20 +19,15 @@ package cn.hippo4j.monitor.local.log;
import cn.hippo4j.common.model.ThreadPoolRunStateInfo;
import cn.hippo4j.common.toolkit.JSONUtil;
import cn.hippo4j.core.executor.state.ThreadPoolRunStateHandler;
import cn.hippo4j.monitor.base.AbstractDynamicThreadPoolMonitor;
import cn.hippo4j.monitor.base.MonitorTypeEnum;
import lombok.extern.slf4j.Slf4j;
/**
* Local log monitor handler.
* Dynamic thread-pool local log monitor handler.
*/
@Slf4j
public class LocalLogMonitorHandler extends AbstractDynamicThreadPoolMonitor {
public LocalLogMonitorHandler(ThreadPoolRunStateHandler threadPoolRunStateHandler) {
super(threadPoolRunStateHandler);
}
public class DynamicThreadPoolLocalLogMonitorHandler extends AbstractDynamicThreadPoolMonitor {
@Override
protected void execute(ThreadPoolRunStateInfo poolRunStateInfo) {

@ -0,0 +1,41 @@
/*
* 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 cn.hippo4j.monitor.local.log;
import cn.hippo4j.common.model.ThreadPoolRunStateInfo;
import cn.hippo4j.common.toolkit.JSONUtil;
import cn.hippo4j.monitor.base.AbstractWebThreadPoolMonitor;
import cn.hippo4j.monitor.base.MonitorTypeEnum;
import lombok.extern.slf4j.Slf4j;
/**
* Web thread-pool local log monitor handler.
*/
@Slf4j
public class WebThreadPoolLocalLogMonitorHandler extends AbstractWebThreadPoolMonitor {
@Override
protected void execute(ThreadPoolRunStateInfo poolRunStateInfo) {
log.info("{}", JSONUtil.toJSONString(poolRunStateInfo));
}
@Override
public String getType() {
return MonitorTypeEnum.LOG.name().toLowerCase();
}
}

@ -15,21 +15,24 @@
* limitations under the License.
*/
package cn.hippo4j.springboot.starter.monitor.local.log;
package cn.hippo4j.monitor.micrometer;
import cn.hippo4j.core.executor.state.ThreadPoolRunStateHandler;
import cn.hippo4j.monitor.local.log.LocalLogMonitorHandler;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import cn.hippo4j.adapter.base.ThreadPoolAdapterState;
import cn.hippo4j.monitor.base.AbstractAdapterThreadPoolMonitor;
import cn.hippo4j.monitor.base.MonitorTypeEnum;
/**
* Local log monitor configuration.
* Adapter thread-pool micrometer monitor handler.
*/
@Configuration
public class LocalLogMonitorConfiguration {
public class AdapterThreadPoolMicrometerMonitorHandler extends AbstractAdapterThreadPoolMonitor {
@Bean
public LocalLogMonitorHandler localLogMonitorHandler(ThreadPoolRunStateHandler threadPoolRunStateHandler) {
return new LocalLogMonitorHandler(threadPoolRunStateHandler);
@Override
protected void execute(ThreadPoolAdapterState threadPoolAdapterState) {
}
@Override
public String getType() {
return MonitorTypeEnum.MICROMETER.name().toLowerCase();
}
}

@ -21,7 +21,6 @@ import cn.hippo4j.common.config.ApplicationContextHolder;
import cn.hippo4j.common.model.ThreadPoolRunStateInfo;
import cn.hippo4j.common.toolkit.BeanUtil;
import cn.hippo4j.common.toolkit.CollectionUtil;
import cn.hippo4j.core.executor.state.ThreadPoolRunStateHandler;
import cn.hippo4j.monitor.base.AbstractDynamicThreadPoolMonitor;
import cn.hippo4j.monitor.base.MonitorTypeEnum;
import io.micrometer.core.instrument.Metrics;
@ -32,9 +31,9 @@ import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/**
* Micrometer monitor handler.
* Dynamic thread-pool micrometer monitor handler.
*/
public class MicrometerMonitorHandler extends AbstractDynamicThreadPoolMonitor {
public class DynamicThreadPoolMicrometerMonitorHandler extends AbstractDynamicThreadPoolMonitor {
private final static String METRIC_NAME_PREFIX = "dynamic.thread-pool";
@ -44,10 +43,6 @@ public class MicrometerMonitorHandler extends AbstractDynamicThreadPoolMonitor {
private final Map<String, ThreadPoolRunStateInfo> RUN_STATE_CACHE = new ConcurrentHashMap<>();
public MicrometerMonitorHandler(ThreadPoolRunStateHandler threadPoolRunStateHandler) {
super(threadPoolRunStateHandler);
}
@Override
protected void execute(ThreadPoolRunStateInfo poolRunStateInfo) {
ThreadPoolRunStateInfo stateInfo = RUN_STATE_CACHE.get(poolRunStateInfo.getTpId());

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

Loading…
Cancel
Save