Merge remote-tracking branch 'upstream/develop' into develop

# Conflicts:
#	README.md
pull/872/head
weihu 3 years ago
commit 9c59d84b43

@ -64,4 +64,4 @@ jobs:
steps:
- uses: actions/checkout@v3
- name: Build with Maven
run: echo y | mvn clean install -Dskip.gpg=true -Dspotless.apply.skip=true
run: echo y | mvn clean install -Dskip.gpg=true -Dspotless.apply.skip=true -Dmaven.javadoc.skip=true

@ -21,7 +21,7 @@
on:
push:
branches:
- develop
- main
jobs:
contrib-readme-job:
@ -33,8 +33,8 @@ jobs:
with:
image_size: 50
columns_per_row: 9
committer_email: m7798432@163.com
committer_username: pirme
committer_email: wechat202110@163.com
committer_username: hippo4jbot[bot]
commit_message: 'Update the list of contributors'
env:
GITHUB_TOKEN: ${{ secrets.ACTION_TOKEN }}

@ -44,6 +44,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)
@ -93,6 +97,20 @@ Hippo-4J 通过对 JDK 线程池增强,以及扩展三方框架底层线程池
<sub><b>李金来</b></sub>
</a>
</td>
<td align="center">
<a href="https://github.com/shanjianq">
<img src="https://avatars.githubusercontent.com/u/49084314?v=4" width="50;" alt="shanjianq"/>
<br />
<sub><b>Shanjianq</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/iwangjie">
<img src="https://avatars.githubusercontent.com/u/23075587?v=4" width="50;" alt="iwangjie"/>
@ -108,12 +126,13 @@ Hippo-4J 通过对 JDK 线程池增强,以及扩展三方框架底层线程池
</a>
</td>
<td align="center">
<a href="https://github.com/shanjianq">
<img src="https://avatars.githubusercontent.com/u/49084314?v=4" width="50;" alt="shanjianq"/>
<a href="https://github.com/pizihao">
<img src="https://avatars.githubusercontent.com/u/48643103?v=4" width="50;" alt="pizihao"/>
<br />
<sub><b>Shanjianq</b></sub>
<sub><b>Pizihao</b></sub>
</a>
</td>
</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"/>
@ -127,13 +146,12 @@ Hippo-4J 通过对 JDK 线程池增强,以及扩展三方框架底层线程池
<br />
<sub><b>Null</b></sub>
</a>
</td></tr>
<tr>
</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/road2master">
<img src="https://avatars.githubusercontent.com/u/53806703?v=4" width="50;" alt="road2master"/>
<br />
<sub><b>Pizihao</b></sub>
<sub><b>Lijx</b></sub>
</a>
</td>
<td align="center">
@ -144,17 +162,17 @@ Hippo-4J 通过对 JDK 线程池增强,以及扩展三方框架底层线程池
</a>
</td>
<td align="center">
<a href="https://github.com/zhuanghaozhe">
<img src="https://avatars.githubusercontent.com/u/73152769?v=4" width="50;" alt="zhuanghaozhe"/>
<a href="https://github.com/baymax55">
<img src="https://avatars.githubusercontent.com/u/35788491?v=4" width="50;" alt="baymax55"/>
<br />
<sub><b>庄昊哲</b></sub>
<sub><b>Baymax55</b></sub>
</a>
</td>
<td align="center">
<a href="https://github.com/road2master">
<img src="https://avatars.githubusercontent.com/u/53806703?v=4" width="50;" alt="road2master"/>
<a href="https://github.com/zhuanghaozhe">
<img src="https://avatars.githubusercontent.com/u/73152769?v=4" width="50;" alt="zhuanghaozhe"/>
<br />
<sub><b>Lijx</b></sub>
<sub><b>庄昊哲</b></sub>
</a>
</td>
<td align="center">
@ -177,7 +195,8 @@ Hippo-4J 通过对 JDK 线程池增强,以及扩展三方框架底层线程池
<br />
<sub><b>Hippo4j</b></sub>
</a>
</td>
</td></tr>
<tr>
<td align="center">
<a href="https://github.com/imyzt">
<img src="https://avatars.githubusercontent.com/u/28680198?v=4" width="50;" alt="imyzt"/>
@ -191,8 +210,7 @@ Hippo-4J 通过对 JDK 线程池增强,以及扩展三方框架底层线程池
<br />
<sub><b>Liutao</b></sub>
</a>
</td></tr>
<tr>
</td>
<td align="center">
<a href="https://github.com/monsterxxp">
<img src="https://avatars.githubusercontent.com/u/37952446?v=4" width="50;" alt="monsterxxp"/>
@ -207,6 +225,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"/>
@ -234,7 +259,8 @@ 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"/>
@ -242,21 +268,13 @@ Hippo-4J 通过对 JDK 线程池增强,以及扩展三方框架底层线程池
<sub><b>Serenity</b></sub>
</a>
</td>
<td align="center">
<a href="https://github.com/baymax55">
<img src="https://avatars.githubusercontent.com/u/35788491?v=4" width="50;" alt="baymax55"/>
<br />
<sub><b>Baymax55</b></sub>
</a>
</td>
<td align="center">
<a href="https://github.com/gewuwo">
<img src="https://avatars.githubusercontent.com/u/97213587?v=4" width="50;" alt="gewuwo"/>
<br />
<sub><b>格悟沃</b></sub>
</a>
</td></tr>
<tr>
</td>
<td align="center">
<a href="https://github.com/hushtian">
<img src="https://avatars.githubusercontent.com/u/55479601?v=4" width="50;" alt="hushtian"/>
@ -305,7 +323,8 @@ 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"/>
@ -313,14 +332,20 @@ Hippo-4J 通过对 JDK 线程池增强,以及扩展三方框架底层线程池
<sub><b>Tudo</b></sub>
</a>
</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"/>
<br />
<sub><b>Null</b></sub>
</a>
</td></tr>
<tr>
</td>
<td align="center">
<a href="https://github.com/onesimplecoder">
<img src="https://avatars.githubusercontent.com/u/30288465?v=4" width="50;" alt="onesimplecoder"/>
@ -362,7 +387,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"/>
@ -377,14 +403,6 @@ Hippo-4J 通过对 JDK 线程池增强,以及扩展三方框架底层线程池
<sub><b>Lynn</b></sub>
</a>
</td>
<td align="center">
<a href="https://github.com/sanliangitch">
<img src="https://avatars.githubusercontent.com/u/48200100?v=4" width="50;" alt="sanliangitch"/>
<br />
<sub><b>WuLang</b></sub>
</a>
</td></tr>
<tr>
<td align="center">
<a href="https://github.com/alexhaoxuan">
<img src="https://avatars.githubusercontent.com/u/46749051?v=4" width="50;" alt="alexhaoxuan"/>
@ -433,7 +451,8 @@ 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"/>
@ -447,8 +466,7 @@ Hippo-4J 通过对 JDK 线程池增强,以及扩展三方框架底层线程池
<br />
<sub><b>Null</b></sub>
</a>
</td></tr>
<tr>
</td>
<td align="center">
<a href="https://github.com/stronglong">
<img src="https://avatars.githubusercontent.com/u/15846157?v=4" width="50;" alt="stronglong"/>
@ -463,13 +481,6 @@ Hippo-4J 通过对 JDK 线程池增强,以及扩展三方框架底层线程池
<sub><b>Null</b></sub>
</a>
</td>
<td align="center">
<a href="https://github.com/jialei-jack">
<img src="https://avatars.githubusercontent.com/u/93201205?v=4" width="50;" alt="jialei-jack"/>
<br />
<sub><b>Jialei-jack</b></sub>
</a>
</td>
<td align="center">
<a href="https://github.com/klsq94">
<img src="https://avatars.githubusercontent.com/u/16208392?v=4" width="50;" alt="klsq94"/>
@ -504,15 +515,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,15 +579,15 @@ 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>
<td align="center">
<a href="https://github.com/li-xiao-shuang">
<img src="https://avatars.githubusercontent.com/u/34903552?v=4" width="50;" alt="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>
```
@ -69,13 +69,11 @@ spring:
package cn.hippo4j.example;
import cn.hippo4j.core.executor.DynamicThreadPool;
import cn.hippo4j.core.executor.support.ResizableCapacityLinkedBlockIngQueue;
import cn.hippo4j.core.executor.support.ThreadPoolBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
@Configuration
public class ThreadPoolConfig {

@ -8,13 +8,13 @@ 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>
- <a href="#群机器人接受不到通知报警">群机器人接受不到通知报警</a>
- <a href="#设置线程池参数优先级问题">设置线程池参数优先级问题</a>
- <a href="#线程池实例中修改队列容量参数问题">线程池实例中修改队列容量参数问题</a>
- <a href="#控制台-sockettimeoutexception-connect-timed-out">控制台 SocketTimeoutException: connect timed out</a>
## 租户和项目在 Hippo4J 中是什么意思
@ -47,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暂时不打算上线生产环境。
@ -94,3 +82,9 @@ Hippo4J 发布时可能会涉及到两端发布,分别是 Server 和 Starter
## 线程池实例中修改队列容量参数问题
在线程池管理中添加时,只有当选择队列类型为 `ResizableCapacityLinkedBlockingQueue` 时,后续再进行修改容量大小时才会实时的刷新修改成功。
## 控制台 SocketTimeoutException: connect timed out
控制台中触发的某些操作涉及到 hippo4j-server 调用客户端项目。如果 hippo4j-server 部署在测试环境,而客户端项目为本地启动,则会触发该问题。
为什么编辑线程池参数不报错?因为线程池的动态变更是客户端主动发起连接,和服务端保持了一个长轮询,所以不存在服务端主动调用客户端行为。

@ -0,0 +1,23 @@
---
sidebar_position: 5
---
# 推荐公众号
## JavaGuide
专注Java后端学习和大厂面试的公众号
![](https://images-machen.oss-cn-beijing.aliyuncs.com/JavaGuide.png)
## HelloGitHub
HelloGitHub专注于开源社区技术和知识内容分享。
![](https://images-machen.oss-cn-beijing.aliyuncs.com/HelloGitHub.png)
## macrozheng
专注Java技术分享解析优质开源项目。涵盖SpringBoot、SpringCloud、Docker、K8S等实用技术作者Github开源项目mall50K+Star
![](https://images-machen.oss-cn-beijing.aliyuncs.com/macrozheng.png)

@ -0,0 +1,23 @@
---
sidebar_position: 6
---
# 公众号合作
## 推荐须知
hippo4j 作为一款新兴动态线程池框架,开源出来的时间比较晚,目前迫切需要不同的途径进行推广。
如果您是公众号运营者或者开源爱好者,欢迎将 hippo4j 推荐给您的粉丝。
1. 您无需为 hippo4j 专门撰写文案,只需要直接导入 [推荐文章](https://mp.weixin.qq.com/s/JTTwcBEiK_MnFcPTZl3zGA) 即可。
2. 在文章底部或内容中留下项目官网或者 GitHub 仓库链接。
3. 文章需至少 1000+ 的阅读量。
作为推荐回报hippo4j 可以为您:
1. 在框架官方文档 [推荐公众号](/docs/user_docs/other/official-ccounts) 页面处留下您的公众号二维码。
2. 在框架官方交流群里@全体成员推广您的公众号一次,附带介绍语。
3. 您的公众号所有新推文章都可以将链接发送到 hippo4j 交流群中,增加阅读量。
如果您还有除公众号以外的其它途径可以与 hippo4j 相互推荐,欢迎 [加群沟通](/docs/user_docs/other/group)。

@ -0,0 +1,299 @@
---
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)
**Feature**
- 支持 H2 数据库 @weihubeats
- 动态线程池配置变更时,支持单个、多个或全部节点变 @pizihao
- 增加线程池活跃度和容量报警可选择关闭
- @DynamicThreadPool 线程池不存在则创建 @shanjianq
- 支持 ETCD 配置中心动态调整参数 @weihubeats
- 创建动态线程池支持 spring 线程池 @BigXin0109
- 线程池实例变更增加执行超时时间
- 线程池相关查询页面增加阻塞队列属性
- 定义动态线程池时,抽象默认配置
- 提供 ExecutorContext 封装上下文细节 @road2master
- Docker 制作服务端镜像,帮助开发者快速启动 @BigXin0109
- RabbitMQ 适配器增加多个 MQ 数据源 @weihubeats
**Bug**
- 动态线程池设置关闭时启动报错 @dousp
- ExecutorTtlWrapper 类型的 Executor 不生效 @BigXin0109
- Undertow 获取 WebServer 类型参数异常 @shining-stars-lk
- 修复线程池核心、最大线程数校验限制
- ByteConvertUtil#getPrintSize 单位转换错误 @onesimplecoder
- 创建线程池单选框选择错误
- ReflectUtil#getFieldsDirectly missing fields @BigXin0109
- 本地代码中设置的 capacity 无效 @BigXin0109
- 服务端线程池超时时间存在拆箱空指针异常 @oreoft
- 未读取服务端返回执行超时时间属性
- ResizableCapacityLinkedBlockingQueue#put 当前元素数量大于 capacity 未阻塞
**Optimize**
- 长轮询任务判断逻辑优化 @shining-stars-lk
- 线程池存在实例不允许删除线程池 @shanjianq
- 优化租户、项目列表展示排版
- 通知报警模块项目和线程池下拉查询排序修改
- 动态线程池拒绝策略触发,以异步的方式报警
- 优化框架中线程池工厂产生的线程名称 @road2master
## 1.4.0 (Aug 16, 2022)
`hippo4j server` 兼容历史低版本,`hippo4j config` 中部分属性名进行了调整,请参考 [hippo4j config 快速开始](https://hippo4j.cn/docs/user_docs/getting-started/hippo4j-core-start)。
注意事项:
1. 如果是对已运行 hippo4j server 升级,执行 `/conf/sql-upgrade` 目录下对应的升级脚本。
2. 需客户端在 1.4.0 及以上版本才可在 hippo4j server 设置线程执行超时时间属性。
**Feature**
- 添加 Alibaba Dubbo 线程池监控及动态变更
- hippo4j server 支持任务执行超时时间动态修改
- 阿里 TTL 框架线程池适配
- 添加动态线程池自动注册功能
- 订阅回调线程池参数变更
- 动态线程池监控增加 SPI 自定义功能
- hippo4j server 支持多种线程池监控方式,例如 Prometheus
- 通知相关参数添加动态变更功能
**Bug**
- 线程池变更executeTimeOut 变更极端情况下会出现异常
- 用户登录时候,如果输入了不存在的用户名,后台报空指针异常
- 修复了对 spring-boot 服务中 tomcat 线程池的兼容问题
- 排除 Tomcat Jar 使用 Undertow 启动报错
**Optimize**
- hippo4j-core-spring-boot-starter 模块修改名称为 hippo4j-config-spring-boot-starter
- 拆分容器线程池子页面Tomcat、Undertow、Jetty
- 服务端访问客户端时对 URL 转码
- MyBatisPlus 修改全局填充方法优化
- 控制台线程池列表下拉框默认正序
- 控制台线程池实例菜单,对于非可修改容量队列外,不允许修改队列容量
- 动态线程池控制台功能变更
- 租户和项目列表分页查询按照创建时间倒序展示
- 线程池监控页面图表 UI 优化
- 设置 maven-gpg-plugin 插件默认不执行
- 前端控制台相关搜索条件添加必填提示
- hippo4j 消息通知 & 报警抽象优化
- 配置中心未配置线程池启动报错
- 控制台线程池报警 UI 以及功能优化
- Web、框架线程池编辑弹框 UI 优化
- 线程池添加、编辑页面 UI 优化
- 线程池运行详情页前端 UI 优化
**Refactor**
- 删除自定义日志组件
- 线程池监控功能重构
- hippo4j core 配置中心生效判断重构
- 配置变更通知 & 报警通知重构
- Web 容器线程池适配迁移 hippo4j-adapter
## 1.3.1 (July 17, 2022)
注:这是一个兼容历史版本的小范围升级。
**Feature**
- 控制台新增线程池功能设置为 Admin 权限
- 添加 Hystrix 线程池监控及动态变更
- 添加 Netty 上传动态线程池监控数据方式
- 添加 GitHub Actions CI 流程
- 添加 Spring Kafka 示例项目
- Tomcat 版本号 >= 9.0.55 线程池适配
**Refactor**
- 更多线程池拆分子目录页面
**Optimize**
- hippo4j core 添加 banner 打印
- 优化可变更容量阻塞队列名称
**BUG**
- Apollo 配置修改延迟了一个版本
- Spring Boot 环境下使用 hippo4j-core 接入,配置中心使用 nacos启动时提示 ConfigService not found
查看 1.3.1 版本发布https://github.com/mabaiwan/hippo4j/milestone/9
## 1.3.0 (June 06, 2022)
1.3.0 发布 **适配三方框架的基础框架**。
目前已完成 **Dubbo、RabbitMQ、RocketMQ、RocketMQSpringCloudStream** 的线程池适配,后续还会接入 **Kafka、Hystrix** 等框架或中间件的线程池适配。
注:这是一个兼容历史版本的重大升级。
**Feature**
- 添加 RabbitMQ 线程池监控及动态变更
- 添加 RocketMQ 线程池监控及动态变更
- 添加 Dubbo 线程池监控及动态变更
- 添加 SpringCloud Stream RocketMQ 消费线程池监控及动态变更
**Refactor**
- 重构容器线程池查询及修改功能
- 优化配置中心触发监听后,所执行的数据变更逻辑
**Optimize**
- 前端控制台删除无用组件
- 服务端页面字段未显示中文
- 控制台 UI 优化
- 修改线程池实例后实时刷新列表参数
- 容器线程池编辑仅限 Admin 权限
- SpringBoot Starter 变更包路径
**BUG**
- 修复 SpringBoot Nacos 动态刷新不生效
- 报警配置 alarm=false 不配置通知报警平台和接收人报错
## 1.2.1 (May 07, 2022)
**BugFix**
- apollo 动态配置不生效
- 修复 hippo4j-core 后置处理器创建线程池问题
- 重构 hippo4j-core spring 后置处理器逻辑
- 优化ThreadPoolNotifyAlarmHandler下的空指针异常
- 修复线程池核心、最大线程数变更问题
- startup.cmd 未正常读取 conf 配置文件
**Optimize**
- 配置文件中字段歧义
- 修改代码中历史网址
- InstanceInfo 的 groupKey 参数重复设置
- ConfigFileTypeEnum 枚举字段添加注释
- 线程资源通过线程池创建,不允许自行显示创建线程
- Guava 版本升级至 30.0-jre 及以上版本
- SystemClock 替换 System.currentTimeMillis()
- 添加代码格式化插件 Spotless
- 修改线程池文案
## 1.2.0 (Mar 13, 2022)
**Feature**
- hippo4j-core线程池资源对接 Prometheus 监控
- hippo4j-core 支持 Zookeeper
- hippo4j-core 支持 Apollo
**Optimize**
- 适配非 Web SpringBoot 项目使用 Hippo4J
- 优化报警通知
- 修复在 JDK 小版本中的兼容性问题
**BugFix**
- server 端查看容器线程池,参数为 null
- 重构线程池查看及容器线程池查看等交互
- 修复引入 hippo4j-spring-boot-starter 后,运行单元测试报错
- 修复可能出现的空指针异常
## 1.1.0 (Mar 13, 2022)
Hippo4J 线程池框架 1.1.0 RELEASE 版本,添加了 Hippo4J-Core依赖配置中心的动态线程池.
**Feature**
- 删除 DynamicThreadPoolExecutor 内代码实现,仅通过线程池扩展点进行扩展
- 通过动态代理实现线程池拒绝策略执行次数统计
- 抽象通知报警消息模块
- 抽象 hippo4j 核心组件,不依赖 server 端即可完成动态调参、监控、报警等功能
- 前端删除线程池按钮添加 Admin 权限
- 添加线程池任务运行超长报警
- 容器线程池支持 Undertow
- 容器线程池支持 Jetty
- 重构服务端异常体系
**Optimize**
- 前端项目 Token 失效跳转登录页
- 优化 Server 启动脚本日志输出
- 优化前端按钮权限控制粒度
- 优化线程池报警推送文案
- 前端弹框样式优化
- 适配低版本 SpringBoot Bind
- 优化消息通知模块
**BugFix**
- Duplicate entry 'xxx' for key 'uk_configinfo_datagrouptenant'
## 1.0.0 (Feb 01, 2022)
**Feature**
- 线程池运行堆栈查看
- 扩展 Web 容器线程池动态调参、监控
**Optimize**
- 删除高版本 SpringBoot Api
- ListableBeanFactory#findAnnotationOnBean SpringBoot 低版本适配
- 优化客户端关闭时调用服务端钩子函数
- 线程池实例参数弹框添加实例 ID 和线程池状态
- 补充线程池替换 Hippo4J 文档
- 1.5.x springboot 引入hippo4j-spring-boot-starter配置项bean初始化失败
- 优化线程池参数编辑合理性校验
- BaseInstanceRegistry 读写锁重构
**BugFix**
- 本地项目线程池实例缓存无法精确清理
- 线程池实例页面多实例不同 Active 展示错误
- 创建动态线程池逻辑判断修复
- 创建动态线程池增强参数未设置
- 控制消息推送报警频率的方法有并发安全的问题
- tomcat线程池上下文获取失败

@ -60,7 +60,7 @@ const config = {
announcementBar: {
id: 'announcementBar-1', // Increment on change
// content: `⭐️ If you like hippo4j, give it a star on <a target="_blank" rel="noopener noreferrer" href="https://gitee.com/mabaiwancn/hippo4j">Gitee</a>, thanks.`,
content: `⭐️ 如果您喜欢 hippo4j请在 <a target="_blank" rel="noopener noreferrer" href="https://gitee.com/mabaiwancn/hippo4j">Gitee</a> <a target="_blank" rel="noopener noreferrer" href="https://github.com/opengoofy/hippo4j">GitHub</a> 上给它一个 star谢谢`,
content: `⭐️ 如果您喜欢 hippo4j请在 <a target="_blank" rel="noopener noreferrer" href="https://gitee.com/mabaiwancn/hippo4j">Gitee</a> <a target="_blank" rel="noopener noreferrer" href="https://github.com/opengoofy/hippo4j">GitHub</a> 上给它一个 star谢谢`,
// content: `<a target="_blank" rel="noopener noreferrer" href="https://xiaomage.info/knowledge-planet/">👉 《小马哥的代码实战课》官方知识星球来啦!!!</a>`,
},
navbar: {
@ -146,7 +146,7 @@ const config = {
items: [
{
label: 'Gitee',
href: 'https://gitee.com/mabaiwancn/hippo4j',
href: 'https://gitee.com/itmachen/hippo4j',
},
{
label: 'GitHub',

@ -18,42 +18,10 @@
<groupId>cn.hippo4j</groupId>
<artifactId>hippo4j-adapter-base</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>dubbo</artifactId>
<version>${alibaba-dubbo.version}</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<configuration>
<archive>
<manifestEntries>
<Implementation-Title>${project.artifactId}</Implementation-Title>
<Implementation-Version>${project.version}</Implementation-Version>
<Build-Time>${maven.build.timestamp}</Build-Time>
<Built-By>chen.ma</Built-By>
</manifestEntries>
</archive>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<version>2.10.3</version>
<executions>
<execution>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>

@ -8,7 +8,6 @@
<version>${revision}</version>
</parent>
<artifactId>hippo4j-adapter-base</artifactId>
<name>hippo4j-adapter-base</name>
<dependencies>
<dependency>
@ -17,35 +16,4 @@
<version>${revision}</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<configuration>
<archive>
<manifestEntries>
<Implementation-Title>${project.artifactId}</Implementation-Title>
<Implementation-Version>${project.version}</Implementation-Version>
<Build-Time>${maven.build.timestamp}</Build-Time>
<Built-By>chen.ma</Built-By>
</manifestEntries>
</archive>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<version>2.10.3</version>
<executions>
<execution>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>

@ -18,7 +18,6 @@
<groupId>cn.hippo4j</groupId>
<artifactId>hippo4j-adapter-base</artifactId>
</dependency>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo</artifactId>
@ -26,35 +25,4 @@
<optional>true</optional>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<configuration>
<archive>
<manifestEntries>
<Implementation-Title>${project.artifactId}</Implementation-Title>
<Implementation-Version>${project.version}</Implementation-Version>
<Build-Time>${maven.build.timestamp}</Build-Time>
<Built-By>chen.ma</Built-By>
</manifestEntries>
</archive>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<version>2.10.3</version>
<executions>
<execution>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>

@ -14,42 +14,10 @@
<groupId>cn.hippo4j</groupId>
<artifactId>hippo4j-adapter-base</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
<version>${spring-cloud-starter-netflix-hystrix.version}</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<configuration>
<archive>
<manifestEntries>
<Implementation-Title>${project.artifactId}</Implementation-Title>
<Implementation-Version>${project.version}</Implementation-Version>
<Build-Time>${maven.build.timestamp}</Build-Time>
<Built-By>chen.ma</Built-By>
</manifestEntries>
</archive>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<version>2.10.3</version>
<executions>
<execution>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>

@ -15,35 +15,4 @@
<artifactId>hippo4j-adapter-base</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<configuration>
<archive>
<manifestEntries>
<Implementation-Title>${project.artifactId}</Implementation-Title>
<Implementation-Version>${project.version}</Implementation-Version>
<Build-Time>${maven.build.timestamp}</Build-Time>
<Built-By>chen.ma</Built-By>
</manifestEntries>
</archive>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<version>2.10.3</version>
<executions>
<execution>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>

@ -14,41 +14,9 @@
<groupId>cn.hippo4j</groupId>
<artifactId>hippo4j-adapter-base</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<configuration>
<archive>
<manifestEntries>
<Implementation-Title>${project.artifactId}</Implementation-Title>
<Implementation-Version>${project.version}</Implementation-Version>
<Build-Time>${maven.build.timestamp}</Build-Time>
<Built-By>chen.ma</Built-By>
</manifestEntries>
</archive>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<version>2.10.3</version>
<executions>
<execution>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>

@ -14,42 +14,10 @@
<groupId>cn.hippo4j</groupId>
<artifactId>hippo4j-adapter-base</artifactId>
</dependency>
<dependency>
<groupId>org.apache.rocketmq</groupId>
<artifactId>rocketmq-spring-boot-starter</artifactId>
<version>${rocketmq.version}</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<configuration>
<archive>
<manifestEntries>
<Implementation-Title>${project.artifactId}</Implementation-Title>
<Implementation-Version>${project.version}</Implementation-Version>
<Build-Time>${maven.build.timestamp}</Build-Time>
<Built-By>chen.ma</Built-By>
</manifestEntries>
</archive>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<version>2.10.3</version>
<executions>
<execution>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>

@ -15,35 +15,4 @@
<artifactId>hippo4j-adapter-base</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<configuration>
<archive>
<manifestEntries>
<Implementation-Title>${project.artifactId}</Implementation-Title>
<Implementation-Version>${project.version}</Implementation-Version>
<Build-Time>${maven.build.timestamp}</Build-Time>
<Built-By>chen.ma</Built-By>
</manifestEntries>
</archive>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<version>2.10.3</version>
<executions>
<execution>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>

@ -14,42 +14,10 @@
<groupId>cn.hippo4j</groupId>
<artifactId>hippo4j-adapter-base</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-stream-rabbit</artifactId>
<version>${spring-cloud-starter-stream-rabbitmq.version}</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<configuration>
<archive>
<manifestEntries>
<Implementation-Title>${project.artifactId}</Implementation-Title>
<Implementation-Version>${project.version}</Implementation-Version>
<Build-Time>${maven.build.timestamp}</Build-Time>
<Built-By>chen.ma</Built-By>
</manifestEntries>
</archive>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<version>2.10.3</version>
<executions>
<execution>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>

@ -14,42 +14,10 @@
<groupId>cn.hippo4j</groupId>
<artifactId>hippo4j-adapter-base</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-stream-rocketmq</artifactId>
<version>${spring-cloud-starter-stream-rocketmq.version}</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<configuration>
<archive>
<manifestEntries>
<Implementation-Title>${project.artifactId}</Implementation-Title>
<Implementation-Version>${project.version}</Implementation-Version>
<Build-Time>${maven.build.timestamp}</Build-Time>
<Built-By>chen.ma</Built-By>
</manifestEntries>
</archive>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<version>2.10.3</version>
<executions>
<execution>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>

@ -16,69 +16,32 @@
<version>${tomcat-embed-core.version}</version>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jetty</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-undertow</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>cn.hippo4j</groupId>
<artifactId>hippo4j-core</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<configuration>
<archive>
<manifestEntries>
<Implementation-Title>${project.artifactId}</Implementation-Title>
<Implementation-Version>${project.version}</Implementation-Version>
<Build-Time>${maven.build.timestamp}</Build-Time>
<Built-By>chen.ma</Built-By>
</manifestEntries>
</archive>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<version>2.10.3</version>
<executions>
<execution>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>

@ -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()));
}
}

@ -18,45 +18,37 @@
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</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-security</artifactId>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>${jjwt.version}</version>
</dependency>
<dependency>
<groupId>cn.hippo4j</groupId>
<artifactId>hippo4j-common</artifactId>

@ -0,0 +1,38 @@
/*
* 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.auth.config;
import cn.hippo4j.auth.filter.RewriteUserInfoApiFilter;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
*
*/
@Configuration
public class FilterConfig {
@Bean
public FilterRegistrationBean<RewriteUserInfoApiFilter> userInfoApiFilterRegistrationBean() {
FilterRegistrationBean<RewriteUserInfoApiFilter> registration = new FilterRegistrationBean<>();
registration.setFilter(new RewriteUserInfoApiFilter());
registration.addUrlPatterns("/*");
return registration;
}
}

@ -0,0 +1,46 @@
/*
* 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.auth.filter;
import cn.hippo4j.auth.toolkit.AuthUtil;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
/**
* When anonymous login is enabled, an error will be reported when viewing the current user information.
* Modify the URI to query the default administrator information.
*
* before:hippo4j/v1/cs/auth/users/info or hippo4j/v1/cs/auth/users/info/xxx
* after:hippo4j/v1/cs/auth/users/info/admin
*/
public class RewriteUserInfoApiFilter implements Filter {
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
boolean enableAuthentication = AuthUtil.enableAuthentication;
HttpServletRequest httpRequest = (HttpServletRequest) servletRequest;
String path = httpRequest.getRequestURI();
if (!enableAuthentication && path.contains("users/info")) {
httpRequest.getRequestDispatcher("/hippo4j/v1/cs/auth/users/info/admin").forward(servletRequest, servletResponse);
return;
}
filterChain.doFilter(servletRequest, servletResponse);
}
}

@ -0,0 +1,32 @@
/*
* 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.auth.toolkit;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
@Component
public class AuthUtil {
public static boolean enableAuthentication;
@Value("${hippo4j.core.auth.enabled:true}")
public void setEnableAuthentication(boolean enabled) {
AuthUtil.enableAuthentication = enabled;
}
}

@ -22,90 +22,45 @@
<artifactId>spring-context</artifactId>
<version>${spring-context.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>${spring-web.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>${spring-beans.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>${spring-core.version}</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<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>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.github.ben-manes.caffeine</groupId>
<artifactId>caffeine</artifactId>
</dependency>
<dependency>
<groupId>com.github.dozermapper</groupId>
<artifactId>dozer-core</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<configuration>
<archive>
<manifestEntries>
<Implementation-Title>${project.artifactId}</Implementation-Title>
<Implementation-Version>${project.version}</Implementation-Version>
<Build-Time>${maven.build.timestamp}</Build-Time>
<Built-By>chen.ma</Built-By>
</manifestEntries>
</archive>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<version>2.10.3</version>
<executions>
<execution>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>

@ -15,23 +15,20 @@
* limitations under the License.
*/
package cn.hippo4j.core.executor.support;
package cn.hippo4j.common.api;
import org.slf4j.MDC;
import static cn.hippo4j.common.constant.Constants.EXECUTE_TIMEOUT_TRACE;
import org.springframework.core.env.ConfigurableEnvironment;
/**
* Executor context.
* Client network service.
*/
public class ExecutorContext {
public interface ClientNetworkService {
/**
* Put execute timeout trace.
* Get network ip port. return as an array 127.0.0.1,8080
*
* @param executeTimeoutTrace
* @param environment environment
* @return network ip port
*/
public static void putExecuteTimeoutTrace(String executeTimeoutTrace) {
MDC.put(EXECUTE_TIMEOUT_TRACE, executeTimeoutTrace);
}
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;

@ -0,0 +1,46 @@
/*
* 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 header constants.
*/
public interface HttpHeaderConstants {
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;
}

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

@ -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);
}
}

@ -29,6 +29,8 @@ public class StringUtil {
public static final char UNDERLINE = '_';
public static final String[] EMPTY_ARRAY = new String[0];
/**
* Returns the given string if it is nonempty; {@code null} otherwise.
*
@ -52,9 +54,11 @@ public class StringUtil {
/**
* Returns {@code true} if the given string is null or is the empty string.
*
* this method has been deprecated, use isEmpty() instead.
* @param str
* @return
*/
@Deprecated
public static boolean isNullOrEmpty(String str) {
return str == null || str.isEmpty();
}
@ -223,6 +227,56 @@ public class StringUtil {
return sb.toString();
}
/**
* combination CharSequence, get a String
*
* @param charSequences CharSequence, if null or empty, get {@link StringUtil#EMPTY}
* @return String
*/
public static String newBuilder(CharSequence... charSequences) {
if (charSequences == null || charSequences.length == 0) {
return StringUtil.EMPTY;
}
return createBuilder(charSequences).toString();
}
/**
* combination CharSequence, get a StringBuilder
*
* @param charSequences CharSequence
* @return StringBuilder
*/
public static StringBuilder createBuilder(CharSequence... charSequences) {
StringBuilder builder = new StringBuilder();
if (charSequences == null || charSequences.length == 0) {
return builder;
}
for (CharSequence sequence : charSequences) {
builder.append(sequence);
}
return builder;
}
/**
* combination CharSequence, to StringBuilder
*
* @param builder StringBuilder, if null create a new
* @param charSequences CharSequence
* @return StringBuilder
*/
public static StringBuilder appends(StringBuilder builder, CharSequence... charSequences) {
if (builder == null) {
return createBuilder(charSequences);
}
if (charSequences == null || charSequences.length == 0) {
return builder;
}
for (CharSequence sequence : charSequences) {
builder.append(sequence);
}
return builder;
}
/**
* Replace a portion of the string, replacing all found
*
@ -238,6 +292,33 @@ public class StringUtil {
.replaceAll(Matcher.quoteReplacement(replaceStr));
}
/**
* <p>Splits the provided text into an array, separators specified.
*
* <pre>
* StringUtils.split(null, *) = null
* StringUtils.split("", *) = []
* StringUtils.split("abc def", null) = ["abc", "def"]
* StringUtils.split("abc def", " ") = ["abc", "def"]
* StringUtils.split("ab:cd:ef", ":") = ["ab", "cd", "ef"]
* </pre>
* @param str the String to parse, may be null
* @param separatorChars the characters used as the delimiters,
* @return an array of parsed Strings
*/
public static String[] split(final String str, final String separatorChars) {
if (str == null) {
return null;
}
if (isBlank(str)) {
return EMPTY_ARRAY;
}
if (isBlank(separatorChars)) {
return str.split(" ");
}
return str.split(separatorChars);
}
/**
* Tests if this string starts with the specified prefix.
*

@ -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());
}
}

@ -18,83 +18,158 @@
package cn.hippo4j.common.toolkit;
import org.junit.Test;
import org.junit.Assert;
import java.util.Objects;
import java.util.Arrays;
import java.util.Optional;
public class StringUtilTest {
@Test
public void replace() {
String url = "http://localhost:8088/hippo4j_manager?";
String replace = StringUtil.replace(url, "/hippo4j_manager?", "?");
Assert.assertEquals(replace, "http://localhost:8088?");
}
/**
* <p>Splits the provided text into an array, separators specified.
*
* <pre>
* StringUtils.split(null, *) = null
* StringUtils.split("", *) = []
* StringUtils.split("abc def", null) = ["abc", "def"]
* StringUtils.split("abc def", " ") = ["abc", "def"]
* StringUtils.split("ab:cd:ef", ":") = ["ab", "cd", "ef"]
* </pre>
*/
@Test
public void split() {
String str1 = null;
String separator1 = "*";
String[] res1 = StringUtil.split(str1, separator1);
assert res1 == null;
String str2 = "";
String separator2 = "*";
String[] res2 = StringUtil.split(str2, separator2);
Assert.assertArrayEquals(res2, new String[0]);
String str3 = "abc def";
String separator3 = null;
String[] res3 = StringUtil.split(str3, separator3);
Assert.assertArrayEquals(res3, new String[]{"abc", "def"});
String str4 = "abc def";
String separator4 = " ";
String[] res4 = StringUtil.split(str4, separator4);
Assert.assertArrayEquals(res4, new String[]{"abc", "def"});
String str5 = "ab:cd:ef";
String separator5 = ":";
String[] res5 = StringUtil.split(str5, separator5);
Assert.assertArrayEquals(res5, new String[]{"ab", "cd", "ef"});
}
@Test
public void assertIsEmpty() {
String string = "";
Assert.isTrue(StringUtil.isEmpty(string));
Assert.assertTrue(StringUtil.isEmpty(string));
}
@Test
public void assertIsNotEmpty() {
String string = "string";
Assert.isTrue(StringUtil.isNotEmpty(string));
Assert.assertTrue(StringUtil.isNotEmpty(string));
}
@Test
public void emptyToNull() {
String string = "";
Assert.isNull(StringUtil.emptyToNull(string));
Assert.assertNull(StringUtil.emptyToNull(string));
}
@Test
public void nullToEmpty() {
String string = "null";
Assert.notEmpty(StringUtil.nullToEmpty(string));
Assert.assertEquals("null", StringUtil.nullToEmpty(string));
}
@Test
public void isNullOrEmpty() {
String string = "null";
Assert.isTrue(!StringUtil.isNullOrEmpty(string));
Assert.assertFalse(StringUtil.isEmpty(string));
}
@Test
public void isBlank() {
String string = "";
Assert.isTrue(StringUtil.isBlank(string));
Assert.assertTrue(StringUtil.isBlank(string));
}
@Test
public void isNotBlank() {
String string = "null";
Assert.isTrue(StringUtil.isNotBlank(string));
Assert.assertTrue(StringUtil.isNotBlank(string));
}
@Test
public void isAllNotEmpty() {
String strings = "str";
Assert.isTrue(StringUtil.isAllNotEmpty(strings));
Assert.assertTrue(StringUtil.isAllNotEmpty(strings));
}
@Test
public void hasEmpty() {
String strings = "";
Assert.isTrue(StringUtil.hasEmpty(strings));
Assert.assertTrue(StringUtil.hasEmpty(strings));
}
@Test
public void toUnderlineCase() {
String string = "str";
String s = StringUtil.toUnderlineCase(string);
Assert.isTrue(Objects.equals(s, "str"));
Assert.assertEquals("str", s);
}
@Test
public void toSymbolCase() {
String string = "str";
String s = StringUtil.toSymbolCase(string, StringUtil.UNDERLINE);
Assert.isTrue(Objects.equals(s, "str"));
Assert.assertEquals("str", s);
}
@Test
public void toCamelCase() {
String string = "str_str";
String s = StringUtil.toCamelCase(string, StringUtil.UNDERLINE);
Assert.isTrue(Objects.equals(s, "strStr"));
Assert.assertEquals("strStr", s);
}
@Test
public void newBuilder() {
String s1 = StringUtil.newBuilder(null);
Assert.assertEquals("", s1);
String s2 = StringUtil.newBuilder("H", "ippo", "4j");
Assert.assertEquals("Hippo4j", s2);
}
@Test
public void createBuilder() {
StringBuilder s1 = StringUtil.createBuilder(null);
Assert.assertEquals("", s1.toString());
StringBuilder s2 = StringUtil.createBuilder("H", "ippo", "4j");
Assert.assertEquals("Hippo4j", s2.toString());
}
@Test
public void appends() {
StringBuilder sb1 = StringUtil.appends(null, "H", "ippo", "4j");
Assert.assertEquals("Hippo4j", sb1.toString());
StringBuilder sb2 = StringUtil.appends(StringUtil.createBuilder("To "), null);
Assert.assertEquals("To ", sb2.toString());
StringBuilder sb3 = StringUtil.appends(StringUtil.createBuilder("To "), "H", "ippo", "4j");
Assert.assertEquals("To Hippo4j", sb3.toString());
}
}

@ -0,0 +1,122 @@
/*
* 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.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 HttpUtilsTest {
/**
* test post url
*/
static String postUrl = "http://console.hippo4j.cn/hippo4j/v1/cs/";
/**
* test get url
*/
static String getUrl = "https://hippo4j.cn/";
@Test
public void get() {
String s = HttpUtil.get(getUrl);
Assert.assertNotNull(s);
}
@Test
public void restApiPost() {
String loginUrl = postUrl + "auth/login";
LoginInfo loginInfo = new LoginInfo();
loginInfo.setPassword("hippo4j");
loginInfo.setUsername("hippo4j");
loginInfo.setRememberMe(1);
String s = HttpUtil.post(loginUrl, loginInfo);
Result result = JSONUtil.parseObject(s, Result.class);
Assert.assertNotNull(result);
String data = result.getData().getData();
Assert.assertNotNull(data);
}
@Test
public void testRestApiPost() {
String loginUrl = postUrl + "auth/login";
LoginInfo loginInfo = new LoginInfo();
loginInfo.setPassword("hippo4j");
loginInfo.setUsername("hippo4j");
loginInfo.setRememberMe(1);
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 = HttpUtil.buildUrl(getUrl, map);
Assert.assertEquals(getUrl + "?password=hippo4j&username=hippo4j", s);
}
@Getter
@Setter
private static class LoginInfo {
private String username;
private String password;
private Integer rememberMe;
}
@Getter
@Setter
private static class Result {
private String code;
private ResultData data;
}
@Getter
@Setter
private static class ResultData {
private String data;
private String[] roles;
}
}

@ -20,71 +20,54 @@
<artifactId>hippo4j-common</artifactId>
<version>${revision}</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>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<version>${h2.version}</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<dependency>
<groupId>cn.hippo4j</groupId>
<artifactId>hippo4j-adapter-base</artifactId>
</dependency>
<dependency>
<groupId>cn.hippo4j</groupId>
<artifactId>hippo4j-discovery</artifactId>
<version>${version}</version>
</dependency>
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-all</artifactId>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
</dependency>
<dependency>
<groupId>org.hibernate.validator</groupId>
<artifactId>hibernate-validator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
</project>

@ -68,6 +68,23 @@ public class ConfigCacheService {
return Objects.equals(contentMd5, md5);
}
/**
* check TpId.
*
* @param groupKey
* @param tpId
* @param clientIdentify
* @return
*/
public static boolean checkTpId(String groupKey, String tpId, String clientIdentify) {
Map<String, CacheItem> cacheItemMap = Optional.ofNullable(CLIENT_CONFIG_CACHE.get(groupKey)).orElse(new HashMap<>());
CacheItem cacheItem;
if (CollectionUtil.isNotEmpty(cacheItemMap) && (cacheItem = cacheItemMap.get(clientIdentify)) != null) {
return Objects.equals(tpId, cacheItem.configAllInfo.getTpId());
}
return Boolean.FALSE;
}
/**
* Get Md5.
*

@ -25,20 +25,18 @@ import cn.hippo4j.common.design.observer.ObserverMessage;
import cn.hippo4j.common.toolkit.CollectionUtil;
import cn.hippo4j.common.toolkit.JSONUtil;
import cn.hippo4j.common.toolkit.StringUtil;
import cn.hippo4j.common.toolkit.http.HttpUtil;
import cn.hippo4j.common.web.base.Result;
import cn.hippo4j.config.model.biz.adapter.ThreadPoolAdapterReqDTO;
import cn.hippo4j.config.model.biz.adapter.ThreadPoolAdapterRespDTO;
import com.fasterxml.jackson.core.type.TypeReference;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;
import static cn.hippo4j.common.constant.Constants.HTTP_EXECUTE_TIMEOUT;
import static cn.hippo4j.common.constant.Constants.IDENTIFY_SLICER_SYMBOL;
/**
@ -49,7 +47,7 @@ import static cn.hippo4j.common.constant.Constants.IDENTIFY_SLICER_SYMBOL;
public class ThreadPoolAdapterService {
/**
* Map<mark, Map<tenantItem, Map<threadPoolKey, List<ThreadPoolAdapterState>>>>
* Map&lt;mark, Map&lt;tenantItem, Map&lt;threadPoolKey, List&lt;ThreadPoolAdapterState&gt;&gt;&gt;&gt;
*/
private static final Map<String, Map<String, Map<String, List<ThreadPoolAdapterState>>>> THREAD_POOL_ADAPTER_MAP = new ConcurrentHashMap<>();
@ -98,18 +96,12 @@ public class ThreadPoolAdapterService {
List<String> addressList = actual.stream().map(ThreadPoolAdapterState::getClientAddress).collect(Collectors.toList());
List<ThreadPoolAdapterRespDTO> result = new ArrayList<>(addressList.size());
addressList.forEach(each -> {
String urlString = new StringBuilder()
.append("http://")
.append(each)
.append("/adapter/thread-pool/info")
.toString();
Map<String, Object> param = new HashMap<>();
String url = StringUtil.newBuilder("http://", each, "/adapter/thread-pool/info");
Map<String, String> param = new HashMap<>();
param.put("mark", requestParameter.getMark());
param.put("threadPoolKey", requestParameter.getThreadPoolKey());
try {
RestTemplate template = new RestTemplate();
String resultStr = template.getForObject(urlString, String.class, param);
String resultStr = HttpUtil.get(url, param);
if (StringUtil.isNotBlank(resultStr)) {
Result<ThreadPoolAdapterRespDTO> restResult = JSONUtil.parseObject(resultStr, new TypeReference<Result<ThreadPoolAdapterRespDTO>>() {
});
@ -131,22 +123,13 @@ public class ThreadPoolAdapterService {
return actual.keySet();
}
}
return new HashSet();
return new HashSet<>();
}
public static void remove(String identify) {
synchronized (ThreadPoolAdapterService.class) {
THREAD_POOL_ADAPTER_MAP.values().forEach(each -> each.forEach((key, val) -> {
val.forEach((threadPoolKey, states) -> {
Iterator<ThreadPoolAdapterState> iterator = states.iterator();
while (iterator.hasNext()) {
ThreadPoolAdapterState adapterState = iterator.next();
if (Objects.equals(adapterState.getIdentify(), identify)) {
iterator.remove();
}
}
});
}));
THREAD_POOL_ADAPTER_MAP.values()
.forEach(each -> each.forEach((key, val) -> val.forEach((threadPoolKey, states) -> states.removeIf(adapterState -> Objects.equals(adapterState.getIdentify(), identify)))));
}
}

@ -74,15 +74,18 @@ public abstract class AbstractConfigModificationVerifyService implements ConfigM
.set(HisConfigVerifyInfo::getGmtVerify, new Date())
.set(HisConfigVerifyInfo::getVerifyUser, UserContext.getUserName());
hisConfigVerifyMapper.update(null, updateWrapper);
Date gmtVerify = hisConfigVerifyMapper.selectById(reqDTO.getId()).getGmtVerify();
Date gmtCreate = hisConfigVerifyMapper.selectById(reqDTO.getId()).getGmtCreate();
LambdaUpdateWrapper<HisConfigVerifyInfo> invalidUpdateWrapper = new LambdaUpdateWrapper<HisConfigVerifyInfo>()
.eq(HisConfigVerifyInfo::getType, reqDTO.getType())
.eq(reqDTO.getTenantId() != null, HisConfigVerifyInfo::getTenantId, reqDTO.getTenantId())
.eq(reqDTO.getItemId() != null, HisConfigVerifyInfo::getItemId, reqDTO.getItemId())
.eq(reqDTO.getTpId() != null, HisConfigVerifyInfo::getTpId, reqDTO.getTpId())
.and(reqDTO.getIdentify() != null, wrapper -> wrapper.eq(HisConfigVerifyInfo::getIdentify, reqDTO.getIdentify()).or().eq(HisConfigVerifyInfo::getModifyAll, true))
.lt(HisConfigVerifyInfo::getGmtVerify, gmtVerify)
.set(HisConfigVerifyInfo::getVerifyStatus, VerifyEnum.VERIFY_INVALID.getVerifyStatus());
.lt(HisConfigVerifyInfo::getGmtCreate, gmtCreate)
.eq(HisConfigVerifyInfo::getVerifyStatus, VerifyEnum.TO_VERIFY.getVerifyStatus())
.set(HisConfigVerifyInfo::getVerifyStatus, VerifyEnum.VERIFY_INVALID.getVerifyStatus())
.set(HisConfigVerifyInfo::getVerifyUser, UserContext.getUserName())
.set(HisConfigVerifyInfo::getGmtVerify, new Date());
hisConfigVerifyMapper.update(null, invalidUpdateWrapper);
}

@ -18,11 +18,11 @@
package cn.hippo4j.config.service.biz.impl;
import cn.hippo4j.common.constant.ConfigModifyTypeConstants;
import cn.hippo4j.common.toolkit.JSONUtil;
import cn.hippo4j.common.toolkit.StringUtil;
import cn.hippo4j.common.toolkit.http.HttpUtil;
import cn.hippo4j.config.model.biz.threadpool.ConfigModifyVerifyReqDTO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;
/**
* Adapter thread pool config modification verify service impl.
@ -31,8 +31,6 @@ import org.springframework.web.client.RestTemplate;
@Service
public class AdapterThreadPoolConfigModificationVerifyServiceImpl extends AbstractConfigModificationVerifyService {
private final RestTemplate restTemplate = new RestTemplate();
@Override
public Integer type() {
return ConfigModifyTypeConstants.ADAPTER_THREAD_POOL;
@ -41,12 +39,8 @@ public class AdapterThreadPoolConfigModificationVerifyServiceImpl extends Abstra
@Override
protected void updateThreadPoolParameter(ConfigModifyVerifyReqDTO reqDTO) {
for (String each : getClientAddress(reqDTO)) {
String urlString = new StringBuilder()
.append("http://")
.append(each)
.append("/adapter/thread-pool/update")
.toString();
restTemplate.postForObject(urlString, JSONUtil.toJSONString(reqDTO), Object.class);
String urlString = StringUtil.newBuilder("http://", each, "/adapter/thread-pool/update");
HttpUtil.post(urlString, reqDTO);
}
}
}

@ -32,6 +32,7 @@ import cn.hippo4j.config.model.biz.monitor.MonitorActiveRespDTO;
import cn.hippo4j.config.model.biz.monitor.MonitorQueryReqDTO;
import cn.hippo4j.config.model.biz.monitor.MonitorRespDTO;
import cn.hippo4j.config.monitor.QueryMonitorExecuteChoose;
import cn.hippo4j.config.service.ConfigCacheService;
import cn.hippo4j.config.service.biz.HisRunDataService;
import cn.hippo4j.common.toolkit.BeanUtil;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
@ -150,11 +151,14 @@ public class HisRunDataServiceImpl extends ServiceImpl<HisRunDataMapper, HisRunD
runtimeMessages.forEach(each -> {
HisRunDataInfo hisRunDataInfo = BeanUtil.convert(each, HisRunDataInfo.class);
String[] parseKey = GroupKey.parseKey(each.getGroupKey());
boolean checkFlag = ConfigCacheService.checkTpId(each.getGroupKey(), parseKey[0], parseKey[3]);
if (checkFlag) {
hisRunDataInfo.setTpId(parseKey[0]);
hisRunDataInfo.setItemId(parseKey[1]);
hisRunDataInfo.setTenantId(parseKey[2]);
hisRunDataInfo.setInstanceId(parseKey[3]);
hisRunDataInfos.add(hisRunDataInfo);
}
});
this.saveBatch(hisRunDataInfos);
}

@ -19,6 +19,7 @@ package cn.hippo4j.config.service.biz.impl;
import cn.hippo4j.common.toolkit.Assert;
import cn.hippo4j.common.enums.DelEnum;
import cn.hippo4j.common.toolkit.StringUtil;
import cn.hippo4j.config.mapper.ItemInfoMapper;
import cn.hippo4j.config.model.ItemInfo;
import cn.hippo4j.config.model.biz.item.ItemQueryReqDTO;
@ -36,7 +37,6 @@ import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.toolkit.SqlHelper;
import lombok.AllArgsConstructor;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import java.util.List;
@ -55,10 +55,10 @@ public class ItemServiceImpl implements ItemService {
@Override
public IPage<ItemRespDTO> queryItemPage(ItemQueryReqDTO reqDTO) {
LambdaQueryWrapper<ItemInfo> wrapper = Wrappers.lambdaQuery(ItemInfo.class)
.eq(!StringUtils.isEmpty(reqDTO.getItemId()), ItemInfo::getItemId, reqDTO.getItemId())
.eq(!StringUtils.isEmpty(reqDTO.getItemName()), ItemInfo::getItemName, reqDTO.getItemName())
.eq(!StringUtils.isEmpty(reqDTO.getTenantId()), ItemInfo::getTenantId, reqDTO.getTenantId())
.eq(!StringUtils.isEmpty(reqDTO.getOwner()), ItemInfo::getOwner, reqDTO.getOwner())
.eq(StringUtil.isNotEmpty(reqDTO.getItemId()), ItemInfo::getItemId, reqDTO.getItemId())
.eq(StringUtil.isNotEmpty(reqDTO.getItemName()), ItemInfo::getItemName, reqDTO.getItemName())
.eq(StringUtil.isNotEmpty(reqDTO.getTenantId()), ItemInfo::getTenantId, reqDTO.getTenantId())
.eq(StringUtil.isNotEmpty(reqDTO.getOwner()), ItemInfo::getOwner, reqDTO.getOwner())
.orderByDesc(reqDTO.getDesc() != null, ItemInfo::getGmtCreate);
Page<ItemInfo> resultPage = itemInfoMapper.selectPage(reqDTO, wrapper);
return resultPage.convert(each -> BeanUtil.convert(each, ItemRespDTO.class));
@ -78,8 +78,8 @@ public class ItemServiceImpl implements ItemService {
@Override
public List<ItemRespDTO> queryItem(ItemQueryReqDTO reqDTO) {
LambdaQueryWrapper<ItemInfo> wrapper = Wrappers.lambdaQuery(ItemInfo.class)
.eq(!StringUtils.isEmpty(reqDTO.getItemId()), ItemInfo::getItemId, reqDTO.getItemId())
.eq(!StringUtils.isEmpty(reqDTO.getTenantId()), ItemInfo::getTenantId, reqDTO.getTenantId());
.eq(StringUtil.isNotEmpty(reqDTO.getItemId()), ItemInfo::getItemId, reqDTO.getItemId())
.eq(StringUtil.isNotEmpty(reqDTO.getTenantId()), ItemInfo::getTenantId, reqDTO.getTenantId());
List<ItemInfo> itemInfos = itemInfoMapper.selectList(wrapper);
return BeanUtil.convert(itemInfos, ItemRespDTO.class);
}

@ -19,6 +19,7 @@ package cn.hippo4j.config.service.biz.impl;
import cn.hippo4j.common.enums.DelEnum;
import cn.hippo4j.common.toolkit.Assert;
import cn.hippo4j.common.toolkit.StringUtil;
import cn.hippo4j.config.mapper.TenantInfoMapper;
import cn.hippo4j.config.model.TenantInfo;
import cn.hippo4j.config.model.biz.item.ItemQueryReqDTO;
@ -37,7 +38,6 @@ import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.toolkit.SqlHelper;
import lombok.AllArgsConstructor;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import java.util.List;
@ -70,9 +70,9 @@ public class TenantServiceImpl implements TenantService {
@Override
public IPage<TenantRespDTO> queryTenantPage(TenantQueryReqDTO reqDTO) {
LambdaQueryWrapper<TenantInfo> wrapper = Wrappers.lambdaQuery(TenantInfo.class)
.eq(!StringUtils.isEmpty(reqDTO.getTenantId()), TenantInfo::getTenantId, reqDTO.getTenantId())
.eq(!StringUtils.isEmpty(reqDTO.getTenantName()), TenantInfo::getTenantName, reqDTO.getTenantName())
.eq(!StringUtils.isEmpty(reqDTO.getOwner()), TenantInfo::getOwner, reqDTO.getOwner())
.eq(StringUtil.isNotEmpty(reqDTO.getTenantId()), TenantInfo::getTenantId, reqDTO.getTenantId())
.eq(StringUtil.isNotEmpty(reqDTO.getTenantName()), TenantInfo::getTenantName, reqDTO.getTenantName())
.eq(StringUtil.isNotEmpty(reqDTO.getOwner()), TenantInfo::getOwner, reqDTO.getOwner())
.orderByDesc(reqDTO.getDesc() != null, TenantInfo::getGmtCreate);
Page resultPage = tenantInfoMapper.selectPage(reqDTO, wrapper);
return resultPage.convert(each -> BeanUtil.convert(each, TenantRespDTO.class));

@ -18,11 +18,11 @@
package cn.hippo4j.config.service.biz.impl;
import cn.hippo4j.common.constant.ConfigModifyTypeConstants;
import cn.hippo4j.common.toolkit.JSONUtil;
import cn.hippo4j.common.toolkit.StringUtil;
import cn.hippo4j.common.toolkit.http.HttpUtil;
import cn.hippo4j.config.model.biz.threadpool.ConfigModifyVerifyReqDTO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;
/**
* Web thread pool config modification verify service impl.
@ -31,8 +31,6 @@ import org.springframework.web.client.RestTemplate;
@Service
public class WebThreadPoolConfigModificationVerifyServiceImpl extends AbstractConfigModificationVerifyService {
private final RestTemplate restTemplate = new RestTemplate();
@Override
public Integer type() {
return ConfigModifyTypeConstants.WEB_THREAD_POOL;
@ -41,12 +39,8 @@ public class WebThreadPoolConfigModificationVerifyServiceImpl extends AbstractCo
@Override
protected void updateThreadPoolParameter(ConfigModifyVerifyReqDTO reqDTO) {
for (String each : getClientAddress(reqDTO)) {
String urlString = new StringBuilder()
.append("http://")
.append(each)
.append("/web/update/pool")
.toString();
restTemplate.postForObject(urlString, JSONUtil.toJSONString(reqDTO), Object.class);
String urlString = StringUtil.newBuilder("http://", each, "/web/update/pool");
HttpUtil.post(urlString, reqDTO);
}
}
}

@ -17,7 +17,7 @@
package cn.hippo4j.config.toolkit;
import org.apache.commons.lang3.StringUtils;
import cn.hippo4j.common.toolkit.StringUtil;
import java.nio.file.Paths;
import java.util.Objects;
@ -41,9 +41,9 @@ public class EnvUtil {
* @return
*/
public static String getHippo4JHome() {
if (StringUtils.isBlank(HIPPO4J_HOME_PATH)) {
if (StringUtil.isBlank(HIPPO4J_HOME_PATH)) {
String hippo4jHome = System.getProperty(HIPPO4J_HOME_KEY);
if (StringUtils.isBlank(hippo4jHome)) {
if (StringUtil.isBlank(hippo4jHome)) {
hippo4jHome = Paths.get(System.getProperty("user.home"), "hippo4j").toString();
}
return hippo4jHome;

@ -19,6 +19,7 @@ package cn.hippo4j.config.toolkit;
import cn.hippo4j.common.toolkit.GroupKey;
import cn.hippo4j.common.toolkit.Md5Util;
import cn.hippo4j.common.toolkit.StringUtil;
import cn.hippo4j.config.service.ConfigCacheService;
import cn.hippo4j.config.model.ConfigAllInfo;
import org.springframework.util.StringUtils;
@ -140,7 +141,7 @@ public class Md5ConfigUtil {
sb.append(dataIdGroupId[1]);
// if have tenant, then set it
if (dataIdGroupId.length == 4) {
if (org.apache.commons.lang3.StringUtils.isNotBlank(dataIdGroupId[2])) {
if (StringUtil.isNotBlank(dataIdGroupId[2])) {
sb.append(WORD_SEPARATOR);
sb.append(dataIdGroupId[2]);
}

@ -19,32 +19,19 @@
<artifactId>hippo4j-config</artifactId>
<version>${revision}</version>
</dependency>
<dependency>
<groupId>cn.hippo4j</groupId>
<artifactId>hippo4j-discovery</artifactId>
<version>${revision}</version>
</dependency>
<dependency>
<groupId>cn.hippo4j</groupId>
<artifactId>hippo4j-auth</artifactId>
<version>${revision}</version>
</dependency>
<dependency>
<groupId>org.hibernate.validator</groupId>
<artifactId>hibernate-validator</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>

@ -18,9 +18,8 @@
package cn.hippo4j.console.controller;
import cn.hippo4j.common.constant.ConfigModifyTypeConstants;
import cn.hippo4j.common.toolkit.BeanUtil;
import cn.hippo4j.common.toolkit.JSONUtil;
import cn.hippo4j.common.toolkit.UserContext;
import cn.hippo4j.common.toolkit.*;
import cn.hippo4j.common.toolkit.http.HttpUtil;
import cn.hippo4j.common.web.base.Result;
import cn.hippo4j.common.web.base.Results;
import cn.hippo4j.config.model.biz.adapter.ThreadPoolAdapterReqDTO;
@ -28,12 +27,11 @@ import cn.hippo4j.config.model.biz.adapter.ThreadPoolAdapterRespDTO;
import cn.hippo4j.config.model.biz.threadpool.ConfigModifySaveReqDTO;
import cn.hippo4j.config.service.ThreadPoolAdapterService;
import cn.hippo4j.config.verify.ConfigModificationVerifyServiceChoose;
import lombok.AllArgsConstructor;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
import java.util.List;
import java.util.Set;
@ -43,7 +41,7 @@ import static cn.hippo4j.common.constant.Constants.REGISTER_ADAPTER_BASE_PATH;
/**
* Thread-pool adapter controller.
*/
@AllArgsConstructor
@RequiredArgsConstructor
@RestController("threadPoolAdapterConsoleController")
public class ThreadPoolAdapterController {
@ -51,8 +49,6 @@ public class ThreadPoolAdapterController {
private final ConfigModificationVerifyServiceChoose configModificationVerifyServiceChoose;
private final RestTemplate restTemplate = new RestTemplate();
@GetMapping(REGISTER_ADAPTER_BASE_PATH + "/query")
public Result<List<ThreadPoolAdapterRespDTO>> queryAdapterThreadPool(ThreadPoolAdapterReqDTO requestParameter) {
List<ThreadPoolAdapterRespDTO> result = threadPoolAdapterService.query(requestParameter);
@ -69,12 +65,8 @@ public class ThreadPoolAdapterController {
public Result<Void> updateAdapterThreadPool(@RequestBody ThreadPoolAdapterReqDTO requestParameter) {
if (UserContext.getUserRole().equals("ROLE_ADMIN")) {
for (String each : requestParameter.getClientAddressList()) {
String urlString = new StringBuilder()
.append("http://")
.append(each)
.append("/adapter/thread-pool/update")
.toString();
restTemplate.postForObject(urlString, JSONUtil.toJSONString(requestParameter), Object.class);
String urlString = StringUtil.newBuilder("http://", each, "/adapter/thread-pool/update");
HttpUtil.post(urlString, requestParameter);
}
} else {
ConfigModifySaveReqDTO modifySaveReqDTO = BeanUtil.convert(requestParameter, ConfigModifySaveReqDTO.class);

@ -21,6 +21,7 @@ import cn.hippo4j.common.constant.ConfigModifyTypeConstants;
import cn.hippo4j.common.constant.Constants;
import cn.hippo4j.common.model.InstanceInfo;
import cn.hippo4j.common.toolkit.*;
import cn.hippo4j.common.toolkit.http.HttpUtil;
import cn.hippo4j.common.web.base.Result;
import cn.hippo4j.common.web.base.Results;
import cn.hippo4j.common.web.exception.ErrorCodeEnum;
@ -35,13 +36,11 @@ import cn.hippo4j.console.model.WebThreadPoolRespDTO;
import cn.hippo4j.discovery.core.BaseInstanceRegistry;
import cn.hippo4j.discovery.core.Lease;
import com.baomidou.mybatisplus.core.metadata.IPage;
import lombok.AllArgsConstructor;
import lombok.RequiredArgsConstructor;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.client.RestTemplate;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
@ -52,7 +51,7 @@ import static cn.hippo4j.common.toolkit.ContentUtil.getGroupKey;
* Thread pool controller.
*/
@RestController
@AllArgsConstructor
@RequiredArgsConstructor
@RequestMapping(Constants.BASE_PATH + "/thread/pool")
public class ThreadPoolController {
@ -62,7 +61,7 @@ public class ThreadPoolController {
private final ConfigModificationVerifyServiceChoose configModificationVerifyServiceChoose;
private final RestTemplate restTemplate = new RestTemplate();
private static final String HTTP = "http://";
@PostMapping("/query/page")
public Result<IPage<ThreadPoolRespDTO>> queryNameSpacePage(@RequestBody ThreadPoolQueryReqDTO reqDTO) {
@ -109,29 +108,15 @@ public class ThreadPoolController {
@GetMapping("/run/state/{tpId}")
public Result runState(@PathVariable("tpId") String tpId,
@RequestParam(value = "clientAddress") String clientAddress) {
String urlString = new StringBuilder()
.append("http://")
.append(clientAddress)
.append("/run/state/")
.append(tpId)
.toString();
String data = restTemplate.getForObject(urlString, String.class, new HashMap<>());
Result result = JSONUtil.parseObject(data, Result.class);
return result;
String urlString = StringUtil.newBuilder(HTTP, clientAddress, "/run/state/", tpId);
return HttpUtil.get(urlString, Result.class);
}
@GetMapping("/run/thread/state/{tpId}")
public Result runThreadState(@PathVariable("tpId") String tpId,
@RequestParam(value = "clientAddress") String clientAddress) {
String urlString = new StringBuilder()
.append("http://")
.append(clientAddress)
.append("/run/thread/state/")
.append(tpId)
.toString();
String data = restTemplate.getForObject(urlString, String.class, new HashMap<>());
Result result = JSONUtil.parseObject(data, Result.class);
return result;
String urlString = StringUtil.newBuilder(HTTP, clientAddress, "/run/thread/state/", tpId);
return HttpUtil.get(urlString, Result.class);
}
@GetMapping("/list/client/instance/{itemId}")
@ -166,38 +151,22 @@ public class ThreadPoolController {
@GetMapping("/web/base/info")
public Result getPoolBaseState(@RequestParam(value = "clientAddress") String clientAddress) {
String urlString = new StringBuilder()
.append("http://")
.append(clientAddress)
.append("/web/base/info")
.toString();
String data = restTemplate.getForObject(urlString, String.class, new HashMap<>());
Result result = JSONUtil.parseObject(data, Result.class);
return result;
String urlString = StringUtil.newBuilder(HTTP, clientAddress, "/web/base/info");
return HttpUtil.get(urlString, Result.class);
}
@GetMapping("/web/run/state")
public Result getPoolRunState(@RequestParam(value = "clientAddress") String clientAddress) {
String urlString = new StringBuilder()
.append("http://")
.append(clientAddress)
.append("/web/run/state")
.toString();
String data = restTemplate.getForObject(urlString, String.class, new HashMap<>());
Result result = JSONUtil.parseObject(data, Result.class);
return result;
String urlString = StringUtil.newBuilder(HTTP, clientAddress, "/web/run/state");
return HttpUtil.get(urlString, Result.class);
}
@PostMapping("/web/update/pool")
public Result<Void> updateWebThreadPool(@RequestBody WebThreadPoolReqDTO requestParam) {
if (UserContext.getUserRole().equals("ROLE_ADMIN")) {
for (String each : requestParam.getClientAddressList()) {
String urlString = new StringBuilder()
.append("http://")
.append(each)
.append("/web/update/pool")
.toString();
restTemplate.postForObject(urlString, JSONUtil.toJSONString(requestParam), Object.class);
String urlString = StringUtil.newBuilder(HTTP, each, "/web/update/pool");
HttpUtil.post(urlString, requestParam);
}
} else {
ConfigModifySaveReqDTO modifySaveReqDTO = BeanUtil.convert(requestParam, ConfigModifySaveReqDTO.class);
@ -238,5 +207,4 @@ public class ThreadPoolController {
});
return Results.success(returnThreadPool);
}
}

File diff suppressed because one or more lines are too long

@ -0,0 +1 @@
.waves-ripple{position:absolute;border-radius:100%;background-color:rgba(0,0,0,.15);background-clip:padding-box;pointer-events:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;-webkit-transform:scale(0);transform:scale(0);opacity:1}.waves-ripple.z-active{opacity:0;-webkit-transform:scale(2);transform:scale(2);-webkit-transition:opacity 1.2s ease-out,-webkit-transform .6s ease-out;transition:opacity 1.2s ease-out,-webkit-transform .6s ease-out;transition:opacity 1.2s ease-out,transform .6s ease-out;transition:opacity 1.2s ease-out,transform .6s ease-out,-webkit-transform .6s ease-out}.pagination-container[data-v-df7d1fa0]{background:#fff;padding:32px 16px}.pagination-container.hidden[data-v-df7d1fa0]{display:none}

@ -1 +1 @@
.social-signup-container[data-v-7309fbbb]{margin:20px 0}.social-signup-container .sign-btn[data-v-7309fbbb]{display:inline-block;cursor:pointer}.social-signup-container .icon[data-v-7309fbbb]{color:#fff;font-size:24px;margin-top:8px}.social-signup-container .qq-svg-container[data-v-7309fbbb],.social-signup-container .wx-svg-container[data-v-7309fbbb]{display:inline-block;width:40px;height:40px;line-height:40px;text-align:center;padding-top:1px;border-radius:4px;margin-bottom:20px;margin-right:5px}.social-signup-container .wx-svg-container[data-v-7309fbbb]{background-color:#24da70}.social-signup-container .qq-svg-container[data-v-7309fbbb]{background-color:#6ba2d6;margin-left:50px}@supports(-webkit-mask:none) and (not (cater-color:#fff)){.login-container .el-input input{color:#fff}}.login-container .el-input{display:inline-block;height:47px;width:85%}.login-container .el-input input{background:transparent;border:0;-webkit-appearance:none;border-radius:0;padding:12px 5px 12px 15px;color:#fff;height:47px;caret-color:#fff}.login-container .el-input input:-webkit-autofill{-webkit-box-shadow:0 0 0 1000px #283443 inset!important;box-shadow:inset 0 0 0 1000px #283443!important;-webkit-text-fill-color:#fff!important}.login-container .el-form-item{border:1px solid hsla(0,0%,100%,.1);background:rgba(0,0,0,.1);border-radius:5px;color:#454545}.login-container[data-v-3efc76dc]{min-height:100%;width:100%;background-color:#2d3a4b;overflow:hidden}.login-container .login-form[data-v-3efc76dc]{position:relative;width:520px;max-width:100%;padding:160px 35px 0;margin:0 auto;overflow:hidden}.login-container .tips[data-v-3efc76dc]{font-size:14px;color:#fff;margin-bottom:10px}.login-container .tips span[data-v-3efc76dc]:first-of-type{margin-right:16px}.login-container .svg-container[data-v-3efc76dc]{padding:6px 5px 6px 15px;color:#889aa4;vertical-align:middle;width:30px;display:inline-block}.login-container .title-container[data-v-3efc76dc]{position:relative}.login-container .title-container .title[data-v-3efc76dc]{font-size:26px;color:#eee;margin:0 auto 40px auto;text-align:center;font-weight:700}.login-container .show-pwd[data-v-3efc76dc]{position:absolute;right:10px;top:7px;font-size:16px;color:#889aa4;cursor:pointer;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.login-container .thirdparty-button[data-v-3efc76dc]{position:absolute;right:0;bottom:6px}@media only screen and (max-width:470px){.login-container .thirdparty-button[data-v-3efc76dc]{display:none}}
.social-signup-container[data-v-7309fbbb]{margin:20px 0}.social-signup-container .sign-btn[data-v-7309fbbb]{display:inline-block;cursor:pointer}.social-signup-container .icon[data-v-7309fbbb]{color:#fff;font-size:24px;margin-top:8px}.social-signup-container .qq-svg-container[data-v-7309fbbb],.social-signup-container .wx-svg-container[data-v-7309fbbb]{display:inline-block;width:40px;height:40px;line-height:40px;text-align:center;padding-top:1px;border-radius:4px;margin-bottom:20px;margin-right:5px}.social-signup-container .wx-svg-container[data-v-7309fbbb]{background-color:#24da70}.social-signup-container .qq-svg-container[data-v-7309fbbb]{background-color:#6ba2d6;margin-left:50px}@supports(-webkit-mask:none) and (not (cater-color:#fff)){.login-container .el-input input{color:#fff}}.login-container .el-input{display:inline-block;height:47px;width:85%}.login-container .el-input input{background:transparent;border:0;-webkit-appearance:none;border-radius:0;padding:12px 5px 12px 15px;color:#fff;height:47px;caret-color:#fff}.login-container .el-input input:-webkit-autofill{-webkit-box-shadow:0 0 0 1000px #283443 inset!important;box-shadow:inset 0 0 0 1000px #283443!important;-webkit-text-fill-color:#fff!important}.login-container .el-form-item{border:1px solid hsla(0,0%,100%,.1);background:rgba(0,0,0,.1);border-radius:5px;color:#454545}.login-container[data-v-13dcd441]{min-height:100%;width:100%;background-color:#2d3a4b;overflow:hidden}.login-container .login-form[data-v-13dcd441]{position:relative;width:520px;max-width:100%;padding:160px 35px 0;margin:0 auto;overflow:hidden}.login-container .tips[data-v-13dcd441]{font-size:14px;color:#fff;margin-bottom:10px}.login-container .tips span[data-v-13dcd441]:first-of-type{margin-right:16px}.login-container .svg-container[data-v-13dcd441]{padding:6px 5px 6px 15px;color:#889aa4;vertical-align:middle;width:30px;display:inline-block}.login-container .title-container[data-v-13dcd441]{position:relative}.login-container .title-container .title[data-v-13dcd441]{font-size:26px;color:#eee;margin:0 auto 40px auto;text-align:center;font-weight:700}.login-container .show-pwd[data-v-13dcd441]{position:absolute;right:10px;top:7px;font-size:16px;color:#889aa4;cursor:pointer;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.login-container .thirdparty-button[data-v-13dcd441]{position:absolute;right:0;bottom:6px}@media only screen and (max-width:470px){.login-container .thirdparty-button[data-v-13dcd441]{display:none}}

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

@ -14,18 +14,15 @@
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<dependency>
<groupId>cn.hippo4j</groupId>
<artifactId>hippo4j-common</artifactId>
<version>${revision}</version>
</dependency>
<dependency>
<groupId>cn.hippo4j</groupId>
<artifactId>hippo4j-message</artifactId>
</dependency>
<dependency>
<groupId>com.aliyun</groupId>
<artifactId>alibaba-dingtalk-service-sdk</artifactId>
@ -38,35 +35,4 @@
</exclusions>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<configuration>
<archive>
<manifestEntries>
<Implementation-Title>${project.artifactId}</Implementation-Title>
<Implementation-Version>${project.version}</Implementation-Version>
<Build-Time>${maven.build.timestamp}</Build-Time>
<Built-By>chen.ma</Built-By>
</manifestEntries>
</archive>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<version>2.10.3</version>
<executions>
<execution>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>

@ -23,7 +23,7 @@ import cn.hippo4j.core.executor.manage.GlobalNotifyAlarmManage;
import cn.hippo4j.core.executor.manage.GlobalThreadPoolManage;
import cn.hippo4j.core.executor.support.ThreadPoolBuilder;
import cn.hippo4j.core.toolkit.IdentifyUtil;
import cn.hippo4j.core.toolkit.TraceContextUtil;
import cn.hippo4j.core.toolkit.ExecutorTraceContextUtil;
import cn.hippo4j.message.service.Hippo4jSendMessageService;
import cn.hippo4j.message.enums.NotifyTypeEnum;
import cn.hippo4j.message.service.ThreadPoolNotifyAlarm;
@ -178,7 +178,7 @@ public class ThreadPoolNotifyAlarmHandler implements Runnable, CommandLineRunner
alarmNotifyRequest.setThreadPoolId(threadPoolId);
alarmNotifyRequest.setExecuteTime(executeTime);
alarmNotifyRequest.setExecuteTimeOut(executeTimeOut);
String executeTimeoutTrace = TraceContextUtil.getAndRemove();
String executeTimeoutTrace = ExecutorTraceContextUtil.getAndRemoveTimeoutTrace();
if (StringUtil.isNotBlank(executeTimeoutTrace)) {
alarmNotifyRequest.setExecuteTimeoutTrace(executeTimeoutTrace);
}

@ -24,7 +24,7 @@ import static cn.hippo4j.common.constant.Constants.EXECUTE_TIMEOUT_TRACE;
/**
* Trace context util.
*/
public class TraceContextUtil {
public class ExecutorTraceContextUtil {
/**
* Execute timeout trace key.
@ -36,12 +36,21 @@ public class TraceContextUtil {
*
* @return
*/
public static String getAndRemove() {
public static String getAndRemoveTimeoutTrace() {
String val = MDC.get(EXECUTE_TIMEOUT_TRACE_KEY);
MDC.remove(EXECUTE_TIMEOUT_TRACE_KEY);
return val;
}
/**
* Put execute timeout trace.
*
* @param trace
*/
public static void putExecuteTimeoutTrace(String trace) {
MDC.put(EXECUTE_TIMEOUT_TRACE, trace);
}
/**
* Set execute timeout trace key.
*

@ -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());

@ -18,25 +18,14 @@
<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>cn.hippo4j</groupId>
<artifactId>hippo4j-common</artifactId>
<version>${revision}</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>

@ -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>

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

Loading…
Cancel
Save