diff --git a/.run/ruoyi-auth.run.xml b/.run/ruoyi-auth.run.xml index 0b69031f..9c84b321 100644 --- a/.run/ruoyi-auth.run.xml +++ b/.run/ruoyi-auth.run.xml @@ -2,7 +2,7 @@ - diff --git a/.run/ruoyi-gateway.run.xml b/.run/ruoyi-gateway.run.xml index d399a727..b6e5ac04 100644 --- a/.run/ruoyi-gateway.run.xml +++ b/.run/ruoyi-gateway.run.xml @@ -2,7 +2,7 @@ - diff --git a/.run/ruoyi-gen.run.xml b/.run/ruoyi-gen.run.xml index d0dc0e67..abd6d2ff 100644 --- a/.run/ruoyi-gen.run.xml +++ b/.run/ruoyi-gen.run.xml @@ -2,7 +2,7 @@ - diff --git a/.run/ruoyi-job.run.xml b/.run/ruoyi-job.run.xml index 4fa17309..ead6cdae 100644 --- a/.run/ruoyi-job.run.xml +++ b/.run/ruoyi-job.run.xml @@ -2,7 +2,7 @@ - diff --git a/.run/ruoyi-monitor.run.xml b/.run/ruoyi-monitor.run.xml index 05292ec7..fc525a25 100644 --- a/.run/ruoyi-monitor.run.xml +++ b/.run/ruoyi-monitor.run.xml @@ -2,7 +2,7 @@ - diff --git a/.run/ruoyi-nacos.run.xml b/.run/ruoyi-nacos.run.xml index 3d8030ca..03e3f236 100644 --- a/.run/ruoyi-nacos.run.xml +++ b/.run/ruoyi-nacos.run.xml @@ -2,7 +2,7 @@ - diff --git a/.run/ruoyi-resource.run.xml b/.run/ruoyi-resource.run.xml index 5092e31a..79b1f4a9 100644 --- a/.run/ruoyi-resource.run.xml +++ b/.run/ruoyi-resource.run.xml @@ -2,7 +2,7 @@ - diff --git a/.run/ruoyi-seata-server.run.xml b/.run/ruoyi-seata-server.run.xml index 9765f397..dd9b15a2 100644 --- a/.run/ruoyi-seata-server.run.xml +++ b/.run/ruoyi-seata-server.run.xml @@ -2,7 +2,7 @@ - diff --git a/.run/ruoyi-sentinel-dashboard.run.xml b/.run/ruoyi-sentinel-dashboard.run.xml index fd0ca162..41c2f518 100644 --- a/.run/ruoyi-sentinel-dashboard.run.xml +++ b/.run/ruoyi-sentinel-dashboard.run.xml @@ -2,7 +2,7 @@ - diff --git a/.run/ruoyi-snailjob-server.run.xml b/.run/ruoyi-snailjob-server.run.xml index e2d7e440..dfeb8b06 100644 --- a/.run/ruoyi-snailjob-server.run.xml +++ b/.run/ruoyi-snailjob-server.run.xml @@ -2,7 +2,7 @@ - diff --git a/.run/ruoyi-system.run.xml b/.run/ruoyi-system.run.xml index a657faef..9c75c60e 100644 --- a/.run/ruoyi-system.run.xml +++ b/.run/ruoyi-system.run.xml @@ -2,7 +2,7 @@ - diff --git a/.run/ruoyi-workflow.run.xml b/.run/ruoyi-workflow.run.xml index 4d1d25c5..59435e9b 100644 --- a/.run/ruoyi-workflow.run.xml +++ b/.run/ruoyi-workflow.run.xml @@ -2,7 +2,7 @@ - diff --git a/README.md b/README.md index 406e0d61..bfb67c32 100644 --- a/README.md +++ b/README.md @@ -9,10 +9,10 @@ [![License](https://img.shields.io/badge/License-MIT-blue.svg)](https://gitee.com/dromara/RuoYi-Cloud-Plus/blob/master/LICENSE) [![使用IntelliJ IDEA开发维护](https://img.shields.io/badge/IntelliJ%20IDEA-提供支持-blue.svg)](https://www.jetbrains.com/?from=RuoYi-Cloud-Plus)
-[![RuoYi-Cloud-Plus](https://img.shields.io/badge/RuoYi_Cloud_Plus-2.2.0-success.svg)](https://gitee.com/dromara/RuoYi-Cloud-Plus) +[![RuoYi-Cloud-Plus](https://img.shields.io/badge/RuoYi_Cloud_Plus-2.2.1-success.svg)](https://gitee.com/dromara/RuoYi-Cloud-Plus) [![Spring Boot](https://img.shields.io/badge/Spring%20Boot-3.1-blue.svg)]() [![JDK-17](https://img.shields.io/badge/JDK-17-green.svg)]() -[![JDK-19](https://img.shields.io/badge/JDK-21-green.svg)]() +[![JDK-21](https://img.shields.io/badge/JDK-21-green.svg)]() > RuoYi-Cloud-Plus `微服务通用权限管理系统` 重写 RuoYi-Cloud 全方位升级(不兼容原框架) @@ -66,12 +66,14 @@ CCFlow 驰聘低代码-流程-表单 - https://gitee.com/opencc/RuoYi-JFlow
| 数据库连接池 | 采用 HikariCP Spring官方内置连接池 配置简单 以性能与稳定性闻名天下 | 采用 druid bug众多 社区维护差 活跃度低 配置众多繁琐性能一般 | | 数据库主键 | 采用 雪花ID 基于时间戳的 有序增长 唯一ID 再也不用为分库分表 数据合并主键冲突重复而发愁 | 采用 数据库自增ID 支持数据量有限 不支持多数据源主键唯一 | | WebSocket协议 | 基于 Spring 封装的 WebSocket 协议 扩展了Token鉴权与分布式会话同步 不再只是基于单机的废物 | 无 | +| SSE推送 | 采用 Spring SSE 实现 扩展了Token鉴权与分布式会话同步 | 无 | | 序列化 | 采用 Jackson Spring官方内置序列化 靠谱!!! | 采用 fastjson bugjson 远近闻名 | | 分布式幂等 | 参考美团GTIS防重系统简化实现(细节可看文档) | 手动编写注解基于aop实现 | | 分布式任务调度 | 采用 SnailJob 天生支持分布式 统一的管理中心 支持多种数据库 支持分片重试DAG任务流等 | 采用 Quartz 基于数据库锁性能差 集群需要做很多配置与改造 | | 分布式日志中心 | 采用 ELK 业界成熟解决方案 实时收集所有服务的运行日志 快速发现定位问题 | 无 | | 分布式搜索引擎 | 采用 ElasticSearch、Easy-Es 以 Mybatis-Plus 方式操作 ElasticSearch | 无 | | 分布式消息队列 | 采用 支持 Kafka、RocketMQ、RabbitMQ 各种 延迟消息 事务消息 流消息 | 无 | +| 分布式消息总线 | 采用 SpringCloud Bus 实现事件总线 跨服务通知 支持 Kafka、RocketMQ、RabbitMQ | 无 | | 分库分表功能 | 采用 Apache Sharding-Proxy 代理服务无入侵支持分库分表 只需编写分库分表规则即可 | 无 | | 文件存储 | 采用 Minio 分布式文件存储 天生支持多机、多硬盘、多分片、多副本存储
支持权限管理 安全可靠 文件可加密存储 | 采用 本机文件存储 文件裸漏 易丢失泄漏 不支持集群有单点效应 | | 云存储 | 采用 AWS S3 协议客户端 支持 七牛、阿里、腾讯 等一切支持S3协议的厂家 | 不支持 | @@ -80,6 +82,7 @@ CCFlow 驰聘低代码-流程-表单 - https://gitee.com/opencc/RuoYi-JFlow
| 接口文档 | 采用 SpringDoc、javadoc 无注解零入侵基于java注释
只需把注释写好 无需再写一大堆的文档注解了 | 采用 Springfox 已停止维护 需要编写大量的注解来支持文档生成 | | 校验框架 | 采用 Validation 支持注解与工具类校验 注解支持国际化 | 仅支持注解 且注解不支持国际化 | | Excel框架 | 采用 Alibaba EasyExcel 基于插件化
框架对其增加了很多功能 例如 自动合并相同内容 自动排列布局 字典翻译等 | 基于 POI 手写实现 功能有限 复杂 扩展性差 | +| 工作流支持 | 支持各种复杂审批 转办 委派 加减签 会签 或签 票签 等功能 | 无 | | 工具类框架 | 采用 Hutool、Lombok 上百种工具覆盖90%的使用需求 基于注解自动生成 get set 等简化框架大量代码 | 手写工具稳定性差易出问题 工具数量有限 代码臃肿需自己手写 get set 等 | | 服务监控框架 | 采用 SpringBoot-Admin 基于SpringBoot官方 actuator 探针机制
实时监控服务状态 框架还为其扩展了在线日志查看监控 | 无 | | 全方位监控报警 | 采用 Prometheus、Grafana 多样化采集 多模板大屏展示 实时报警监控 提供详细的搭建文档 | 无 | diff --git a/config/nacos/application-common.yml b/config/nacos/application-common.yml index e60c9d3e..17b26aec 100644 --- a/config/nacos/application-common.yml +++ b/config/nacos/application-common.yml @@ -70,12 +70,16 @@ spring: # 允许对象忽略json中不存在的属性 fail_on_unknown_properties: false cloud: + nacos: + discovery: + metadata: + # admin 监控账号密码 + username: ruoyi + userpassword: 123456 # sentinel 配置 sentinel: # sentinel 开关 enabled: true - # 取消控制台懒加载 - eager: true transport: # dashboard控制台服务名 用于服务发现 # 如无此配置将默认使用下方 dashboard 配置直接注册 @@ -103,7 +107,8 @@ spring: # redis 密码必须配置 password: ruoyi123 database: 0 - timeout: 10s + # 需要使用数字 + timeout: 10000 ssl.enabled: false # redisson 配置 @@ -154,6 +159,7 @@ logging: org.springframework: warn org.apache.dubbo: warn com.alibaba.nacos: warn + com.alibaba.cloud.sentinel: warn org.mybatis.spring.mapper: error org.apache.dubbo.config: error # 临时处理 spring 调整日志级别导致启动警告问题 不影响使用等待 alibaba 适配 diff --git a/config/nacos/ruoyi-gateway.yml b/config/nacos/ruoyi-gateway.yml index b51856f7..60657ae0 100644 --- a/config/nacos/ruoyi-gateway.yml +++ b/config/nacos/ruoyi-gateway.yml @@ -18,6 +18,7 @@ security: - /auth/register - /auth/tenant/list - /resource/sms/code + - /resource/sse/close - /*/v3/api-docs - /*/error - /csrf diff --git a/config/nacos/ruoyi-resource.yml b/config/nacos/ruoyi-resource.yml index 9c539725..0352230f 100644 --- a/config/nacos/ruoyi-resource.yml +++ b/config/nacos/ruoyi-resource.yml @@ -24,9 +24,14 @@ spring: # username: ${datasource.system-postgres.username} # password: ${datasource.system-postgres.password} +# 默认/推荐使用sse推送 +sse: + enabled: true + path: /sse + websocket: # 如果关闭 需要和前端开关一起关闭 - enabled: true + enabled: false # 路径 path: /websocket # 设置访问源地址 diff --git a/config/nacos/ruoyi-snailjob-server.yml b/config/nacos/ruoyi-snailjob-server.yml index 4440fc4f..cc9c1ed8 100644 --- a/config/nacos/ruoyi-snailjob-server.yml +++ b/config/nacos/ruoyi-snailjob-server.yml @@ -13,6 +13,15 @@ spring: idle-timeout: 600000 max-lifetime: 900000 keepaliveTime: 30000 + cloud: + nacos: + discovery: + metadata: + # 解决 er 服务有 context-path 无法监控问题 + management.context-path: ${server.servlet.context-path}/actuator + # 监控账号密码 + username: ruoyi + userpassword: 123456 # snail-job 服务端配置 snail-job: diff --git a/config/nacos/ruoyi-workflow.yml b/config/nacos/ruoyi-workflow.yml index 51cf2a6a..5933ebc3 100644 --- a/config/nacos/ruoyi-workflow.yml +++ b/config/nacos/ruoyi-workflow.yml @@ -26,6 +26,10 @@ spring: # flowable配置 flowable: + # 开关 用于启动/停用工作流 + enabled: true + process.enabled: ${flowable.enabled} + eventregistry.enabled: ${flowable.enabled} # 关闭定时任务JOB async-executor-activate: false # 将databaseSchemaUpdate设置为true。当Flowable发现库与数据库表结构不一致时,会自动将数据库表结构升级至新版本。 diff --git a/docker/docker-compose.yml b/docker/docker-compose.yml index 66bc2dd6..21b86c01 100644 --- a/docker/docker-compose.yml +++ b/docker/docker-compose.yml @@ -2,7 +2,7 @@ version: '3' services: mysql: - image: mysql:8.0.31 + image: mysql:8.0.33 container_name: mysql environment: # 时区上海 @@ -29,7 +29,7 @@ services: network_mode: "host" nacos: - image: ruoyi/ruoyi-nacos:2.2.0 + image: ruoyi/ruoyi-nacos:2.2.1 container_name: nacos ports: - "8848:8848" @@ -96,7 +96,7 @@ services: network_mode: "host" seata-server: - image: ruoyi/ruoyi-seata-server:2.2.0 + image: ruoyi/ruoyi-seata-server:2.2.1 container_name: seata-server ports: - "7091:7091" @@ -135,7 +135,7 @@ services: network_mode: "host" sentinel: - image: ruoyi/ruoyi-sentinel-dashboard:2.2.0 + image: ruoyi/ruoyi-sentinel-dashboard:2.2.1 container_name: sentinel environment: TZ: Asia/Shanghai @@ -150,7 +150,7 @@ services: network_mode: "host" ruoyi-monitor: - image: ruoyi/ruoyi-monitor:2.2.0 + image: ruoyi/ruoyi-monitor:2.2.1 container_name: ruoyi-monitor environment: # 时区上海 @@ -166,7 +166,7 @@ services: network_mode: "host" ruoyi-snailjob-server: - image: ruoyi/ruoyi-snailjob-server:2.2.0 + image: ruoyi/ruoyi-snailjob-server:2.2.1 container_name: ruoyi-snailjob-server environment: # 时区上海 @@ -180,7 +180,7 @@ services: network_mode: "host" ruoyi-gateway: - image: ruoyi/ruoyi-gateway:2.2.0 + image: ruoyi/ruoyi-gateway:2.2.1 container_name: ruoyi-gateway environment: # 时区上海 @@ -196,7 +196,7 @@ services: network_mode: "host" ruoyi-auth: - image: ruoyi/ruoyi-auth:2.2.0 + image: ruoyi/ruoyi-auth:2.2.1 container_name: ruoyi-auth environment: # 时区上海 @@ -212,7 +212,7 @@ services: network_mode: "host" ruoyi-system: - image: ruoyi/ruoyi-system:2.2.0 + image: ruoyi/ruoyi-system:2.2.1 container_name: ruoyi-system environment: # 时区上海 @@ -228,7 +228,7 @@ services: network_mode: "host" ruoyi-gen: - image: ruoyi/ruoyi-gen:2.2.0 + image: ruoyi/ruoyi-gen:2.2.1 container_name: ruoyi-gen environment: # 时区上海 @@ -244,7 +244,7 @@ services: network_mode: "host" ruoyi-job: - image: ruoyi/ruoyi-job:2.2.0 + image: ruoyi/ruoyi-job:2.2.1 container_name: ruoyi-job environment: # 时区上海 @@ -260,7 +260,7 @@ services: network_mode: "host" ruoyi-resource: - image: ruoyi/ruoyi-resource:2.2.0 + image: ruoyi/ruoyi-resource:2.2.1 container_name: ruoyi-resource environment: # 时区上海 @@ -276,7 +276,7 @@ services: network_mode: "host" ruoyi-workflow: - image: ruoyi/ruoyi-workflow:2.2.0 + image: ruoyi/ruoyi-workflow:2.2.1 container_name: ruoyi-workflow environment: # 时区上海 diff --git a/docker/nginx/conf/nginx.conf b/docker/nginx/conf/nginx.conf index ed01e597..6d837c4e 100644 --- a/docker/nginx/conf/nginx.conf +++ b/docker/nginx/conf/nginx.conf @@ -71,10 +71,13 @@ http { proxy_set_header X-Real-IP $remote_addr; proxy_set_header REMOTE-HOST $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; - # websocket参数 + proxy_read_timeout 86400s; + # sse 与 websocket参数 proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; + proxy_buffering off; + proxy_cache off; proxy_pass http://server/; } diff --git a/docker/skywalking/agent/config/agent.config b/docker/skywalking/agent/config/agent.config index 45b09a35..4c9f72fe 100644 --- a/docker/skywalking/agent/config/agent.config +++ b/docker/skywalking/agent/config/agent.config @@ -68,7 +68,7 @@ agent.force_reconnection_period=${SW_AGENT_FORCE_RECONNECTION_PERIOD:1} agent.operation_name_threshold=${SW_AGENT_OPERATION_NAME_THRESHOLD:150} # Keep tracing even the backend is not available if this value is true. -agent.keep_tracing=${SW_AGENT_KEEP_TRACING:false} +agent.keep_tracing=${SW_AGENT_KEEP_TRACING:true} # The agent use gRPC plain text in default. # If true, SkyWalking agent uses TLS even no CA file detected. diff --git a/docker/skywalking/agent/plugins/apm-httpClient-4.x-plugin-9.2.0.jar b/docker/skywalking/agent/plugins/apm-httpClient-4.x-plugin-9.2.0.jar index e69de29b..d9e7895b 100644 Binary files a/docker/skywalking/agent/plugins/apm-httpClient-4.x-plugin-9.2.0.jar and b/docker/skywalking/agent/plugins/apm-httpClient-4.x-plugin-9.2.0.jar differ diff --git a/pom.xml b/pom.xml index 3ba38fce..9c4bdf90 100644 --- a/pom.xml +++ b/pom.xml @@ -13,40 +13,39 @@ RuoYi-Cloud-Plus微服务系统 - 2.2.0 + 2.2.1 UTF-8 UTF-8 17 - 3.2.6 - 2023.0.2 + 3.2.9 + 2023.0.3 3.2.3 3.5.16 3.5.7 3.9.1 4.3.1 2.3 - 2.2.21 - 2.5.0 + 2.2.22 + 2.6.0 0.15.0 - 5.2.3 - 3.3.4 - 5.8.27 - 3.31.0 + 4.0.2 + 5.8.31 + 3.34.1 2.2.7 - 1.0.1 + 1.1.2 1.38.0 - 1.18.32 + 1.18.34 7.4 2.0.0 7.14.0 9.2.0 1.76 - 2.14.4 - 1.3.6 + 1.4.4 0.2.0 1.16.6 2.7.0 + 2.3.15.Final 1.2.83 @@ -56,9 +55,11 @@ 4.10.0 - 3.2.1 + 3.3.2 + + 8.7.2-20240808 - 7.0.0 + 7.0.1 2.3.0 @@ -233,26 +234,10 @@ ${lombok.version} - - org.apache.poi - poi - ${poi.version} - - - org.apache.poi - poi-ooxml - ${poi.version} - com.alibaba easyexcel ${easyexcel.version} - - - org.apache.poi - poi-ooxml-schemas - - @@ -368,6 +353,28 @@ ${ip2region.version} + + io.undertow + undertow-core + ${undertow.version} + + + io.undertow + undertow-servlet + ${undertow.version} + + + io.undertow + undertow-websockets-jsr + ${undertow.version} + + + + commons-compress + org.apache.commons + 1.26.2 + + com.alibaba fastjson @@ -381,12 +388,6 @@ 5.1.0 - - com.alibaba - transmittable-thread-local - ${alibaba-ttl.version} - - io.github.linpeilie mapstruct-plus-spring-boot-starter diff --git a/ruoyi-api/ruoyi-api-bom/pom.xml b/ruoyi-api/ruoyi-api-bom/pom.xml index 8bdae831..26889bed 100644 --- a/ruoyi-api/ruoyi-api-bom/pom.xml +++ b/ruoyi-api/ruoyi-api-bom/pom.xml @@ -15,7 +15,7 @@ - 2.2.0 + 2.2.1 diff --git a/ruoyi-auth/src/main/java/org/dromara/auth/controller/CaptchaController.java b/ruoyi-auth/src/main/java/org/dromara/auth/controller/CaptchaController.java index 1537cb5f..82931278 100644 --- a/ruoyi-auth/src/main/java/org/dromara/auth/controller/CaptchaController.java +++ b/ruoyi-auth/src/main/java/org/dromara/auth/controller/CaptchaController.java @@ -1,6 +1,5 @@ package org.dromara.auth.controller; -import cn.dev33.satoken.annotation.SaIgnore; import cn.hutool.captcha.AbstractCaptcha; import cn.hutool.captcha.generator.CodeGenerator; import cn.hutool.core.util.IdUtil; @@ -32,7 +31,6 @@ import java.time.Duration; * * @author Lion Li */ -@SaIgnore @Slf4j @Validated @RequiredArgsConstructor diff --git a/ruoyi-auth/src/main/java/org/dromara/auth/listener/UserActionListener.java b/ruoyi-auth/src/main/java/org/dromara/auth/listener/UserActionListener.java index c4a1a0e1..60acd9df 100644 --- a/ruoyi-auth/src/main/java/org/dromara/auth/listener/UserActionListener.java +++ b/ruoyi-auth/src/main/java/org/dromara/auth/listener/UserActionListener.java @@ -3,6 +3,8 @@ package org.dromara.auth.listener; import cn.dev33.satoken.config.SaTokenConfig; import cn.dev33.satoken.listener.SaTokenListener; import cn.dev33.satoken.stp.SaLoginModel; +import cn.dev33.satoken.stp.StpUtil; +import cn.hutool.core.convert.Convert; import cn.hutool.http.useragent.UserAgent; import cn.hutool.http.useragent.UserAgentUtil; import lombok.RequiredArgsConstructor; @@ -85,7 +87,10 @@ public class UserActionListener implements SaTokenListener { */ @Override public void doLogout(String loginType, Object loginId, String tokenValue) { - RedisUtils.deleteObject(CacheConstants.ONLINE_TOKEN_KEY + tokenValue); + String tenantId = Convert.toStr(StpUtil.getExtra(tokenValue, LoginHelper.TENANT_KEY)); + TenantHelper.dynamic(tenantId, () -> { + RedisUtils.deleteObject(CacheConstants.ONLINE_TOKEN_KEY + tokenValue); + }); log.info("user doLogout, useId:{}, token:{}", loginId, tokenValue); } @@ -94,7 +99,10 @@ public class UserActionListener implements SaTokenListener { */ @Override public void doKickout(String loginType, Object loginId, String tokenValue) { - RedisUtils.deleteObject(CacheConstants.ONLINE_TOKEN_KEY + tokenValue); + String tenantId = Convert.toStr(StpUtil.getExtra(tokenValue, LoginHelper.TENANT_KEY)); + TenantHelper.dynamic(tenantId, () -> { + RedisUtils.deleteObject(CacheConstants.ONLINE_TOKEN_KEY + tokenValue); + }); log.info("user doLogoutByLoginId, useId:{}, token:{}", loginId, tokenValue); } @@ -103,7 +111,10 @@ public class UserActionListener implements SaTokenListener { */ @Override public void doReplaced(String loginType, Object loginId, String tokenValue) { - RedisUtils.deleteObject(CacheConstants.ONLINE_TOKEN_KEY + tokenValue); + String tenantId = Convert.toStr(StpUtil.getExtra(tokenValue, LoginHelper.TENANT_KEY)); + TenantHelper.dynamic(tenantId, () -> { + RedisUtils.deleteObject(CacheConstants.ONLINE_TOKEN_KEY + tokenValue); + }); log.info("user doReplaced, useId:{}, token:{}", loginId, tokenValue); } diff --git a/ruoyi-auth/src/main/java/org/dromara/auth/service/SysLoginService.java b/ruoyi-auth/src/main/java/org/dromara/auth/service/SysLoginService.java index eacdc01b..d50ce975 100644 --- a/ruoyi-auth/src/main/java/org/dromara/auth/service/SysLoginService.java +++ b/ruoyi-auth/src/main/java/org/dromara/auth/service/SysLoginService.java @@ -14,6 +14,7 @@ import org.apache.dubbo.config.annotation.DubboReference; import org.dromara.auth.form.RegisterBody; import org.dromara.auth.properties.CaptchaProperties; import org.dromara.auth.properties.UserPasswordProperties; +import org.dromara.common.core.constant.CacheConstants; import org.dromara.common.core.constant.Constants; import org.dromara.common.core.constant.GlobalConstants; import org.dromara.common.core.constant.TenantConstants; @@ -205,7 +206,7 @@ public class SysLoginService { * 登录校验 */ public void checkLogin(LoginType loginType, String tenantId, String username, Supplier supplier) { - String errorKey = GlobalConstants.PWD_ERR_CNT_KEY + username; + String errorKey = CacheConstants.PWD_ERR_CNT_KEY + username; String loginFail = Constants.LOGIN_FAIL; Integer maxRetryCount = userPasswordProperties.getMaxRetryCount(); Integer lockTime = userPasswordProperties.getLockTime(); diff --git a/ruoyi-auth/src/main/java/org/dromara/auth/service/impl/EmailAuthStrategy.java b/ruoyi-auth/src/main/java/org/dromara/auth/service/impl/EmailAuthStrategy.java index 8790fe13..a9f6d351 100644 --- a/ruoyi-auth/src/main/java/org/dromara/auth/service/impl/EmailAuthStrategy.java +++ b/ruoyi-auth/src/main/java/org/dromara/auth/service/impl/EmailAuthStrategy.java @@ -19,6 +19,7 @@ import org.dromara.common.core.utils.ValidatorUtils; import org.dromara.common.json.utils.JsonUtils; import org.dromara.common.redis.utils.RedisUtils; import org.dromara.common.satoken.utils.LoginHelper; +import org.dromara.common.tenant.helper.TenantHelper; import org.dromara.system.api.RemoteUserService; import org.dromara.system.api.domain.vo.RemoteClientVo; import org.dromara.system.api.model.LoginUser; @@ -46,10 +47,11 @@ public class EmailAuthStrategy implements IAuthStrategy { String tenantId = loginBody.getTenantId(); String email = loginBody.getEmail(); String emailCode = loginBody.getEmailCode(); - - // 通过邮箱查找用户 - LoginUser loginUser = remoteUserService.getUserInfoByEmail(email, tenantId); - loginService.checkLogin(LoginType.EMAIL, tenantId, loginUser.getUsername(), () -> !validateEmailCode(tenantId, email, emailCode)); + LoginUser loginUser = TenantHelper.dynamic(tenantId, () -> { + LoginUser user = remoteUserService.getUserInfoByEmail(email, tenantId); + loginService.checkLogin(LoginType.EMAIL, tenantId, user.getUsername(), () -> !validateEmailCode(tenantId, email, emailCode)); + return user; + }); loginUser.setClientKey(client.getClientKey()); loginUser.setDeviceType(client.getDeviceType()); SaLoginModel model = new SaLoginModel(); diff --git a/ruoyi-auth/src/main/java/org/dromara/auth/service/impl/PasswordAuthStrategy.java b/ruoyi-auth/src/main/java/org/dromara/auth/service/impl/PasswordAuthStrategy.java index db4ea945..0071ea4e 100644 --- a/ruoyi-auth/src/main/java/org/dromara/auth/service/impl/PasswordAuthStrategy.java +++ b/ruoyi-auth/src/main/java/org/dromara/auth/service/impl/PasswordAuthStrategy.java @@ -22,6 +22,7 @@ import org.dromara.common.core.utils.ValidatorUtils; import org.dromara.common.json.utils.JsonUtils; import org.dromara.common.redis.utils.RedisUtils; import org.dromara.common.satoken.utils.LoginHelper; +import org.dromara.common.tenant.helper.TenantHelper; import org.dromara.system.api.RemoteUserService; import org.dromara.system.api.domain.vo.RemoteClientVo; import org.dromara.system.api.model.LoginUser; @@ -58,9 +59,11 @@ public class PasswordAuthStrategy implements IAuthStrategy { if (captchaProperties.getEnabled()) { validateCaptcha(tenantId, username, code, uuid); } - - LoginUser loginUser = remoteUserService.getUserInfo(username, tenantId); - loginService.checkLogin(LoginType.PASSWORD, tenantId, username, () -> !BCrypt.checkpw(password, loginUser.getPassword())); + LoginUser loginUser = TenantHelper.dynamic(tenantId, () -> { + LoginUser user = remoteUserService.getUserInfo(username, tenantId); + loginService.checkLogin(LoginType.PASSWORD, tenantId, username, () -> !BCrypt.checkpw(password, user.getPassword())); + return user; + }); loginUser.setClientKey(client.getClientKey()); loginUser.setDeviceType(client.getDeviceType()); SaLoginModel model = new SaLoginModel(); diff --git a/ruoyi-auth/src/main/java/org/dromara/auth/service/impl/SmsAuthStrategy.java b/ruoyi-auth/src/main/java/org/dromara/auth/service/impl/SmsAuthStrategy.java index d32b5aa1..899cafcc 100644 --- a/ruoyi-auth/src/main/java/org/dromara/auth/service/impl/SmsAuthStrategy.java +++ b/ruoyi-auth/src/main/java/org/dromara/auth/service/impl/SmsAuthStrategy.java @@ -19,6 +19,7 @@ import org.dromara.common.core.utils.ValidatorUtils; import org.dromara.common.json.utils.JsonUtils; import org.dromara.common.redis.utils.RedisUtils; import org.dromara.common.satoken.utils.LoginHelper; +import org.dromara.common.tenant.helper.TenantHelper; import org.dromara.system.api.RemoteUserService; import org.dromara.system.api.domain.vo.RemoteClientVo; import org.dromara.system.api.model.LoginUser; @@ -46,10 +47,11 @@ public class SmsAuthStrategy implements IAuthStrategy { String tenantId = loginBody.getTenantId(); String phonenumber = loginBody.getPhonenumber(); String smsCode = loginBody.getSmsCode(); - - // 通过手机号查找用户 - LoginUser loginUser = remoteUserService.getUserInfoByPhonenumber(phonenumber, tenantId); - loginService.checkLogin(LoginType.SMS, tenantId, loginUser.getUsername(), () -> !validateSmsCode(tenantId, phonenumber, smsCode)); + LoginUser loginUser = TenantHelper.dynamic(tenantId, () -> { + LoginUser user = remoteUserService.getUserInfoByPhonenumber(phonenumber, tenantId); + loginService.checkLogin(LoginType.SMS, tenantId, user.getUsername(), () -> !validateSmsCode(tenantId, phonenumber, smsCode)); + return user; + }); loginUser.setClientKey(client.getClientKey()); loginUser.setDeviceType(client.getDeviceType()); SaLoginModel model = new SaLoginModel(); diff --git a/ruoyi-common/pom.xml b/ruoyi-common/pom.xml index ff6f5581..48e00955 100644 --- a/ruoyi-common/pom.xml +++ b/ruoyi-common/pom.xml @@ -44,6 +44,7 @@ ruoyi-common-social ruoyi-common-nacos ruoyi-common-bus + ruoyi-common-sse ruoyi-common diff --git a/ruoyi-common/ruoyi-common-alibaba-bom/pom.xml b/ruoyi-common/ruoyi-common-alibaba-bom/pom.xml index e2f4f110..561e2f1b 100644 --- a/ruoyi-common/ruoyi-common-alibaba-bom/pom.xml +++ b/ruoyi-common/ruoyi-common-alibaba-bom/pom.xml @@ -14,8 +14,8 @@ - 2.2.0 - 2023.0.1.0 + 2.2.1 + 2023.0.1.2 1.8.8 1.7.1 2.3.3 @@ -123,7 +123,7 @@ com.alibaba.csp - sentinel-spring-webmvc-adapter + sentinel-spring-webmvc-v6x-adapter ${sentinel.version} diff --git a/ruoyi-common/ruoyi-common-bom/pom.xml b/ruoyi-common/ruoyi-common-bom/pom.xml index dcafd753..8a096cd6 100644 --- a/ruoyi-common/ruoyi-common-bom/pom.xml +++ b/ruoyi-common/ruoyi-common-bom/pom.xml @@ -14,7 +14,7 @@ - 2.2.0 + 2.2.1 @@ -250,6 +250,13 @@ ${revision} + + + org.dromara + ruoyi-common-sse + ${revision} + + diff --git a/ruoyi-common/ruoyi-common-core/pom.xml b/ruoyi-common/ruoyi-common-core/pom.xml index 84ab453a..01d876e7 100644 --- a/ruoyi-common/ruoyi-common-core/pom.xml +++ b/ruoyi-common/ruoyi-common-core/pom.xml @@ -99,11 +99,6 @@ ip2region - - com.alibaba - transmittable-thread-local - - diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/constant/CacheConstants.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/constant/CacheConstants.java index 67bc8e4c..ceb83704 100644 --- a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/constant/CacheConstants.java +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/constant/CacheConstants.java @@ -22,4 +22,9 @@ public interface CacheConstants { */ String SYS_DICT_KEY = "sys_dict:"; + /** + * 登录账户密码错误次数 redis key + */ + String PWD_ERR_CNT_KEY = "pwd_err_cnt:"; + } diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/constant/GlobalConstants.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/constant/GlobalConstants.java index 8e5a6eb9..73f62a39 100644 --- a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/constant/GlobalConstants.java +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/constant/GlobalConstants.java @@ -27,11 +27,6 @@ public interface GlobalConstants { */ String RATE_LIMIT_KEY = GLOBAL_REDIS_KEY + "rate_limit:"; - /** - * 登录账户密码错误次数 redis key - */ - String PWD_ERR_CNT_KEY = GLOBAL_REDIS_KEY + "pwd_err_cnt:"; - /** * 三方认证 redis key */ diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/constant/UserConstants.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/constant/UserConstants.java index 6f3b0b96..76f6dd4a 100644 --- a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/constant/UserConstants.java +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/constant/UserConstants.java @@ -67,6 +67,16 @@ public interface UserConstants { */ String DICT_NORMAL = "0"; + /** + * 通用存在标志 + */ + String DEL_FLAG_NORMAL = "0"; + + /** + * 通用删除标志 + */ + String DEL_FLAG_REMOVED = "2"; + /** * 是否为系统默认(是) */ diff --git a/ruoyi-common/ruoyi-common-dubbo/src/main/java/org/apache/dubbo/metadata/store/redis/RedisMetadataReport.java b/ruoyi-common/ruoyi-common-dubbo/src/main/java/org/apache/dubbo/metadata/store/redis/RedisMetadataReport.java index b2bb4186..9d6af3af 100644 --- a/ruoyi-common/ruoyi-common-dubbo/src/main/java/org/apache/dubbo/metadata/store/redis/RedisMetadataReport.java +++ b/ruoyi-common/ruoyi-common-dubbo/src/main/java/org/apache/dubbo/metadata/store/redis/RedisMetadataReport.java @@ -16,52 +16,27 @@ */ package org.apache.dubbo.metadata.store.redis; +import org.apache.commons.pool2.impl.GenericObjectPoolConfig; import org.apache.dubbo.common.URL; import org.apache.dubbo.common.config.configcenter.ConfigItem; import org.apache.dubbo.common.logger.ErrorTypeAwareLogger; import org.apache.dubbo.common.logger.LoggerFactory; -import org.apache.dubbo.common.utils.ConcurrentHashMapUtils; -import org.apache.dubbo.common.utils.ConcurrentHashSet; -import org.apache.dubbo.common.utils.JsonUtils; -import org.apache.dubbo.common.utils.StringUtils; +import org.apache.dubbo.common.utils.*; import org.apache.dubbo.metadata.MappingChangedEvent; import org.apache.dubbo.metadata.MappingListener; import org.apache.dubbo.metadata.MetadataInfo; import org.apache.dubbo.metadata.ServiceNameMapping; -import org.apache.dubbo.metadata.report.identifier.BaseMetadataIdentifier; -import org.apache.dubbo.metadata.report.identifier.KeyTypeEnum; -import org.apache.dubbo.metadata.report.identifier.MetadataIdentifier; -import org.apache.dubbo.metadata.report.identifier.ServiceMetadataIdentifier; -import org.apache.dubbo.metadata.report.identifier.SubscriberMetadataIdentifier; +import org.apache.dubbo.metadata.report.identifier.*; import org.apache.dubbo.metadata.report.support.AbstractMetadataReport; import org.apache.dubbo.rpc.RpcException; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.concurrent.ConcurrentHashMap; - -import org.apache.commons.pool2.impl.GenericObjectPoolConfig; -import redis.clients.jedis.HostAndPort; -import redis.clients.jedis.Jedis; -import redis.clients.jedis.JedisCluster; -import redis.clients.jedis.JedisPool; -import redis.clients.jedis.JedisPoolConfig; -import redis.clients.jedis.JedisPubSub; -import redis.clients.jedis.Transaction; +import redis.clients.jedis.*; import redis.clients.jedis.params.SetParams; import redis.clients.jedis.util.JedisClusterCRC16; -import static org.apache.dubbo.common.constants.CommonConstants.CLUSTER_KEY; -import static org.apache.dubbo.common.constants.CommonConstants.CYCLE_REPORT_KEY; -import static org.apache.dubbo.common.constants.CommonConstants.DEFAULT_TIMEOUT; -import static org.apache.dubbo.common.constants.CommonConstants.GROUP_CHAR_SEPARATOR; -import static org.apache.dubbo.common.constants.CommonConstants.QUEUES_KEY; -import static org.apache.dubbo.common.constants.CommonConstants.TIMEOUT_KEY; +import java.util.*; +import java.util.concurrent.ConcurrentHashMap; + +import static org.apache.dubbo.common.constants.CommonConstants.*; import static org.apache.dubbo.common.constants.LoggerCodeConstants.TRANSPORT_FAILED_RESPONSE; import static org.apache.dubbo.metadata.MetadataConstants.META_DATA_STORE_TAG; import static org.apache.dubbo.metadata.ServiceNameMapping.DEFAULT_MAPPING_GROUP; @@ -479,7 +454,7 @@ public class RedisMetadataReport extends AbstractMetadataReport { logger.info("sub from redis:" + key + " message:" + msg); String applicationNames = getMappingData(buildMappingKey(DEFAULT_MAPPING_GROUP), msg); MappingChangedEvent mappingChangedEvent = new MappingChangedEvent(msg, getAppNames(applicationNames)); - if (!listeners.get(msg).isEmpty()) { + if (!CollectionUtils.isEmpty(listeners.get(msg))) { for (MappingListener mappingListener : listeners.get(msg)) { mappingListener.onEvent(mappingChangedEvent); } diff --git a/ruoyi-common/ruoyi-common-dubbo/src/main/java/org/dromara/common/dubbo/config/CustomBeanFactoryPostProcessor.java b/ruoyi-common/ruoyi-common-dubbo/src/main/java/org/dromara/common/dubbo/config/CustomBeanFactoryPostProcessor.java index ef28564d..40ad3a2e 100644 --- a/ruoyi-common/ruoyi-common-dubbo/src/main/java/org/dromara/common/dubbo/config/CustomBeanFactoryPostProcessor.java +++ b/ruoyi-common/ruoyi-common-dubbo/src/main/java/org/dromara/common/dubbo/config/CustomBeanFactoryPostProcessor.java @@ -1,5 +1,6 @@ package org.dromara.common.dubbo.config; +import org.dromara.common.core.utils.StringUtils; import org.springframework.beans.BeansException; import org.springframework.beans.factory.config.BeanFactoryPostProcessor; import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; @@ -34,6 +35,10 @@ public class CustomBeanFactoryPostProcessor implements BeanFactoryPostProcessor, */ @Override public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException { + String property = System.getProperty("DUBBO_IP_TO_REGISTRY"); + if (StringUtils.isNotBlank(property)) { + return; + } // 获取 InetUtils bean,用于获取 IP 地址 InetUtils inetUtils = beanFactory.getBean(InetUtils.class); String ip = "127.0.0.1"; diff --git a/ruoyi-common/ruoyi-common-dubbo/src/main/java/org/dromara/common/dubbo/filter/DubboRequestFilter.java b/ruoyi-common/ruoyi-common-dubbo/src/main/java/org/dromara/common/dubbo/filter/DubboRequestFilter.java index 273155e2..5e74c65d 100644 --- a/ruoyi-common/ruoyi-common-dubbo/src/main/java/org/dromara/common/dubbo/filter/DubboRequestFilter.java +++ b/ruoyi-common/ruoyi-common-dubbo/src/main/java/org/dromara/common/dubbo/filter/DubboRequestFilter.java @@ -67,8 +67,8 @@ public class DubboRequestFilter implements Filter { Result result = invoker.invoke(invocation); // 计算调用耗时 long elapsed = System.currentTimeMillis() - startTime; - // 如果发生异常且调用的是泛化服务,则记录异常日志 - if (result.hasException() && invoker.getInterface().equals(GenericService.class)) { + // 如果发生异常且调用的不是泛化服务,则记录异常日志 + if (result.hasException() && !invoker.getInterface().equals(GenericService.class)) { log.error("DUBBO - 服务异常: {},Exception={}", baselog, result.getException()); } else { // 根据日志级别输出服务响应信息 diff --git a/ruoyi-common/ruoyi-common-dubbo/src/main/resources/common-dubbo.yml b/ruoyi-common/ruoyi-common-dubbo/src/main/resources/common-dubbo.yml index e7035f1a..3e1199f6 100644 --- a/ruoyi-common/ruoyi-common-dubbo/src/main/resources/common-dubbo.yml +++ b/ruoyi-common/ruoyi-common-dubbo/src/main/resources/common-dubbo.yml @@ -27,6 +27,7 @@ dubbo: parameters: namespace: ${spring.profiles.active} database: ${spring.data.redis.database} + timeout: ${spring.data.redis.timeout} # 消费者相关配置 consumer: # 结果缓存(LRU算法) diff --git a/ruoyi-common/ruoyi-common-excel/pom.xml b/ruoyi-common/ruoyi-common-excel/pom.xml index dd4a5eeb..14b9410b 100644 --- a/ruoyi-common/ruoyi-common-excel/pom.xml +++ b/ruoyi-common/ruoyi-common-excel/pom.xml @@ -25,6 +25,11 @@ com.alibaba easyexcel + + commons-compress + org.apache.commons + 1.26.2 + diff --git a/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/core/CellMergeStrategy.java b/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/core/CellMergeStrategy.java index 7c0a48b9..7c7721c6 100644 --- a/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/core/CellMergeStrategy.java +++ b/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/core/CellMergeStrategy.java @@ -107,7 +107,7 @@ public class CellMergeStrategy extends AbstractMergeStrategy implements Workbook } if (!cellValue.equals(val)) { - if ((i - repeatCell.getCurrent() > 1) && isMerge(list, i, field)) { + if ((i - repeatCell.getCurrent() > 1)) { cellList.add(new CellRangeAddress(repeatCell.getCurrent() + rowIndex, i + rowIndex - 1, colNum, colNum)); } map.put(field, new RepeatCell(val, i)); @@ -115,6 +115,11 @@ public class CellMergeStrategy extends AbstractMergeStrategy implements Workbook if (i > repeatCell.getCurrent() && isMerge(list, i, field)) { cellList.add(new CellRangeAddress(repeatCell.getCurrent() + rowIndex, i + rowIndex, colNum, colNum)); } + } else if (!isMerge(list, i, field)) { + if ((i - repeatCell.getCurrent() > 1)) { + cellList.add(new CellRangeAddress(repeatCell.getCurrent() + rowIndex, i + rowIndex - 1, colNum, colNum)); + } + map.put(field, new RepeatCell(val, i)); } } } diff --git a/ruoyi-common/ruoyi-common-mail/src/main/java/org/dromara/common/mail/config/MailConfiguration.java b/ruoyi-common/ruoyi-common-mail/src/main/java/org/dromara/common/mail/config/MailConfiguration.java index 64101225..d8f8ef24 100644 --- a/ruoyi-common/ruoyi-common-mail/src/main/java/org/dromara/common/mail/config/MailConfiguration.java +++ b/ruoyi-common/ruoyi-common-mail/src/main/java/org/dromara/common/mail/config/MailConfiguration.java @@ -1,6 +1,6 @@ package org.dromara.common.mail.config; -import org.dromara.common.mail.utils.MailAccount; +import cn.hutool.extra.mail.MailAccount; import org.dromara.common.mail.config.properties.MailProperties; import org.springframework.boot.autoconfigure.AutoConfiguration; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; diff --git a/ruoyi-common/ruoyi-common-mail/src/main/java/org/dromara/common/mail/utils/GlobalMailAccount.java b/ruoyi-common/ruoyi-common-mail/src/main/java/org/dromara/common/mail/utils/GlobalMailAccount.java deleted file mode 100644 index fdae8697..00000000 --- a/ruoyi-common/ruoyi-common-mail/src/main/java/org/dromara/common/mail/utils/GlobalMailAccount.java +++ /dev/null @@ -1,46 +0,0 @@ -package org.dromara.common.mail.utils; - -import cn.hutool.core.io.IORuntimeException; - -/** - * 全局邮件帐户,依赖于邮件配置文件{@link MailAccount#MAIL_SETTING_PATHS} - * - * @author looly - */ -public enum GlobalMailAccount { - INSTANCE; - - private final MailAccount mailAccount; - - /** - * 构造 - */ - GlobalMailAccount() { - mailAccount = createDefaultAccount(); - } - - /** - * 获得邮件帐户 - * - * @return 邮件帐户 - */ - public MailAccount getAccount() { - return this.mailAccount; - } - - /** - * 创建默认帐户 - * - * @return MailAccount - */ - private MailAccount createDefaultAccount() { - for (String mailSettingPath : MailAccount.MAIL_SETTING_PATHS) { - try { - return new MailAccount(mailSettingPath); - } catch (IORuntimeException ignore) { - //ignore - } - } - return null; - } -} diff --git a/ruoyi-common/ruoyi-common-mail/src/main/java/org/dromara/common/mail/utils/InternalMailUtil.java b/ruoyi-common/ruoyi-common-mail/src/main/java/org/dromara/common/mail/utils/InternalMailUtil.java deleted file mode 100644 index b755e737..00000000 --- a/ruoyi-common/ruoyi-common-mail/src/main/java/org/dromara/common/mail/utils/InternalMailUtil.java +++ /dev/null @@ -1,108 +0,0 @@ -package org.dromara.common.mail.utils; - -import cn.hutool.core.util.ArrayUtil; -import jakarta.mail.internet.AddressException; -import jakarta.mail.internet.InternetAddress; -import jakarta.mail.internet.MimeUtility; - -import java.io.UnsupportedEncodingException; -import java.nio.charset.Charset; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - -/** - * 邮件内部工具类 - * - * @author looly - * @since 3.2.3 - */ -public class InternalMailUtil { - - /** - * 将多个字符串邮件地址转为{@link InternetAddress}列表
- * 单个字符串地址可以是多个地址合并的字符串 - * - * @param addrStrs 地址数组 - * @param charset 编码(主要用于中文用户名的编码) - * @return 地址数组 - * @since 4.0.3 - */ - public static InternetAddress[] parseAddressFromStrs(String[] addrStrs, Charset charset) { - final List resultList = new ArrayList<>(addrStrs.length); - InternetAddress[] addrs; - for (String addrStr : addrStrs) { - addrs = parseAddress(addrStr, charset); - if (ArrayUtil.isNotEmpty(addrs)) { - Collections.addAll(resultList, addrs); - } - } - return resultList.toArray(new InternetAddress[0]); - } - - /** - * 解析第一个地址 - * - * @param address 地址字符串 - * @param charset 编码,{@code null}表示使用系统属性定义的编码或系统编码 - * @return 地址列表 - */ - public static InternetAddress parseFirstAddress(String address, Charset charset) { - final InternetAddress[] internetAddresses = parseAddress(address, charset); - if (ArrayUtil.isEmpty(internetAddresses)) { - try { - return new InternetAddress(address); - } catch (AddressException e) { - throw new MailException(e); - } - } - return internetAddresses[0]; - } - - /** - * 将一个地址字符串解析为多个地址
- * 地址间使用" "、","、";"分隔 - * - * @param address 地址字符串 - * @param charset 编码,{@code null}表示使用系统属性定义的编码或系统编码 - * @return 地址列表 - */ - public static InternetAddress[] parseAddress(String address, Charset charset) { - InternetAddress[] addresses; - try { - addresses = InternetAddress.parse(address); - } catch (AddressException e) { - throw new MailException(e); - } - //编码用户名 - if (ArrayUtil.isNotEmpty(addresses)) { - final String charsetStr = null == charset ? null : charset.name(); - for (InternetAddress internetAddress : addresses) { - try { - internetAddress.setPersonal(internetAddress.getPersonal(), charsetStr); - } catch (UnsupportedEncodingException e) { - throw new MailException(e); - } - } - } - - return addresses; - } - - /** - * 编码中文字符
- * 编码失败返回原字符串 - * - * @param text 被编码的文本 - * @param charset 编码 - * @return 编码后的结果 - */ - public static String encodeText(String text, Charset charset) { - try { - return MimeUtility.encodeText(text, charset.name(), null); - } catch (UnsupportedEncodingException e) { - // ignore - } - return text; - } -} diff --git a/ruoyi-common/ruoyi-common-mail/src/main/java/org/dromara/common/mail/utils/Mail.java b/ruoyi-common/ruoyi-common-mail/src/main/java/org/dromara/common/mail/utils/Mail.java deleted file mode 100644 index 6ca4b69e..00000000 --- a/ruoyi-common/ruoyi-common-mail/src/main/java/org/dromara/common/mail/utils/Mail.java +++ /dev/null @@ -1,483 +0,0 @@ -package org.dromara.common.mail.utils; - -import cn.hutool.core.builder.Builder; -import cn.hutool.core.io.FileUtil; -import cn.hutool.core.io.IORuntimeException; -import cn.hutool.core.io.IoUtil; -import cn.hutool.core.util.ArrayUtil; -import cn.hutool.core.util.ObjectUtil; -import cn.hutool.core.util.StrUtil; -import jakarta.activation.DataHandler; -import jakarta.activation.DataSource; -import jakarta.activation.FileDataSource; -import jakarta.activation.FileTypeMap; -import jakarta.mail.*; -import jakarta.mail.internet.MimeBodyPart; -import jakarta.mail.internet.MimeMessage; -import jakarta.mail.internet.MimeMultipart; -import jakarta.mail.internet.MimeUtility; -import jakarta.mail.util.ByteArrayDataSource; - -import java.io.*; -import java.nio.charset.Charset; -import java.util.Date; - -/** - * 邮件发送客户端 - * - * @author looly - * @since 3.2.0 - */ -public class Mail implements Builder { - @Serial - private static final long serialVersionUID = 1L; - - /** - * 邮箱帐户信息以及一些客户端配置信息 - */ - private final MailAccount mailAccount; - /** - * 收件人列表 - */ - private String[] tos; - /** - * 抄送人列表(carbon copy) - */ - private String[] ccs; - /** - * 密送人列表(blind carbon copy) - */ - private String[] bccs; - /** - * 回复地址(reply-to) - */ - private String[] reply; - /** - * 标题 - */ - private String title; - /** - * 内容 - */ - private String content; - /** - * 是否为HTML - */ - private boolean isHtml; - /** - * 正文、附件和图片的混合部分 - */ - private final Multipart multipart = new MimeMultipart(); - /** - * 是否使用全局会话,默认为false - */ - private boolean useGlobalSession = false; - - /** - * debug输出位置,可以自定义debug日志 - */ - private PrintStream debugOutput; - - /** - * 创建邮件客户端 - * - * @param mailAccount 邮件帐号 - * @return Mail - */ - public static Mail create(MailAccount mailAccount) { - return new Mail(mailAccount); - } - - /** - * 创建邮件客户端,使用全局邮件帐户 - * - * @return Mail - */ - public static Mail create() { - return new Mail(); - } - - // --------------------------------------------------------------- Constructor start - - /** - * 构造,使用全局邮件帐户 - */ - public Mail() { - this(GlobalMailAccount.INSTANCE.getAccount()); - } - - /** - * 构造 - * - * @param mailAccount 邮件帐户,如果为null使用默认配置文件的全局邮件配置 - */ - public Mail(MailAccount mailAccount) { - mailAccount = (null != mailAccount) ? mailAccount : GlobalMailAccount.INSTANCE.getAccount(); - this.mailAccount = mailAccount.defaultIfEmpty(); - } - // --------------------------------------------------------------- Constructor end - - // --------------------------------------------------------------- Getters and Setters start - - /** - * 设置收件人 - * - * @param tos 收件人列表 - * @return this - * @see #setTos(String...) - */ - public Mail to(String... tos) { - return setTos(tos); - } - - /** - * 设置多个收件人 - * - * @param tos 收件人列表 - * @return this - */ - public Mail setTos(String... tos) { - this.tos = tos; - return this; - } - - /** - * 设置多个抄送人(carbon copy) - * - * @param ccs 抄送人列表 - * @return this - * @since 4.0.3 - */ - public Mail setCcs(String... ccs) { - this.ccs = ccs; - return this; - } - - /** - * 设置多个密送人(blind carbon copy) - * - * @param bccs 密送人列表 - * @return this - * @since 4.0.3 - */ - public Mail setBccs(String... bccs) { - this.bccs = bccs; - return this; - } - - /** - * 设置多个回复地址(reply-to) - * - * @param reply 回复地址(reply-to)列表 - * @return this - * @since 4.6.0 - */ - public Mail setReply(String... reply) { - this.reply = reply; - return this; - } - - /** - * 设置标题 - * - * @param title 标题 - * @return this - */ - public Mail setTitle(String title) { - this.title = title; - return this; - } - - /** - * 设置正文
- * 正文可以是普通文本也可以是HTML(默认普通文本),可以通过调用{@link #setHtml(boolean)} 设置是否为HTML - * - * @param content 正文 - * @return this - */ - public Mail setContent(String content) { - this.content = content; - return this; - } - - /** - * 设置是否是HTML - * - * @param isHtml 是否为HTML - * @return this - */ - public Mail setHtml(boolean isHtml) { - this.isHtml = isHtml; - return this; - } - - /** - * 设置正文 - * - * @param content 正文内容 - * @param isHtml 是否为HTML - * @return this - */ - public Mail setContent(String content, boolean isHtml) { - setContent(content); - return setHtml(isHtml); - } - - /** - * 设置文件类型附件,文件可以是图片文件,此时自动设置cid(正文中引用图片),默认cid为文件名 - * - * @param files 附件文件列表 - * @return this - */ - public Mail setFiles(File... files) { - if (ArrayUtil.isEmpty(files)) { - return this; - } - - final DataSource[] attachments = new DataSource[files.length]; - for (int i = 0; i < files.length; i++) { - attachments[i] = new FileDataSource(files[i]); - } - return setAttachments(attachments); - } - - /** - * 增加附件或图片,附件使用{@link DataSource} 形式表示,可以使用{@link FileDataSource}包装文件表示文件附件 - * - * @param attachments 附件列表 - * @return this - * @since 4.0.9 - */ - public Mail setAttachments(DataSource... attachments) { - if (ArrayUtil.isNotEmpty(attachments)) { - final Charset charset = this.mailAccount.getCharset(); - MimeBodyPart bodyPart; - String nameEncoded; - try { - for (DataSource attachment : attachments) { - bodyPart = new MimeBodyPart(); - bodyPart.setDataHandler(new DataHandler(attachment)); - nameEncoded = attachment.getName(); - if (this.mailAccount.isEncodefilename()) { - nameEncoded = InternalMailUtil.encodeText(nameEncoded, charset); - } - // 普通附件文件名 - bodyPart.setFileName(nameEncoded); - if (StrUtil.startWith(attachment.getContentType(), "image/")) { - // 图片附件,用于正文中引用图片 - bodyPart.setContentID(nameEncoded); - } - this.multipart.addBodyPart(bodyPart); - } - } catch (MessagingException e) { - throw new MailException(e); - } - } - return this; - } - - /** - * 增加图片,图片的键对应到邮件模板中的占位字符串,图片类型默认为"image/jpeg" - * - * @param cid 图片与占位符,占位符格式为cid:${cid} - * @param imageStream 图片文件 - * @return this - * @since 4.6.3 - */ - public Mail addImage(String cid, InputStream imageStream) { - return addImage(cid, imageStream, null); - } - - /** - * 增加图片,图片的键对应到邮件模板中的占位字符串 - * - * @param cid 图片与占位符,占位符格式为cid:${cid} - * @param imageStream 图片流,不关闭 - * @param contentType 图片类型,null赋值默认的"image/jpeg" - * @return this - * @since 4.6.3 - */ - public Mail addImage(String cid, InputStream imageStream, String contentType) { - ByteArrayDataSource imgSource; - try { - imgSource = new ByteArrayDataSource(imageStream, ObjectUtil.defaultIfNull(contentType, "image/jpeg")); - } catch (IOException e) { - throw new IORuntimeException(e); - } - imgSource.setName(cid); - return setAttachments(imgSource); - } - - /** - * 增加图片,图片的键对应到邮件模板中的占位字符串 - * - * @param cid 图片与占位符,占位符格式为cid:${cid} - * @param imageFile 图片文件 - * @return this - * @since 4.6.3 - */ - public Mail addImage(String cid, File imageFile) { - InputStream in = null; - try { - in = FileUtil.getInputStream(imageFile); - return addImage(cid, in, FileTypeMap.getDefaultFileTypeMap().getContentType(imageFile)); - } finally { - IoUtil.close(in); - } - } - - /** - * 设置字符集编码 - * - * @param charset 字符集编码 - * @return this - * @see MailAccount#setCharset(Charset) - */ - public Mail setCharset(Charset charset) { - this.mailAccount.setCharset(charset); - return this; - } - - /** - * 设置是否使用全局会话,默认为true - * - * @param isUseGlobalSession 是否使用全局会话,默认为true - * @return this - * @since 4.0.2 - */ - public Mail setUseGlobalSession(boolean isUseGlobalSession) { - this.useGlobalSession = isUseGlobalSession; - return this; - } - - /** - * 设置debug输出位置,可以自定义debug日志 - * - * @param debugOutput debug输出位置 - * @return this - * @since 5.5.6 - */ - public Mail setDebugOutput(PrintStream debugOutput) { - this.debugOutput = debugOutput; - return this; - } - // --------------------------------------------------------------- Getters and Setters end - - @Override - public MimeMessage build() { - try { - return buildMsg(); - } catch (MessagingException e) { - throw new MailException(e); - } - } - - /** - * 发送 - * - * @return message-id - * @throws MailException 邮件发送异常 - */ - public String send() throws MailException { - try { - return doSend(); - } catch (MessagingException e) { - if (e instanceof SendFailedException) { - // 当地址无效时,显示更加详细的无效地址信息 - final Address[] invalidAddresses = ((SendFailedException) e).getInvalidAddresses(); - final String msg = StrUtil.format("Invalid Addresses: {}", ArrayUtil.toString(invalidAddresses)); - throw new MailException(msg, e); - } - throw new MailException(e); - } - } - - // --------------------------------------------------------------- Private method start - - /** - * 执行发送 - * - * @return message-id - * @throws MessagingException 发送异常 - */ - private String doSend() throws MessagingException { - final MimeMessage mimeMessage = buildMsg(); - Transport.send(mimeMessage); - return mimeMessage.getMessageID(); - } - - /** - * 构建消息 - * - * @return {@link MimeMessage}消息 - * @throws MessagingException 消息异常 - */ - private MimeMessage buildMsg() throws MessagingException { - final Charset charset = this.mailAccount.getCharset(); - final MimeMessage msg = new MimeMessage(getSession()); - // 发件人 - final String from = this.mailAccount.getFrom(); - if (StrUtil.isEmpty(from)) { - // 用户未提供发送方,则从Session中自动获取 - msg.setFrom(); - } else { - msg.setFrom(InternalMailUtil.parseFirstAddress(from, charset)); - } - // 标题 - msg.setSubject(this.title, (null == charset) ? null : charset.name()); - // 发送时间 - msg.setSentDate(new Date()); - // 内容和附件 - msg.setContent(buildContent(charset)); - // 收件人 - msg.setRecipients(MimeMessage.RecipientType.TO, InternalMailUtil.parseAddressFromStrs(this.tos, charset)); - // 抄送人 - if (ArrayUtil.isNotEmpty(this.ccs)) { - msg.setRecipients(MimeMessage.RecipientType.CC, InternalMailUtil.parseAddressFromStrs(this.ccs, charset)); - } - // 密送人 - if (ArrayUtil.isNotEmpty(this.bccs)) { - msg.setRecipients(MimeMessage.RecipientType.BCC, InternalMailUtil.parseAddressFromStrs(this.bccs, charset)); - } - // 回复地址(reply-to) - if (ArrayUtil.isNotEmpty(this.reply)) { - msg.setReplyTo(InternalMailUtil.parseAddressFromStrs(this.reply, charset)); - } - - return msg; - } - - /** - * 构建邮件信息主体 - * - * @param charset 编码,{@code null}则使用{@link MimeUtility#getDefaultJavaCharset()} - * @return 邮件信息主体 - * @throws MessagingException 消息异常 - */ - private Multipart buildContent(Charset charset) throws MessagingException { - final String charsetStr = null != charset ? charset.name() : MimeUtility.getDefaultJavaCharset(); - // 正文 - final MimeBodyPart body = new MimeBodyPart(); - body.setContent(content, StrUtil.format("text/{}; charset={}", isHtml ? "html" : "plain", charsetStr)); - this.multipart.addBodyPart(body); - - return this.multipart; - } - - /** - * 获取默认邮件会话
- * 如果为全局单例的会话,则全局只允许一个邮件帐号,否则每次发送邮件会新建一个新的会话 - * - * @return 邮件会话 {@link Session} - */ - private Session getSession() { - final Session session = MailUtils.getSession(this.mailAccount, this.useGlobalSession); - - if (null != this.debugOutput) { - session.setDebugOut(debugOutput); - } - - return session; - } - // --------------------------------------------------------------- Private method end -} diff --git a/ruoyi-common/ruoyi-common-mail/src/main/java/org/dromara/common/mail/utils/MailAccount.java b/ruoyi-common/ruoyi-common-mail/src/main/java/org/dromara/common/mail/utils/MailAccount.java deleted file mode 100644 index 2a732a1a..00000000 --- a/ruoyi-common/ruoyi-common-mail/src/main/java/org/dromara/common/mail/utils/MailAccount.java +++ /dev/null @@ -1,659 +0,0 @@ -package org.dromara.common.mail.utils; - -import cn.hutool.core.util.CharsetUtil; -import cn.hutool.core.util.ObjectUtil; -import cn.hutool.core.util.StrUtil; -import cn.hutool.setting.Setting; - -import java.io.Serial; -import java.io.Serializable; -import java.nio.charset.Charset; -import java.util.HashMap; -import java.util.Map; -import java.util.Properties; - -/** - * 邮件账户对象 - * - * @author Luxiaolei - */ -public class MailAccount implements Serializable { - @Serial - private static final long serialVersionUID = -6937313421815719204L; - - private static final String MAIL_PROTOCOL = "mail.transport.protocol"; - private static final String SMTP_HOST = "mail.smtp.host"; - private static final String SMTP_PORT = "mail.smtp.port"; - private static final String SMTP_AUTH = "mail.smtp.auth"; - private static final String SMTP_TIMEOUT = "mail.smtp.timeout"; - private static final String SMTP_CONNECTION_TIMEOUT = "mail.smtp.connectiontimeout"; - private static final String SMTP_WRITE_TIMEOUT = "mail.smtp.writetimeout"; - - // SSL - private static final String STARTTLS_ENABLE = "mail.smtp.starttls.enable"; - private static final String SSL_ENABLE = "mail.smtp.ssl.enable"; - private static final String SSL_PROTOCOLS = "mail.smtp.ssl.protocols"; - private static final String SOCKET_FACTORY = "mail.smtp.socketFactory.class"; - private static final String SOCKET_FACTORY_FALLBACK = "mail.smtp.socketFactory.fallback"; - private static final String SOCKET_FACTORY_PORT = "smtp.socketFactory.port"; - - // System Properties - private static final String SPLIT_LONG_PARAMS = "mail.mime.splitlongparameters"; - //private static final String ENCODE_FILE_NAME = "mail.mime.encodefilename"; - //private static final String CHARSET = "mail.mime.charset"; - - // 其他 - private static final String MAIL_DEBUG = "mail.debug"; - - public static final String[] MAIL_SETTING_PATHS = new String[]{"config/mail.setting", "config/mailAccount.setting", "mail.setting"}; - - /** - * SMTP服务器域名 - */ - private String host; - /** - * SMTP服务端口 - */ - private Integer port; - /** - * 是否需要用户名密码验证 - */ - private Boolean auth; - /** - * 用户名 - */ - private String user; - /** - * 密码 - */ - private String pass; - /** - * 发送方,遵循RFC-822标准 - */ - private String from; - - /** - * 是否打开调试模式,调试模式会显示与邮件服务器通信过程,默认不开启 - */ - private boolean debug; - /** - * 编码用于编码邮件正文和发送人、收件人等中文 - */ - private Charset charset = CharsetUtil.CHARSET_UTF_8; - /** - * 对于超长参数是否切分为多份,默认为false(国内邮箱附件不支持切分的附件名) - */ - private boolean splitlongparameters = false; - /** - * 对于文件名是否使用{@link #charset}编码,默认为 {@code true} - */ - private boolean encodefilename = true; - - /** - * 使用 STARTTLS安全连接,STARTTLS是对纯文本通信协议的扩展。它将纯文本连接升级为加密连接(TLS或SSL), 而不是使用一个单独的加密通信端口。 - */ - private boolean starttlsEnable = false; - /** - * 使用 SSL安全连接 - */ - private Boolean sslEnable; - - /** - * SSL协议,多个协议用空格分隔 - */ - private String sslProtocols; - - /** - * 指定实现javax.net.SocketFactory接口的类的名称,这个类将被用于创建SMTP的套接字 - */ - private String socketFactoryClass = "javax.net.ssl.SSLSocketFactory"; - /** - * 如果设置为true,未能创建一个套接字使用指定的套接字工厂类将导致使用java.net.Socket创建的套接字类, 默认值为true - */ - private boolean socketFactoryFallback; - /** - * 指定的端口连接到在使用指定的套接字工厂。如果没有设置,将使用默认端口 - */ - private int socketFactoryPort = 465; - - /** - * SMTP超时时长,单位毫秒,缺省值不超时 - */ - private long timeout; - /** - * Socket连接超时值,单位毫秒,缺省值不超时 - */ - private long connectionTimeout; - /** - * Socket写出超时值,单位毫秒,缺省值不超时 - */ - private long writeTimeout; - - /** - * 自定义的其他属性,此自定义属性会覆盖默认属性 - */ - private final Map customProperty = new HashMap<>(); - - // -------------------------------------------------------------- Constructor start - - /** - * 构造,所有参数需自行定义或保持默认值 - */ - public MailAccount() { - } - - /** - * 构造 - * - * @param settingPath 配置文件路径 - */ - public MailAccount(String settingPath) { - this(new Setting(settingPath)); - } - - /** - * 构造 - * - * @param setting 配置文件 - */ - public MailAccount(Setting setting) { - setting.toBean(this); - } - - // -------------------------------------------------------------- Constructor end - - /** - * 获得SMTP服务器域名 - * - * @return SMTP服务器域名 - */ - public String getHost() { - return host; - } - - /** - * 设置SMTP服务器域名 - * - * @param host SMTP服务器域名 - * @return this - */ - public MailAccount setHost(String host) { - this.host = host; - return this; - } - - /** - * 获得SMTP服务端口 - * - * @return SMTP服务端口 - */ - public Integer getPort() { - return port; - } - - /** - * 设置SMTP服务端口 - * - * @param port SMTP服务端口 - * @return this - */ - public MailAccount setPort(Integer port) { - this.port = port; - return this; - } - - /** - * 是否需要用户名密码验证 - * - * @return 是否需要用户名密码验证 - */ - public Boolean isAuth() { - return auth; - } - - /** - * 设置是否需要用户名密码验证 - * - * @param isAuth 是否需要用户名密码验证 - * @return this - */ - public MailAccount setAuth(boolean isAuth) { - this.auth = isAuth; - return this; - } - - /** - * 获取用户名 - * - * @return 用户名 - */ - public String getUser() { - return user; - } - - /** - * 设置用户名 - * - * @param user 用户名 - * @return this - */ - public MailAccount setUser(String user) { - this.user = user; - return this; - } - - /** - * 获取密码 - * - * @return 密码 - */ - public String getPass() { - return pass; - } - - /** - * 设置密码 - * - * @param pass 密码 - * @return this - */ - public MailAccount setPass(String pass) { - this.pass = pass; - return this; - } - - /** - * 获取发送方,遵循RFC-822标准 - * - * @return 发送方,遵循RFC-822标准 - */ - public String getFrom() { - return from; - } - - /** - * 设置发送方,遵循RFC-822标准
- * 发件人可以是以下形式: - * - *
-     * 1. user@xxx.xx
-     * 2.  name <user@xxx.xx>
-     * 
- * - * @param from 发送方,遵循RFC-822标准 - * @return this - */ - public MailAccount setFrom(String from) { - this.from = from; - return this; - } - - /** - * 是否打开调试模式,调试模式会显示与邮件服务器通信过程,默认不开启 - * - * @return 是否打开调试模式,调试模式会显示与邮件服务器通信过程,默认不开启 - * @since 4.0.2 - */ - public boolean isDebug() { - return debug; - } - - /** - * 设置是否打开调试模式,调试模式会显示与邮件服务器通信过程,默认不开启 - * - * @param debug 是否打开调试模式,调试模式会显示与邮件服务器通信过程,默认不开启 - * @return this - * @since 4.0.2 - */ - public MailAccount setDebug(boolean debug) { - this.debug = debug; - return this; - } - - /** - * 获取字符集编码 - * - * @return 编码,可能为{@code null} - */ - public Charset getCharset() { - return charset; - } - - /** - * 设置字符集编码,此选项不会修改全局配置,若修改全局配置,请设置此项为{@code null}并设置: - *
-     * 	System.setProperty("mail.mime.charset", charset);
-     * 
- * - * @param charset 字符集编码,{@code null} 则表示使用全局设置的默认编码,全局编码为mail.mime.charset系统属性 - * @return this - */ - public MailAccount setCharset(Charset charset) { - this.charset = charset; - return this; - } - - /** - * 对于超长参数是否切分为多份,默认为false(国内邮箱附件不支持切分的附件名) - * - * @return 对于超长参数是否切分为多份 - */ - public boolean isSplitlongparameters() { - return splitlongparameters; - } - - /** - * 设置对于超长参数是否切分为多份,默认为false(国内邮箱附件不支持切分的附件名)
- * 注意此项为全局设置,此项会调用 - *
-     * System.setProperty("mail.mime.splitlongparameters", true)
-     * 
- * - * @param splitlongparameters 对于超长参数是否切分为多份 - */ - public void setSplitlongparameters(boolean splitlongparameters) { - this.splitlongparameters = splitlongparameters; - } - - /** - * 对于文件名是否使用{@link #charset}编码,默认为 {@code true} - * - * @return 对于文件名是否使用{@link #charset}编码,默认为 {@code true} - * @since 5.7.16 - */ - public boolean isEncodefilename() { - - return encodefilename; - } - - /** - * 设置对于文件名是否使用{@link #charset}编码,此选项不会修改全局配置
- * 如果此选项设置为{@code false},则是否编码取决于两个系统属性: - *
    - *
  • mail.mime.encodefilename 是否编码附件文件名
  • - *
  • mail.mime.charset 编码文件名的编码
  • - *
- * - * @param encodefilename 对于文件名是否使用{@link #charset}编码 - * @since 5.7.16 - */ - public void setEncodefilename(boolean encodefilename) { - this.encodefilename = encodefilename; - } - - /** - * 是否使用 STARTTLS安全连接,STARTTLS是对纯文本通信协议的扩展。它将纯文本连接升级为加密连接(TLS或SSL), 而不是使用一个单独的加密通信端口。 - * - * @return 是否使用 STARTTLS安全连接 - */ - public boolean isStarttlsEnable() { - return this.starttlsEnable; - } - - /** - * 设置是否使用STARTTLS安全连接,STARTTLS是对纯文本通信协议的扩展。它将纯文本连接升级为加密连接(TLS或SSL), 而不是使用一个单独的加密通信端口。 - * - * @param startttlsEnable 是否使用STARTTLS安全连接 - * @return this - */ - public MailAccount setStarttlsEnable(boolean startttlsEnable) { - this.starttlsEnable = startttlsEnable; - return this; - } - - /** - * 是否使用 SSL安全连接 - * - * @return 是否使用 SSL安全连接 - */ - public Boolean isSslEnable() { - return this.sslEnable; - } - - /** - * 设置是否使用SSL安全连接 - * - * @param sslEnable 是否使用SSL安全连接 - * @return this - */ - public MailAccount setSslEnable(Boolean sslEnable) { - this.sslEnable = sslEnable; - return this; - } - - /** - * 获取SSL协议,多个协议用空格分隔 - * - * @return SSL协议,多个协议用空格分隔 - * @since 5.5.7 - */ - public String getSslProtocols() { - return sslProtocols; - } - - /** - * 设置SSL协议,多个协议用空格分隔 - * - * @param sslProtocols SSL协议,多个协议用空格分隔 - * @since 5.5.7 - */ - public void setSslProtocols(String sslProtocols) { - this.sslProtocols = sslProtocols; - } - - /** - * 获取指定实现javax.net.SocketFactory接口的类的名称,这个类将被用于创建SMTP的套接字 - * - * @return 指定实现javax.net.SocketFactory接口的类的名称, 这个类将被用于创建SMTP的套接字 - */ - public String getSocketFactoryClass() { - return socketFactoryClass; - } - - /** - * 设置指定实现javax.net.SocketFactory接口的类的名称,这个类将被用于创建SMTP的套接字 - * - * @param socketFactoryClass 指定实现javax.net.SocketFactory接口的类的名称,这个类将被用于创建SMTP的套接字 - * @return this - */ - public MailAccount setSocketFactoryClass(String socketFactoryClass) { - this.socketFactoryClass = socketFactoryClass; - return this; - } - - /** - * 如果设置为true,未能创建一个套接字使用指定的套接字工厂类将导致使用java.net.Socket创建的套接字类, 默认值为true - * - * @return 如果设置为true, 未能创建一个套接字使用指定的套接字工厂类将导致使用java.net.Socket创建的套接字类, 默认值为true - */ - public boolean isSocketFactoryFallback() { - return socketFactoryFallback; - } - - /** - * 如果设置为true,未能创建一个套接字使用指定的套接字工厂类将导致使用java.net.Socket创建的套接字类, 默认值为true - * - * @param socketFactoryFallback 如果设置为true,未能创建一个套接字使用指定的套接字工厂类将导致使用java.net.Socket创建的套接字类, 默认值为true - * @return this - */ - public MailAccount setSocketFactoryFallback(boolean socketFactoryFallback) { - this.socketFactoryFallback = socketFactoryFallback; - return this; - } - - /** - * 获取指定的端口连接到在使用指定的套接字工厂。如果没有设置,将使用默认端口 - * - * @return 指定的端口连接到在使用指定的套接字工厂。如果没有设置,将使用默认端口 - */ - public int getSocketFactoryPort() { - return socketFactoryPort; - } - - /** - * 指定的端口连接到在使用指定的套接字工厂。如果没有设置,将使用默认端口 - * - * @param socketFactoryPort 指定的端口连接到在使用指定的套接字工厂。如果没有设置,将使用默认端口 - * @return this - */ - public MailAccount setSocketFactoryPort(int socketFactoryPort) { - this.socketFactoryPort = socketFactoryPort; - return this; - } - - /** - * 设置SMTP超时时长,单位毫秒,缺省值不超时 - * - * @param timeout SMTP超时时长,单位毫秒,缺省值不超时 - * @return this - * @since 4.1.17 - */ - public MailAccount setTimeout(long timeout) { - this.timeout = timeout; - return this; - } - - /** - * 设置Socket连接超时值,单位毫秒,缺省值不超时 - * - * @param connectionTimeout Socket连接超时值,单位毫秒,缺省值不超时 - * @return this - * @since 4.1.17 - */ - public MailAccount setConnectionTimeout(long connectionTimeout) { - this.connectionTimeout = connectionTimeout; - return this; - } - - /** - * 设置Socket写出超时值,单位毫秒,缺省值不超时 - * - * @param writeTimeout Socket写出超时值,单位毫秒,缺省值不超时 - * @return this - * @since 5.8.3 - */ - public MailAccount setWriteTimeout(long writeTimeout) { - this.writeTimeout = writeTimeout; - return this; - } - - /** - * 获取自定义属性列表 - * - * @return 自定义参数列表 - * @since 5.6.4 - */ - public Map getCustomProperty() { - return customProperty; - } - - /** - * 设置自定义属性,如mail.smtp.ssl.socketFactory - * - * @param key 属性名,空白被忽略 - * @param value 属性值, null被忽略 - * @return this - * @since 5.6.4 - */ - public MailAccount setCustomProperty(String key, Object value) { - if (StrUtil.isNotBlank(key) && ObjectUtil.isNotNull(value)) { - this.customProperty.put(key, value); - } - return this; - } - - /** - * 获得SMTP相关信息 - * - * @return {@link Properties} - */ - public Properties getSmtpProps() { - //全局系统参数 - System.setProperty(SPLIT_LONG_PARAMS, String.valueOf(this.splitlongparameters)); - - final Properties p = new Properties(); - p.put(MAIL_PROTOCOL, "smtp"); - p.put(SMTP_HOST, this.host); - p.put(SMTP_PORT, String.valueOf(this.port)); - p.put(SMTP_AUTH, String.valueOf(this.auth)); - if (this.timeout > 0) { - p.put(SMTP_TIMEOUT, String.valueOf(this.timeout)); - } - if (this.connectionTimeout > 0) { - p.put(SMTP_CONNECTION_TIMEOUT, String.valueOf(this.connectionTimeout)); - } - // issue#2355 - if (this.writeTimeout > 0) { - p.put(SMTP_WRITE_TIMEOUT, String.valueOf(this.writeTimeout)); - } - - p.put(MAIL_DEBUG, String.valueOf(this.debug)); - - if (this.starttlsEnable) { - //STARTTLS是对纯文本通信协议的扩展。它将纯文本连接升级为加密连接(TLS或SSL), 而不是使用一个单独的加密通信端口。 - p.put(STARTTLS_ENABLE, "true"); - - if (null == this.sslEnable) { - //为了兼容旧版本,当用户没有此项配置时,按照starttlsEnable开启状态时对待 - this.sslEnable = true; - } - } - - // SSL - if (null != this.sslEnable && this.sslEnable) { - p.put(SSL_ENABLE, "true"); - p.put(SOCKET_FACTORY, socketFactoryClass); - p.put(SOCKET_FACTORY_FALLBACK, String.valueOf(this.socketFactoryFallback)); - p.put(SOCKET_FACTORY_PORT, String.valueOf(this.socketFactoryPort)); - // issue#IZN95@Gitee,在Linux下需自定义SSL协议版本 - if (StrUtil.isNotBlank(this.sslProtocols)) { - p.put(SSL_PROTOCOLS, this.sslProtocols); - } - } - - // 补充自定义属性,允许自定属性覆盖已经设置的值 - p.putAll(this.customProperty); - - return p; - } - - /** - * 如果某些值为null,使用默认值 - * - * @return this - */ - public MailAccount defaultIfEmpty() { - // 去掉发件人的姓名部分 - final String fromAddress = InternalMailUtil.parseFirstAddress(this.from, this.charset).getAddress(); - - if (StrUtil.isBlank(this.host)) { - // 如果SMTP地址为空,默认使用smtp.<发件人邮箱后缀> - this.host = StrUtil.format("smtp.{}", StrUtil.subSuf(fromAddress, fromAddress.indexOf('@') + 1)); - } - if (StrUtil.isBlank(user)) { - // 如果用户名为空,默认为发件人(issue#I4FYVY@Gitee) - //this.user = StrUtil.subPre(fromAddress, fromAddress.indexOf('@')); - this.user = fromAddress; - } - if (null == this.auth) { - // 如果密码非空白,则使用认证模式 - this.auth = (false == StrUtil.isBlank(this.pass)); - } - if (null == this.port) { - // 端口在SSL状态下默认与socketFactoryPort一致,非SSL状态下默认为25 - this.port = (null != this.sslEnable && this.sslEnable) ? this.socketFactoryPort : 25; - } - if (null == this.charset) { - // 默认UTF-8编码 - this.charset = CharsetUtil.CHARSET_UTF_8; - } - - return this; - } - - @Override - public String toString() { - return "MailAccount [host=" + host + ", port=" + port + ", auth=" + auth + ", user=" + user + ", pass=" + (StrUtil.isEmpty(this.pass) ? "" : "******") + ", from=" + from + ", startttlsEnable=" - + starttlsEnable + ", socketFactoryClass=" + socketFactoryClass + ", socketFactoryFallback=" + socketFactoryFallback + ", socketFactoryPort=" + socketFactoryPort + "]"; - } -} diff --git a/ruoyi-common/ruoyi-common-mail/src/main/java/org/dromara/common/mail/utils/MailException.java b/ruoyi-common/ruoyi-common-mail/src/main/java/org/dromara/common/mail/utils/MailException.java deleted file mode 100644 index cc199d45..00000000 --- a/ruoyi-common/ruoyi-common-mail/src/main/java/org/dromara/common/mail/utils/MailException.java +++ /dev/null @@ -1,40 +0,0 @@ -package org.dromara.common.mail.utils; - -import cn.hutool.core.exceptions.ExceptionUtil; -import cn.hutool.core.util.StrUtil; - -import java.io.Serial; - -/** - * 邮件异常 - * - * @author xiaoleilu - */ -public class MailException extends RuntimeException { - @Serial - private static final long serialVersionUID = 8247610319171014183L; - - public MailException(Throwable e) { - super(ExceptionUtil.getMessage(e), e); - } - - public MailException(String message) { - super(message); - } - - public MailException(String messageTemplate, Object... params) { - super(StrUtil.format(messageTemplate, params)); - } - - public MailException(String message, Throwable throwable) { - super(message, throwable); - } - - public MailException(String message, Throwable throwable, boolean enableSuppression, boolean writableStackTrace) { - super(message, throwable, enableSuppression, writableStackTrace); - } - - public MailException(Throwable throwable, String messageTemplate, Object... params) { - super(StrUtil.format(messageTemplate, params), throwable); - } -} diff --git a/ruoyi-common/ruoyi-common-mail/src/main/java/org/dromara/common/mail/utils/MailUtils.java b/ruoyi-common/ruoyi-common-mail/src/main/java/org/dromara/common/mail/utils/MailUtils.java index 040cc572..a28701fb 100644 --- a/ruoyi-common/ruoyi-common-mail/src/main/java/org/dromara/common/mail/utils/MailUtils.java +++ b/ruoyi-common/ruoyi-common-mail/src/main/java/org/dromara/common/mail/utils/MailUtils.java @@ -5,6 +5,9 @@ import cn.hutool.core.io.IoUtil; import cn.hutool.core.map.MapUtil; import cn.hutool.core.util.CharUtil; import cn.hutool.core.util.StrUtil; +import cn.hutool.extra.mail.JakartaMail; +import cn.hutool.extra.mail.JakartaUserPassAuthenticator; +import cn.hutool.extra.mail.MailAccount; import jakarta.mail.Authenticator; import jakarta.mail.Session; import lombok.AccessLevel; @@ -17,7 +20,7 @@ import java.io.InputStream; import java.util.Collection; import java.util.List; import java.util.Map; - +import java.util.Map.Entry; /** * 邮件工具类 @@ -385,7 +388,7 @@ public class MailUtils { public static Session getSession(MailAccount mailAccount, boolean isSingleton) { Authenticator authenticator = null; if (mailAccount.isAuth()) { - authenticator = new UserPassAuthenticator(mailAccount.getUser(), mailAccount.getPass()); + authenticator = new JakartaUserPassAuthenticator(mailAccount.getUser(), mailAccount.getPass()); } return isSingleton ? Session.getDefaultInstance(mailAccount.getSmtpProps(), authenticator) // @@ -412,7 +415,7 @@ public class MailUtils { */ private static String send(MailAccount mailAccount, boolean useGlobalSession, Collection tos, Collection ccs, Collection bccs, String subject, String content, Map imageMap, boolean isHtml, File... files) { - final Mail mail = Mail.create(mailAccount).setUseGlobalSession(useGlobalSession); + final JakartaMail mail = JakartaMail.create(mailAccount).setUseGlobalSession(useGlobalSession); // 可选抄送人 if (CollUtil.isNotEmpty(ccs)) { @@ -431,7 +434,7 @@ public class MailUtils { // 图片 if (MapUtil.isNotEmpty(imageMap)) { - for (Map.Entry entry : imageMap.entrySet()) { + for (Entry entry : imageMap.entrySet()) { mail.addImage(entry.getKey(), entry.getValue()); // 关闭流 IoUtil.close(entry.getValue()); @@ -463,5 +466,4 @@ public class MailUtils { return result; } // ------------------------------------------------------------------------------------------------------------------------ Private method end - } diff --git a/ruoyi-common/ruoyi-common-mail/src/main/java/org/dromara/common/mail/utils/UserPassAuthenticator.java b/ruoyi-common/ruoyi-common-mail/src/main/java/org/dromara/common/mail/utils/UserPassAuthenticator.java deleted file mode 100644 index fbbe5e37..00000000 --- a/ruoyi-common/ruoyi-common-mail/src/main/java/org/dromara/common/mail/utils/UserPassAuthenticator.java +++ /dev/null @@ -1,33 +0,0 @@ -package org.dromara.common.mail.utils; - -import jakarta.mail.Authenticator; -import jakarta.mail.PasswordAuthentication; - -/** - * 用户名密码验证器 - * - * @author looly - * @since 3.1.2 - */ -public class UserPassAuthenticator extends Authenticator { - - private final String user; - private final String pass; - - /** - * 构造 - * - * @param user 用户名 - * @param pass 密码 - */ - public UserPassAuthenticator(String user, String pass) { - this.user = user; - this.pass = pass; - } - - @Override - protected PasswordAuthentication getPasswordAuthentication() { - return new PasswordAuthentication(this.user, this.pass); - } - -} diff --git a/ruoyi-common/ruoyi-common-mybatis/pom.xml b/ruoyi-common/ruoyi-common-mybatis/pom.xml index d25f4f4d..7fe7e3bb 100644 --- a/ruoyi-common/ruoyi-common-mybatis/pom.xml +++ b/ruoyi-common/ruoyi-common-mybatis/pom.xml @@ -50,21 +50,26 @@ com.mysql mysql-connector-j - - - com.oracle.database.jdbc - ojdbc8 - - - - org.postgresql - postgresql - - - - com.microsoft.sqlserver - mssql-jdbc - + + + + + + + + + + + + + + + + + + + + diff --git a/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/annotation/DataColumn.java b/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/annotation/DataColumn.java index f8c5cd00..bca638f7 100644 --- a/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/annotation/DataColumn.java +++ b/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/annotation/DataColumn.java @@ -30,4 +30,12 @@ public @interface DataColumn { */ String[] value() default "dept_id"; + /** + * 权限标识符 用于通过菜单权限标识符来获取数据权限 + * 拥有此标识符的角色 将不会拼接此角色的数据过滤sql + * + * @return 权限标识符 + */ + String permission() default ""; + } diff --git a/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/annotation/DataPermission.java b/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/annotation/DataPermission.java index 6fd3c3e0..f5f22d59 100644 --- a/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/annotation/DataPermission.java +++ b/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/annotation/DataPermission.java @@ -20,4 +20,11 @@ public @interface DataPermission { */ DataColumn[] value(); + /** + * 权限拼接标识符(用于指定连接语句的sql符号) + * 如不填 默认 select 用 OR 其他语句用 AND + * 内容 OR 或者 AND + */ + String joinStr() default ""; + } diff --git a/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/enums/DataScopeType.java b/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/enums/DataScopeType.java index a67395fa..5a30d687 100644 --- a/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/enums/DataScopeType.java +++ b/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/enums/DataScopeType.java @@ -4,7 +4,6 @@ import lombok.AllArgsConstructor; import lombok.Getter; import org.dromara.common.core.utils.StringUtils; import org.dromara.common.mybatis.helper.DataPermissionHelper; -import org.dromara.common.mybatis.service.SysDataScopeService; import org.dromara.system.api.model.LoginUser; /** @@ -14,9 +13,9 @@ import org.dromara.system.api.model.LoginUser; * 内置数据: * - {@code user}: 当前登录用户信息,参考 {@link LoginUser} * 内置服务: - * - {@code sdss}: 系统数据权限服务,参考 {@link SysDataScopeService} + * - {@code sdss}: 系统数据权限服务,参考 SysDataScopeService * 如需扩展数据,可以通过 {@link DataPermissionHelper} 进行操作 - * 如需扩展服务,可以通过 {@link SysDataScopeService} 自行编写 + * 如需扩展服务,可以通过 SysDataScopeService 自行编写 *

* * @author Lion Li @@ -33,29 +32,21 @@ public enum DataScopeType { /** * 自定数据权限 - * 使用 SpEL 表达式:`#{#deptName} IN ( #{@sdss.getRoleCustom( #user.roleId )} )` - * 如果不满足条件,则使用默认 SQL 表达式:`1 = 0` */ CUSTOM("2", " #{#deptName} IN ( #{@sdss.getRoleCustom( #user.roleId )} ) ", " 1 = 0 "), /** * 部门数据权限 - * 使用 SpEL 表达式:`#{#deptName} = #{#user.deptId}` - * 如果不满足条件,则使用默认 SQL 表达式:`1 = 0` */ DEPT("3", " #{#deptName} = #{#user.deptId} ", " 1 = 0 "), /** * 部门及以下数据权限 - * 使用 SpEL 表达式:`#{#deptName} IN ( #{@sdss.getDeptAndChild( #user.deptId )}` - * 如果不满足条件,则使用默认 SQL 表达式:`1 = 0` */ DEPT_AND_CHILD("4", " #{#deptName} IN ( #{@sdss.getDeptAndChild( #user.deptId )} )", " 1 = 0 "), /** * 仅本人数据权限 - * 使用 SpEL 表达式:`#{#userName} = #{#user.userId}` - * 如果不满足条件,则使用默认 SQL 表达式:`1 = 0` */ SELF("5", " #{#userName} = #{#user.userId} ", " 1 = 0 "); diff --git a/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/handler/InjectionMetaObjectHandler.java b/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/handler/InjectionMetaObjectHandler.java index f6b2b121..c0e650c6 100644 --- a/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/handler/InjectionMetaObjectHandler.java +++ b/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/handler/InjectionMetaObjectHandler.java @@ -47,6 +47,10 @@ public class InjectionMetaObjectHandler implements MetaObjectHandler { ? baseEntity.getCreateDept() : loginUser.getDeptId()); } } + } else { + Date date = new Date(); + this.strictInsertFill(metaObject, "createTime", Date.class, date); + this.strictInsertFill(metaObject, "updateTime", Date.class, date); } } catch (Exception e) { throw new ServiceException("自动注入异常 => " + e.getMessage(), HttpStatus.HTTP_UNAUTHORIZED); @@ -71,6 +75,8 @@ public class InjectionMetaObjectHandler implements MetaObjectHandler { if (ObjectUtil.isNotNull(userId)) { baseEntity.setUpdateBy(userId); } + } else { + this.strictUpdateFill(metaObject, "updateTime", Date.class, new Date()); } } catch (Exception e) { throw new ServiceException("自动注入异常 => " + e.getMessage(), HttpStatus.HTTP_UNAUTHORIZED); diff --git a/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/handler/PlusDataPermissionHandler.java b/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/handler/PlusDataPermissionHandler.java index 200006ff..5171e563 100644 --- a/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/handler/PlusDataPermissionHandler.java +++ b/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/handler/PlusDataPermissionHandler.java @@ -99,7 +99,7 @@ public class PlusDataPermissionHandler { return where; } // 构造数据过滤条件的 SQL 片段 - String dataFilterSql = buildDataFilter(dataPermission.value(), isSelect); + String dataFilterSql = buildDataFilter(dataPermission, isSelect); if (StringUtils.isBlank(dataFilterSql)) { return where; } @@ -120,14 +120,17 @@ public class PlusDataPermissionHandler { /** * 构建数据过滤条件的 SQL 语句 * - * @param dataColumns 数据权限注解中的列信息 - * @param isSelect 标志当前操作是否为查询操作,查询操作和更新或删除操作在处理过滤条件时会有不同的处理方式 + * @param dataPermission 数据权限注解 + * @param isSelect 标志当前操作是否为查询操作,查询操作和更新或删除操作在处理过滤条件时会有不同的处理方式 * @return 构建的数据过滤条件的 SQL 语句 * @throws ServiceException 如果角色的数据范围异常或者 key 与 value 的长度不匹配,则抛出 ServiceException 异常 */ - private String buildDataFilter(DataColumn[] dataColumns, boolean isSelect) { + private String buildDataFilter(DataPermission dataPermission, boolean isSelect) { // 更新或删除需满足所有条件 String joinStr = isSelect ? " OR " : " AND "; + if (StringUtils.isNotBlank(dataPermission.joinStr())) { + joinStr = " " + dataPermission.joinStr() + " "; + } LoginUser user = DataPermissionHelper.getVariable("user"); StandardEvaluationContext context = new StandardEvaluationContext(); context.setBeanResolver(beanResolver); @@ -145,7 +148,7 @@ public class PlusDataPermissionHandler { return ""; } boolean isSuccess = false; - for (DataColumn dataColumn : dataColumns) { + for (DataColumn dataColumn : dataPermission.value()) { if (dataColumn.key().length != dataColumn.value().length) { throw new ServiceException("角色数据范围异常 => key与value长度不匹配"); } @@ -155,6 +158,13 @@ public class PlusDataPermissionHandler { )) { continue; } + // 包含权限标识符 这直接跳过 + if (StringUtils.isNotBlank(dataColumn.permission()) && + CollUtil.contains(user.getMenuPermission(), dataColumn.permission()) + ) { + isSuccess = true; + continue; + } // 设置注解变量 key 为表达式变量 value 为变量值 for (int i = 0; i < dataColumn.key().length; i++) { context.setVariable(dataColumn.key()[i], dataColumn.value()[i]); diff --git a/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/helper/DataPermissionHelper.java b/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/helper/DataPermissionHelper.java index 4650a5a1..39fad6e8 100644 --- a/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/helper/DataPermissionHelper.java +++ b/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/helper/DataPermissionHelper.java @@ -2,14 +2,17 @@ package org.dromara.common.mybatis.helper; import cn.dev33.satoken.context.SaHolder; import cn.dev33.satoken.context.model.SaStorage; +import cn.hutool.core.collection.CollectionUtil; import cn.hutool.core.util.ObjectUtil; import com.baomidou.mybatisplus.core.plugins.IgnoreStrategy; import com.baomidou.mybatisplus.core.plugins.InterceptorIgnoreHelper; import lombok.AccessLevel; import lombok.NoArgsConstructor; +import org.dromara.common.core.utils.reflect.ReflectUtils; import java.util.HashMap; import java.util.Map; +import java.util.Stack; import java.util.function.Supplier; /** @@ -24,6 +27,8 @@ public class DataPermissionHelper { public static final String DATA_PERMISSION_KEY = "data:permission"; + private static final ThreadLocal> REENTRANT_IGNORE = ThreadLocal.withInitial(Stack::new); + /** * 从上下文中获取指定键的变量值,并将其转换为指定的类型 * @@ -66,23 +71,54 @@ public class DataPermissionHelper { throw new NullPointerException("data permission context type exception"); } + private static IgnoreStrategy getIgnoreStrategy() { + Object ignoreStrategyLocal = ReflectUtils.getStaticFieldValue(ReflectUtils.getField(InterceptorIgnoreHelper.class, "IGNORE_STRATEGY_LOCAL")); + if (ignoreStrategyLocal instanceof ThreadLocal IGNORE_STRATEGY_LOCAL) { + if (IGNORE_STRATEGY_LOCAL.get() instanceof IgnoreStrategy ignoreStrategy) { + return ignoreStrategy; + } + } + return null; + } + /** * 开启忽略数据权限(开启后需手动调用 {@link #disableIgnore()} 关闭) */ public static void enableIgnore() { - InterceptorIgnoreHelper.handle(IgnoreStrategy.builder().dataPermission(true).build()); + IgnoreStrategy ignoreStrategy = getIgnoreStrategy(); + if (ObjectUtil.isNull(ignoreStrategy)) { + InterceptorIgnoreHelper.handle(IgnoreStrategy.builder().dataPermission(true).build()); + } else { + ignoreStrategy.setDataPermission(true); + } + Stack reentrantStack = REENTRANT_IGNORE.get(); + reentrantStack.push(reentrantStack.size() + 1); } /** * 关闭忽略数据权限 */ public static void disableIgnore() { - InterceptorIgnoreHelper.clearIgnoreStrategy(); + IgnoreStrategy ignoreStrategy = getIgnoreStrategy(); + if (ObjectUtil.isNotNull(ignoreStrategy)) { + boolean noOtherIgnoreStrategy = !Boolean.TRUE.equals(ignoreStrategy.getDynamicTableName()) + && !Boolean.TRUE.equals(ignoreStrategy.getBlockAttack()) + && !Boolean.TRUE.equals(ignoreStrategy.getIllegalSql()) + && !Boolean.TRUE.equals(ignoreStrategy.getTenantLine()) + && CollectionUtil.isEmpty(ignoreStrategy.getOthers()); + Stack reentrantStack = REENTRANT_IGNORE.get(); + boolean empty = reentrantStack.isEmpty() || reentrantStack.pop() == 1; + if (noOtherIgnoreStrategy && empty) { + InterceptorIgnoreHelper.clearIgnoreStrategy(); + } else if (empty) { + ignoreStrategy.setDataPermission(false); + } + + } } /** * 在忽略数据权限中执行 - *

禁止在忽略数据权限中执行忽略数据权限

* * @param handle 处理执行方法 */ @@ -97,7 +133,6 @@ public class DataPermissionHelper { /** * 在忽略数据权限中执行 - *

禁止在忽略数据权限中执行忽略数据权限

* * @param handle 处理执行方法 */ diff --git a/ruoyi-common/ruoyi-common-ratelimiter/src/main/java/org/dromara/common/ratelimiter/aspectj/RateLimiterAspect.java b/ruoyi-common/ruoyi-common-ratelimiter/src/main/java/org/dromara/common/ratelimiter/aspectj/RateLimiterAspect.java index 02735b07..1f4904a3 100644 --- a/ruoyi-common/ruoyi-common-ratelimiter/src/main/java/org/dromara/common/ratelimiter/aspectj/RateLimiterAspect.java +++ b/ruoyi-common/ruoyi-common-ratelimiter/src/main/java/org/dromara/common/ratelimiter/aspectj/RateLimiterAspect.java @@ -80,11 +80,11 @@ public class RateLimiterAspect { private String getCombineKey(RateLimiter rateLimiter, JoinPoint point) { String key = rateLimiter.key(); - if (StringUtils.isNotBlank(key)) { + // 判断 key 不为空 和 不是表达式 + if (StringUtils.isNotBlank(key) && StringUtils.containsAny(key, "#")) { MethodSignature signature = (MethodSignature) point.getSignature(); Method targetMethod = signature.getMethod(); Object[] args = point.getArgs(); - //noinspection DataFlowIssue MethodBasedEvaluationContext context = new MethodBasedEvaluationContext(null, targetMethod, args, pnd); context.setBeanResolver(new BeanFactoryResolver(SpringUtils.getBeanFactory())); diff --git a/ruoyi-common/ruoyi-common-redis/src/main/java/org/dromara/common/redis/manager/CaffeineCacheDecorator.java b/ruoyi-common/ruoyi-common-redis/src/main/java/org/dromara/common/redis/manager/CaffeineCacheDecorator.java index ee1d405f..793e21f5 100644 --- a/ruoyi-common/ruoyi-common-redis/src/main/java/org/dromara/common/redis/manager/CaffeineCacheDecorator.java +++ b/ruoyi-common/ruoyi-common-redis/src/main/java/org/dromara/common/redis/manager/CaffeineCacheDecorator.java @@ -15,15 +15,17 @@ public class CaffeineCacheDecorator implements Cache { private static final com.github.benmanes.caffeine.cache.Cache CAFFEINE = SpringUtils.getBean("caffeine"); + private final String name; private final Cache cache; - public CaffeineCacheDecorator(Cache cache) { + public CaffeineCacheDecorator(String name, Cache cache) { + this.name = name; this.cache = cache; } @Override public String getName() { - return cache.getName(); + return name; } @Override @@ -32,7 +34,7 @@ public class CaffeineCacheDecorator implements Cache { } public String getUniqueKey(Object key) { - return cache.getName() + ":" + key; + return name + ":" + key; } @Override diff --git a/ruoyi-common/ruoyi-common-redis/src/main/java/org/dromara/common/redis/manager/PlusSpringCacheManager.java b/ruoyi-common/ruoyi-common-redis/src/main/java/org/dromara/common/redis/manager/PlusSpringCacheManager.java index a48cb142..740e2a13 100644 --- a/ruoyi-common/ruoyi-common-redis/src/main/java/org/dromara/common/redis/manager/PlusSpringCacheManager.java +++ b/ruoyi-common/ruoyi-common-redis/src/main/java/org/dromara/common/redis/manager/PlusSpringCacheManager.java @@ -156,7 +156,7 @@ public class PlusSpringCacheManager implements CacheManager { private Cache createMap(String name, CacheConfig config) { RMap map = RedisUtils.getClient().getMap(name); - Cache cache = new CaffeineCacheDecorator(new RedissonCache(map, allowNullValues)); + Cache cache = new CaffeineCacheDecorator(name, new RedissonCache(map, allowNullValues)); if (transactionAware) { cache = new TransactionAwareCacheDecorator(cache); } @@ -170,7 +170,7 @@ public class PlusSpringCacheManager implements CacheManager { private Cache createMapCache(String name, CacheConfig config) { RMapCache map = RedisUtils.getClient().getMapCache(name); - Cache cache = new CaffeineCacheDecorator(new RedissonCache(map, config, allowNullValues)); + Cache cache = new CaffeineCacheDecorator(name, new RedissonCache(map, config, allowNullValues)); if (transactionAware) { cache = new TransactionAwareCacheDecorator(cache); } diff --git a/ruoyi-common/ruoyi-common-satoken/pom.xml b/ruoyi-common/ruoyi-common-satoken/pom.xml index ecdb7630..5643acb8 100644 --- a/ruoyi-common/ruoyi-common-satoken/pom.xml +++ b/ruoyi-common/ruoyi-common-satoken/pom.xml @@ -27,17 +27,6 @@ cn.dev33 sa-token-jwt ${satoken.version} - - - cn.hutool - hutool-all - - - - - - cn.hutool - hutool-jwt diff --git a/ruoyi-common/ruoyi-common-security/src/main/java/org/dromara/common/security/config/SecurityConfiguration.java b/ruoyi-common/ruoyi-common-security/src/main/java/org/dromara/common/security/config/SecurityConfiguration.java index efd34fc2..fb1b39a0 100644 --- a/ruoyi-common/ruoyi-common-security/src/main/java/org/dromara/common/security/config/SecurityConfiguration.java +++ b/ruoyi-common/ruoyi-common-security/src/main/java/org/dromara/common/security/config/SecurityConfiguration.java @@ -2,10 +2,12 @@ package org.dromara.common.security.config; import cn.dev33.satoken.SaManager; import cn.dev33.satoken.filter.SaServletFilter; +import cn.dev33.satoken.httpauth.basic.SaHttpBasicUtil; import cn.dev33.satoken.interceptor.SaInterceptor; import cn.dev33.satoken.same.SaSameUtil; import cn.dev33.satoken.util.SaResult; import org.dromara.common.core.constant.HttpStatus; +import org.dromara.common.core.utils.SpringUtils; import org.springframework.boot.autoconfigure.AutoConfiguration; import org.springframework.context.annotation.Bean; import org.springframework.web.servlet.config.annotation.InterceptorRegistry; @@ -35,7 +37,7 @@ public class SecurityConfiguration implements WebMvcConfigurer { public SaServletFilter getSaServletFilter() { return new SaServletFilter() .addInclude("/**") - .addExclude("/actuator/**") + .addExclude("/actuator", "/actuator/**") .setAuth(obj -> { if (SaManager.getConfig().getCheckSameToken()) { SaSameUtil.checkCurrentRequestToken(); @@ -44,4 +46,19 @@ public class SecurityConfiguration implements WebMvcConfigurer { .setError(e -> SaResult.error("认证失败,无法访问系统资源").setCode(HttpStatus.UNAUTHORIZED)); } + /** + * 对 actuator 健康检查接口 做账号密码鉴权 + */ + @Bean + public SaServletFilter actuatorFilter() { + String username = SpringUtils.getProperty("spring.cloud.nacos.discovery.metadata.username"); + String password = SpringUtils.getProperty("spring.cloud.nacos.discovery.metadata.userpassword"); + return new SaServletFilter() + .addInclude("/actuator", "/actuator/**") + .setAuth(obj -> { + SaHttpBasicUtil.check(username + ":" + password); + }) + .setError(e -> SaResult.error(e.getMessage()).setCode(HttpStatus.UNAUTHORIZED)); + } + } diff --git a/ruoyi-common/ruoyi-common-sensitive/src/main/java/org/dromara/common/sensitive/core/SensitiveStrategy.java b/ruoyi-common/ruoyi-common-sensitive/src/main/java/org/dromara/common/sensitive/core/SensitiveStrategy.java index 9d1978a1..995dcbd9 100644 --- a/ruoyi-common/ruoyi-common-sensitive/src/main/java/org/dromara/common/sensitive/core/SensitiveStrategy.java +++ b/ruoyi-common/ruoyi-common-sensitive/src/main/java/org/dromara/common/sensitive/core/SensitiveStrategy.java @@ -37,7 +37,57 @@ public enum SensitiveStrategy { /** * 银行卡 */ - BANK_CARD(DesensitizedUtil::bankCard); + BANK_CARD(DesensitizedUtil::bankCard), + + /** + * 中文名 + */ + CHINESE_NAME(DesensitizedUtil::chineseName), + + /** + * 固定电话 + */ + FIXED_PHONE(DesensitizedUtil::fixedPhone), + + /** + * 用户ID + */ + USER_ID(s -> String.valueOf(DesensitizedUtil.userId())), + + /** + * 密码 + */ + PASSWORD(DesensitizedUtil::password), + + /** + * ipv4 + */ + IPV4(DesensitizedUtil::ipv4), + + /** + * ipv6 + */ + IPV6(DesensitizedUtil::ipv6), + + /** + * 中国大陆车牌,包含普通车辆、新能源车辆 + */ + CAR_LICENSE(DesensitizedUtil::carLicense), + + /** + * 只显示第一个字符 + */ + FIRST_MASK(DesensitizedUtil::firstMask), + + /** + * 清空为null + */ + CLEAR(s -> DesensitizedUtil.clear()), + + /** + * 清空为"" + */ + CLEAR_TO_NULL(s -> DesensitizedUtil.clearToNull()); //可自行添加其他脱敏策略 diff --git a/ruoyi-common/ruoyi-common-sentinel/src/main/java/com/alibaba/cloud/sentinel/custom/SentinelAutoConfiguration.java b/ruoyi-common/ruoyi-common-sentinel/src/main/java/com/alibaba/cloud/sentinel/custom/SentinelAutoConfiguration.java deleted file mode 100644 index df23c492..00000000 --- a/ruoyi-common/ruoyi-common-sentinel/src/main/java/com/alibaba/cloud/sentinel/custom/SentinelAutoConfiguration.java +++ /dev/null @@ -1,265 +0,0 @@ -/* - * Copyright 2013-2018 the original author or authors. - * - * Licensed 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 - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.alibaba.cloud.sentinel.custom; - -import com.alibaba.cloud.commons.lang.StringUtils; -import com.alibaba.cloud.sentinel.SentinelProperties; -import com.alibaba.cloud.sentinel.datasource.converter.JsonConverter; -import com.alibaba.cloud.sentinel.datasource.converter.XmlConverter; -import com.alibaba.csp.sentinel.annotation.aspectj.SentinelResourceAspect; -import com.alibaba.csp.sentinel.config.SentinelConfig; -import com.alibaba.csp.sentinel.init.InitExecutor; -import com.alibaba.csp.sentinel.log.LogBase; -import com.alibaba.csp.sentinel.slots.block.authority.AuthorityRule; -import com.alibaba.csp.sentinel.slots.block.degrade.DegradeRule; -import com.alibaba.csp.sentinel.slots.block.flow.FlowRule; -import com.alibaba.csp.sentinel.slots.block.flow.param.ParamFlowRule; -import com.alibaba.csp.sentinel.slots.system.SystemRule; -import com.alibaba.csp.sentinel.transport.config.TransportConfig; -import com.fasterxml.jackson.databind.DeserializationFeature; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.dataformat.xml.XmlMapper; -import jakarta.annotation.PostConstruct; -import org.dromara.common.core.utils.StreamUtils; -import org.dromara.common.sentinel.config.properties.SentinelCustomProperties; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.beans.factory.support.DefaultListableBeanFactory; -import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; -import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; -import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; -import org.springframework.boot.context.properties.EnableConfigurationProperties; -import org.springframework.cloud.client.ServiceInstance; -import org.springframework.cloud.client.discovery.DiscoveryClient; -import org.springframework.context.ApplicationContext; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.core.env.Environment; - -import java.util.List; - -import static com.alibaba.cloud.sentinel.SentinelConstants.BLOCK_PAGE_URL_CONF_KEY; -import static com.alibaba.csp.sentinel.config.SentinelConfig.setConfig; - -/** - * 改造sentinel自动配置 支持服务名注册 - * - * @author Lion Li - * - * @author xiaojing - * @author jiashuai.xie - * @author Jim - */ -@Configuration(proxyBeanMethods = false) -@ConditionalOnProperty(name = "spring.cloud.sentinel.enabled", matchIfMissing = true) -@EnableConfigurationProperties({SentinelProperties.class, SentinelCustomProperties.class}) -public class SentinelAutoConfiguration { - - @Value("${project.name:${spring.application.name:}}") - private String projectName; - - @Autowired - private SentinelProperties properties; - @Autowired - private SentinelCustomProperties customProperties; - @Autowired - private DiscoveryClient discoveryClient; - - @PostConstruct - private void init() { - if (StringUtils.isEmpty(System.getProperty(LogBase.LOG_DIR)) - && StringUtils.isNotBlank(properties.getLog().getDir())) { - System.setProperty(LogBase.LOG_DIR, properties.getLog().getDir()); - } - if (StringUtils.isEmpty(System.getProperty(LogBase.LOG_NAME_USE_PID)) - && properties.getLog().isSwitchPid()) { - System.setProperty(LogBase.LOG_NAME_USE_PID, - String.valueOf(properties.getLog().isSwitchPid())); - } - if (StringUtils.isEmpty(System.getProperty(SentinelConfig.APP_NAME_PROP_KEY)) - && StringUtils.isNotBlank(projectName)) { - System.setProperty(SentinelConfig.APP_NAME_PROP_KEY, projectName); - } - if (StringUtils.isEmpty(System.getProperty(TransportConfig.SERVER_PORT)) - && StringUtils.isNotBlank(properties.getTransport().getPort())) { - System.setProperty(TransportConfig.SERVER_PORT, - properties.getTransport().getPort()); - } - - if (StringUtils.isNotBlank(customProperties.getServerName())) { - List instances = discoveryClient.getInstances(customProperties.getServerName()); - String serverList = StreamUtils.join(instances, instance -> - String.format("http://%s:%s", instance.getHost(), instance.getPort())); - System.setProperty(TransportConfig.CONSOLE_SERVER, serverList); - } else { - if (StringUtils.isEmpty(System.getProperty(TransportConfig.CONSOLE_SERVER)) - && StringUtils.isNotBlank(properties.getTransport().getDashboard())) { - System.setProperty(TransportConfig.CONSOLE_SERVER, - properties.getTransport().getDashboard()); - } - } - - if (StringUtils.isEmpty(System.getProperty(TransportConfig.HEARTBEAT_INTERVAL_MS)) - && StringUtils - .isNotBlank(properties.getTransport().getHeartbeatIntervalMs())) { - System.setProperty(TransportConfig.HEARTBEAT_INTERVAL_MS, - properties.getTransport().getHeartbeatIntervalMs()); - } - if (StringUtils.isEmpty(System.getProperty(TransportConfig.HEARTBEAT_CLIENT_IP)) - && StringUtils.isNotBlank(properties.getTransport().getClientIp())) { - System.setProperty(TransportConfig.HEARTBEAT_CLIENT_IP, - properties.getTransport().getClientIp()); - } - if (StringUtils.isEmpty(System.getProperty(SentinelConfig.CHARSET)) - && StringUtils.isNotBlank(properties.getMetric().getCharset())) { - System.setProperty(SentinelConfig.CHARSET, - properties.getMetric().getCharset()); - } - if (StringUtils - .isEmpty(System.getProperty(SentinelConfig.SINGLE_METRIC_FILE_SIZE)) - && StringUtils.isNotBlank(properties.getMetric().getFileSingleSize())) { - System.setProperty(SentinelConfig.SINGLE_METRIC_FILE_SIZE, - properties.getMetric().getFileSingleSize()); - } - if (StringUtils - .isEmpty(System.getProperty(SentinelConfig.TOTAL_METRIC_FILE_COUNT)) - && StringUtils.isNotBlank(properties.getMetric().getFileTotalCount())) { - System.setProperty(SentinelConfig.TOTAL_METRIC_FILE_COUNT, - properties.getMetric().getFileTotalCount()); - } - if (StringUtils.isEmpty(System.getProperty(SentinelConfig.COLD_FACTOR)) - && StringUtils.isNotBlank(properties.getFlow().getColdFactor())) { - System.setProperty(SentinelConfig.COLD_FACTOR, - properties.getFlow().getColdFactor()); - } - if (StringUtils.isNotBlank(properties.getBlockPage())) { - setConfig(BLOCK_PAGE_URL_CONF_KEY, properties.getBlockPage()); - } - - // earlier initialize - if (properties.isEager()) { - InitExecutor.doInit(); - } - - } - - @Bean - @ConditionalOnMissingBean - public SentinelResourceAspect sentinelResourceAspect() { - return new SentinelResourceAspect(); - } - - @Bean - @ConditionalOnMissingBean - @ConditionalOnClass(name = "org.springframework.web.client.RestTemplate") - @ConditionalOnProperty(name = "resttemplate.sentinel.enabled", havingValue = "true", - matchIfMissing = true) - public SentinelBeanPostProcessor sentinelBeanPostProcessor( - ApplicationContext applicationContext) { - return new SentinelBeanPostProcessor(applicationContext); - } - - @Bean - @ConditionalOnMissingBean - public SentinelDataSourceHandler sentinelDataSourceHandler( - DefaultListableBeanFactory beanFactory, SentinelProperties sentinelProperties, - Environment env) { - return new SentinelDataSourceHandler(beanFactory, sentinelProperties, env); - } - - @ConditionalOnClass(ObjectMapper.class) - @Configuration(proxyBeanMethods = false) - protected static class SentinelConverterConfiguration { - - @Configuration(proxyBeanMethods = false) - protected static class SentinelJsonConfiguration { - - private ObjectMapper objectMapper = new ObjectMapper(); - - public SentinelJsonConfiguration() { - objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, - false); - } - - @Bean("sentinel-json-flow-converter") - public JsonConverter jsonFlowConverter() { - return new JsonConverter(objectMapper, FlowRule.class); - } - - @Bean("sentinel-json-degrade-converter") - public JsonConverter jsonDegradeConverter() { - return new JsonConverter(objectMapper, DegradeRule.class); - } - - @Bean("sentinel-json-system-converter") - public JsonConverter jsonSystemConverter() { - return new JsonConverter(objectMapper, SystemRule.class); - } - - @Bean("sentinel-json-authority-converter") - public JsonConverter jsonAuthorityConverter() { - return new JsonConverter(objectMapper, AuthorityRule.class); - } - - @Bean("sentinel-json-param-flow-converter") - public JsonConverter jsonParamFlowConverter() { - return new JsonConverter(objectMapper, ParamFlowRule.class); - } - - } - - @ConditionalOnClass(XmlMapper.class) - @Configuration(proxyBeanMethods = false) - protected static class SentinelXmlConfiguration { - - private XmlMapper xmlMapper = new XmlMapper(); - - public SentinelXmlConfiguration() { - xmlMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, - false); - } - - @Bean("sentinel-xml-flow-converter") - public XmlConverter xmlFlowConverter() { - return new XmlConverter(xmlMapper, FlowRule.class); - } - - @Bean("sentinel-xml-degrade-converter") - public XmlConverter xmlDegradeConverter() { - return new XmlConverter(xmlMapper, DegradeRule.class); - } - - @Bean("sentinel-xml-system-converter") - public XmlConverter xmlSystemConverter() { - return new XmlConverter(xmlMapper, SystemRule.class); - } - - @Bean("sentinel-xml-authority-converter") - public XmlConverter xmlAuthorityConverter() { - return new XmlConverter(xmlMapper, AuthorityRule.class); - } - - @Bean("sentinel-xml-param-flow-converter") - public XmlConverter xmlParamFlowConverter() { - return new XmlConverter(xmlMapper, ParamFlowRule.class); - } - - } - - } - -} diff --git a/ruoyi-common/ruoyi-common-sentinel/src/main/java/org/dromara/common/sentinel/config/SentinelCustomAutoConfiguration.java b/ruoyi-common/ruoyi-common-sentinel/src/main/java/org/dromara/common/sentinel/config/SentinelCustomAutoConfiguration.java new file mode 100644 index 00000000..edfdcd19 --- /dev/null +++ b/ruoyi-common/ruoyi-common-sentinel/src/main/java/org/dromara/common/sentinel/config/SentinelCustomAutoConfiguration.java @@ -0,0 +1,51 @@ +package org.dromara.common.sentinel.config; + +import com.alibaba.cloud.commons.lang.StringUtils; +import com.alibaba.cloud.sentinel.SentinelProperties; +import com.alibaba.cloud.sentinel.custom.SentinelAutoConfiguration; +import com.alibaba.csp.sentinel.init.InitExecutor; +import com.alibaba.csp.sentinel.transport.config.TransportConfig; +import org.dromara.common.core.utils.StreamUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.AutoConfiguration; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.cloud.client.ServiceInstance; +import org.springframework.cloud.client.discovery.DiscoveryClient; +import org.springframework.context.annotation.Bean; + +import java.util.List; + +/** + * @author Lion Li + */ +@AutoConfiguration(before = SentinelAutoConfiguration.class) +@EnableConfigurationProperties({SentinelProperties.class, SentinelCustomProperties.class}) +public class SentinelCustomAutoConfiguration { + + @Autowired + private SentinelProperties properties; + @Autowired + private SentinelCustomProperties customProperties; + @Autowired + private DiscoveryClient discoveryClient; + + @Bean + public void sentinelInit() { + if (StringUtils.isNotBlank(customProperties.getServerName())) { + List instances = discoveryClient.getInstances(customProperties.getServerName()); + String serverList = StreamUtils.join(instances, instance -> + String.format("http://%s:%s", instance.getHost(), instance.getPort())); + System.setProperty(TransportConfig.CONSOLE_SERVER, serverList); + } else { + if (StringUtils.isEmpty(System.getProperty(TransportConfig.CONSOLE_SERVER)) + && StringUtils.isNotBlank(properties.getTransport().getDashboard())) { + System.setProperty(TransportConfig.CONSOLE_SERVER, + properties.getTransport().getDashboard()); + } + } + // 手动初始化 sentinel + InitExecutor.doInit(); + } + + +} diff --git a/ruoyi-common/ruoyi-common-sentinel/src/main/java/org/dromara/common/sentinel/config/properties/SentinelCustomProperties.java b/ruoyi-common/ruoyi-common-sentinel/src/main/java/org/dromara/common/sentinel/config/SentinelCustomProperties.java similarity index 84% rename from ruoyi-common/ruoyi-common-sentinel/src/main/java/org/dromara/common/sentinel/config/properties/SentinelCustomProperties.java rename to ruoyi-common/ruoyi-common-sentinel/src/main/java/org/dromara/common/sentinel/config/SentinelCustomProperties.java index 934cd36b..0cd3982c 100644 --- a/ruoyi-common/ruoyi-common-sentinel/src/main/java/org/dromara/common/sentinel/config/properties/SentinelCustomProperties.java +++ b/ruoyi-common/ruoyi-common-sentinel/src/main/java/org/dromara/common/sentinel/config/SentinelCustomProperties.java @@ -1,4 +1,4 @@ -package org.dromara.common.sentinel.config.properties; +package org.dromara.common.sentinel.config; import lombok.Data; import org.springframework.boot.context.properties.ConfigurationProperties; diff --git a/ruoyi-common/ruoyi-common-sentinel/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/ruoyi-common/ruoyi-common-sentinel/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports index 8b137891..68693d42 100644 --- a/ruoyi-common/ruoyi-common-sentinel/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports +++ b/ruoyi-common/ruoyi-common-sentinel/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports @@ -1 +1 @@ - +org.dromara.common.sentinel.config.SentinelCustomAutoConfiguration diff --git a/ruoyi-common/ruoyi-common-social/src/main/java/org/dromara/common/social/utils/SocialUtils.java b/ruoyi-common/ruoyi-common-social/src/main/java/org/dromara/common/social/utils/SocialUtils.java index 60ba3865..f0cbcf5e 100644 --- a/ruoyi-common/ruoyi-common-social/src/main/java/org/dromara/common/social/utils/SocialUtils.java +++ b/ruoyi-common/ruoyi-common-social/src/main/java/org/dromara/common/social/utils/SocialUtils.java @@ -58,9 +58,9 @@ public class SocialUtils { case "linkedin" -> new AuthLinkedinRequest(builder.build(), STATE_CACHE); case "microsoft" -> new AuthMicrosoftRequest(builder.build(), STATE_CACHE); case "renren" -> new AuthRenrenRequest(builder.build(), STATE_CACHE); - case "stack_overflow" -> new AuthStackOverflowRequest(builder.stackOverflowKey("").build(), STATE_CACHE); + case "stack_overflow" -> new AuthStackOverflowRequest(builder.build(), STATE_CACHE); case "huawei" -> new AuthHuaweiRequest(builder.build(), STATE_CACHE); - case "wechat_enterprise" -> new AuthWeChatEnterpriseQrcodeRequest(builder.agentId("").build(), STATE_CACHE); + case "wechat_enterprise" -> new AuthWeChatEnterpriseQrcodeRequest(builder.build(), STATE_CACHE); case "gitlab" -> new AuthGitlabRequest(builder.build(), STATE_CACHE); case "wechat_mp" -> new AuthWeChatMpRequest(builder.build(), STATE_CACHE); case "aliyun" -> new AuthAliyunRequest(builder.build(), STATE_CACHE); diff --git a/ruoyi-common/ruoyi-common-sse/pom.xml b/ruoyi-common/ruoyi-common-sse/pom.xml new file mode 100644 index 00000000..88f89a14 --- /dev/null +++ b/ruoyi-common/ruoyi-common-sse/pom.xml @@ -0,0 +1,40 @@ + + + + org.dromara + ruoyi-common + ${revision} + + 4.0.0 + + ruoyi-common-sse + + + ruoyi-common-sse 模块 + + + + + org.dromara + ruoyi-common-core + + + org.dromara + ruoyi-common-redis + + + org.dromara + ruoyi-common-satoken + + + org.dromara + ruoyi-common-json + + + org.springframework + spring-webmvc + + + diff --git a/ruoyi-common/ruoyi-common-sse/src/main/java/org/dromara/common/sse/config/SseAutoConfiguration.java b/ruoyi-common/ruoyi-common-sse/src/main/java/org/dromara/common/sse/config/SseAutoConfiguration.java new file mode 100644 index 00000000..0cf8054e --- /dev/null +++ b/ruoyi-common/ruoyi-common-sse/src/main/java/org/dromara/common/sse/config/SseAutoConfiguration.java @@ -0,0 +1,36 @@ +package org.dromara.common.sse.config; + +import org.dromara.common.sse.controller.SseController; +import org.dromara.common.sse.core.SseEmitterManager; +import org.dromara.common.sse.listener.SseTopicListener; +import org.springframework.boot.autoconfigure.AutoConfiguration; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.context.annotation.Bean; + +/** + * SSE 自动装配 + * + * @author Lion Li + */ +@AutoConfiguration +@ConditionalOnProperty(value = "sse.enabled", havingValue = "true") +@EnableConfigurationProperties(SseProperties.class) +public class SseAutoConfiguration { + + @Bean + public SseEmitterManager sseEmitterManager() { + return new SseEmitterManager(); + } + + @Bean + public SseTopicListener sseTopicListener() { + return new SseTopicListener(); + } + + @Bean + public SseController sseController(SseEmitterManager sseEmitterManager) { + return new SseController(sseEmitterManager); + } + +} diff --git a/ruoyi-common/ruoyi-common-sse/src/main/java/org/dromara/common/sse/config/SseProperties.java b/ruoyi-common/ruoyi-common-sse/src/main/java/org/dromara/common/sse/config/SseProperties.java new file mode 100644 index 00000000..ce4e1732 --- /dev/null +++ b/ruoyi-common/ruoyi-common-sse/src/main/java/org/dromara/common/sse/config/SseProperties.java @@ -0,0 +1,21 @@ +package org.dromara.common.sse.config; + +import lombok.Data; +import org.springframework.boot.context.properties.ConfigurationProperties; + +/** + * SSE 配置项 + * + * @author Lion Li + */ +@Data +@ConfigurationProperties("sse") +public class SseProperties { + + private Boolean enabled; + + /** + * 路径 + */ + private String path; +} diff --git a/ruoyi-common/ruoyi-common-sse/src/main/java/org/dromara/common/sse/controller/SseController.java b/ruoyi-common/ruoyi-common-sse/src/main/java/org/dromara/common/sse/controller/SseController.java new file mode 100644 index 00000000..41832fc9 --- /dev/null +++ b/ruoyi-common/ruoyi-common-sse/src/main/java/org/dromara/common/sse/controller/SseController.java @@ -0,0 +1,85 @@ +package org.dromara.common.sse.controller; + +import cn.dev33.satoken.stp.StpUtil; +import lombok.RequiredArgsConstructor; +import org.dromara.common.core.domain.R; +import org.dromara.common.satoken.utils.LoginHelper; +import org.dromara.common.sse.core.SseEmitterManager; +import org.dromara.common.sse.dto.SseMessageDto; +import org.springframework.beans.factory.DisposableBean; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.http.MediaType; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.servlet.mvc.method.annotation.SseEmitter; + +import java.util.List; + +/** + * SSE 控制器 + * + * @author Lion Li + */ +@RestController +@ConditionalOnProperty(value = "sse.enabled", havingValue = "true") +@RequiredArgsConstructor +public class SseController implements DisposableBean { + + private final SseEmitterManager sseEmitterManager; + + /** + * 建立 SSE 连接 + */ + @GetMapping(value = "${sse.path}", produces = MediaType.TEXT_EVENT_STREAM_VALUE) + public SseEmitter connect() { + String tokenValue = StpUtil.getTokenValue(); + Long userId = LoginHelper.getUserId(); + return sseEmitterManager.connect(userId, tokenValue); + } + + /** + * 关闭 SSE 连接 + */ + @GetMapping(value = "${sse.path}/close") + public R close() { + String tokenValue = StpUtil.getTokenValue(); + Long userId = LoginHelper.getUserId(); + sseEmitterManager.disconnect(userId, tokenValue); + return R.ok(); + } + + /** + * 向特定用户发送消息 + * + * @param userId 目标用户的 ID + * @param msg 要发送的消息内容 + */ + @GetMapping(value = "${sse.path}/send") + public R send(Long userId, String msg) { + SseMessageDto dto = new SseMessageDto(); + dto.setUserIds(List.of(userId)); + dto.setMessage(msg); + sseEmitterManager.publishMessage(dto); + return R.ok(); + } + + /** + * 向所有用户发送消息 + * + * @param msg 要发送的消息内容 + */ + @GetMapping(value = "${sse.path}/sendAll") + public R send(String msg) { + sseEmitterManager.publishAll(msg); + return R.ok(); + } + + /** + * 清理资源。此方法目前不执行任何操作,但避免因未实现而导致错误 + */ + @Override + public void destroy() throws Exception { + // 销毁时不需要做什么 此方法避免无用操作报错 + } + +} diff --git a/ruoyi-common/ruoyi-common-sse/src/main/java/org/dromara/common/sse/core/SseEmitterManager.java b/ruoyi-common/ruoyi-common-sse/src/main/java/org/dromara/common/sse/core/SseEmitterManager.java new file mode 100644 index 00000000..1d37a27d --- /dev/null +++ b/ruoyi-common/ruoyi-common-sse/src/main/java/org/dromara/common/sse/core/SseEmitterManager.java @@ -0,0 +1,160 @@ +package org.dromara.common.sse.core; + +import cn.hutool.core.collection.CollUtil; +import lombok.extern.slf4j.Slf4j; +import org.dromara.common.redis.utils.RedisUtils; +import org.dromara.common.sse.dto.SseMessageDto; +import org.springframework.web.servlet.mvc.method.annotation.SseEmitter; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.function.Consumer; + +/** + * 管理 Server-Sent Events (SSE) 连接 + * + * @author Lion Li + */ +@Slf4j +public class SseEmitterManager { + + /** + * 订阅的频道 + */ + private final static String SSE_TOPIC = "global:sse"; + + private final static Map> USER_TOKEN_EMITTERS = new ConcurrentHashMap<>(); + + /** + * 建立与指定用户的 SSE 连接 + * + * @param userId 用户的唯一标识符,用于区分不同用户的连接 + * @param token 用户的唯一令牌,用于识别具体的连接 + * @return 返回一个 SseEmitter 实例,客户端可以通过该实例接收 SSE 事件 + */ + public SseEmitter connect(Long userId, String token) { + // 从 USER_TOKEN_EMITTERS 中获取或创建当前用户的 SseEmitter 映射表(ConcurrentHashMap) + // 每个用户可以有多个 SSE 连接,通过 token 进行区分 + Map emitters = USER_TOKEN_EMITTERS.computeIfAbsent(userId, k -> new ConcurrentHashMap<>()); + + // 创建一个新的 SseEmitter 实例,超时时间设置为 0 表示无限制 + SseEmitter emitter = new SseEmitter(0L); + + emitters.put(token, emitter); + + // 当 emitter 完成、超时或发生错误时,从映射表中移除对应的 token + emitter.onCompletion(() -> emitters.remove(token)); + emitter.onTimeout(() -> emitters.remove(token)); + emitter.onError((e) -> emitters.remove(token)); + + try { + // 向客户端发送一条连接成功的事件 + emitter.send(SseEmitter.event().comment("connected")); + } catch (IOException e) { + // 如果发送消息失败,则从映射表中移除 emitter + emitters.remove(token); + } + return emitter; + } + + /** + * 断开指定用户的 SSE 连接 + * + * @param userId 用户的唯一标识符,用于区分不同用户的连接 + * @param token 用户的唯一令牌,用于识别具体的连接 + */ + public void disconnect(Long userId, String token) { + Map emitters = USER_TOKEN_EMITTERS.get(userId); + if (emitters != null) { + try { + emitters.get(token).send(SseEmitter.event().comment("disconnected")); + } catch (Exception ignore) { + } + emitters.remove(token); + } + } + + /** + * 订阅SSE消息主题,并提供一个消费者函数来处理接收到的消息 + * + * @param consumer 处理SSE消息的消费者函数 + */ + public void subscribeMessage(Consumer consumer) { + RedisUtils.subscribe(SSE_TOPIC, SseMessageDto.class, consumer); + } + + /** + * 向指定的用户会话发送消息 + * + * @param userId 要发送消息的用户id + * @param message 要发送的消息内容 + */ + public void sendMessage(Long userId, String message) { + Map emitters = USER_TOKEN_EMITTERS.get(userId); + if (emitters != null) { + for (Map.Entry entry : emitters.entrySet()) { + try { + entry.getValue().send(SseEmitter.event() + .name("message") + .data(message)); + } catch (Exception e) { + emitters.remove(entry.getKey()); + } + } + } + } + + /** + * 本机全用户会话发送消息 + * + * @param message 要发送的消息内容 + */ + public void sendMessage(String message) { + for (Long userId : USER_TOKEN_EMITTERS.keySet()) { + sendMessage(userId, message); + } + } + + /** + * 发布SSE订阅消息 + * + * @param sseMessageDto 要发布的SSE消息对象 + */ + public void publishMessage(SseMessageDto sseMessageDto) { + List unsentUserIds = new ArrayList<>(); + // 当前服务内用户,直接发送消息 + for (Long userId : sseMessageDto.getUserIds()) { + if (USER_TOKEN_EMITTERS.containsKey(userId)) { + sendMessage(userId, sseMessageDto.getMessage()); + continue; + } + unsentUserIds.add(userId); + } + // 不在当前服务内用户,发布订阅消息 + if (CollUtil.isNotEmpty(unsentUserIds)) { + SseMessageDto broadcastMessage = new SseMessageDto(); + broadcastMessage.setMessage(sseMessageDto.getMessage()); + broadcastMessage.setUserIds(unsentUserIds); + RedisUtils.publish(SSE_TOPIC, broadcastMessage, consumer -> { + log.info("SSE发送主题订阅消息topic:{} session keys:{} message:{}", + SSE_TOPIC, unsentUserIds, sseMessageDto.getMessage()); + }); + } + } + + /** + * 向所有的用户发布订阅的消息(群发) + * + * @param message 要发布的消息内容 + */ + public void publishAll(String message) { + SseMessageDto broadcastMessage = new SseMessageDto(); + broadcastMessage.setMessage(message); + RedisUtils.publish(SSE_TOPIC, broadcastMessage, consumer -> { + log.info("SSE发送主题订阅消息topic:{} message:{}", SSE_TOPIC, message); + }); + } +} diff --git a/ruoyi-common/ruoyi-common-sse/src/main/java/org/dromara/common/sse/dto/SseMessageDto.java b/ruoyi-common/ruoyi-common-sse/src/main/java/org/dromara/common/sse/dto/SseMessageDto.java new file mode 100644 index 00000000..a2e1210c --- /dev/null +++ b/ruoyi-common/ruoyi-common-sse/src/main/java/org/dromara/common/sse/dto/SseMessageDto.java @@ -0,0 +1,29 @@ +package org.dromara.common.sse.dto; + +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; +import java.util.List; + +/** + * 消息的dto + * + * @author zendwang + */ +@Data +public class SseMessageDto implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 需要推送到的session key 列表 + */ + private List userIds; + + /** + * 需要发送的消息 + */ + private String message; +} diff --git a/ruoyi-common/ruoyi-common-sse/src/main/java/org/dromara/common/sse/listener/SseTopicListener.java b/ruoyi-common/ruoyi-common-sse/src/main/java/org/dromara/common/sse/listener/SseTopicListener.java new file mode 100644 index 00000000..7a4dff13 --- /dev/null +++ b/ruoyi-common/ruoyi-common-sse/src/main/java/org/dromara/common/sse/listener/SseTopicListener.java @@ -0,0 +1,48 @@ +package org.dromara.common.sse.listener; + +import cn.hutool.core.collection.CollUtil; +import lombok.extern.slf4j.Slf4j; +import org.dromara.common.sse.core.SseEmitterManager; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.ApplicationArguments; +import org.springframework.boot.ApplicationRunner; +import org.springframework.core.Ordered; + +/** + * SSE 主题订阅监听器 + * + * @author Lion Li + */ +@Slf4j +public class SseTopicListener implements ApplicationRunner, Ordered { + + @Autowired + private SseEmitterManager sseEmitterManager; + + /** + * 在Spring Boot应用程序启动时初始化SSE主题订阅监听器 + * + * @param args 应用程序参数 + * @throws Exception 初始化过程中可能抛出的异常 + */ + @Override + public void run(ApplicationArguments args) throws Exception { + sseEmitterManager.subscribeMessage((message) -> { + log.info("SSE主题订阅收到消息session keys={} message={}", message.getUserIds(), message.getMessage()); + // 如果key不为空就按照key发消息 如果为空就群发 + if (CollUtil.isNotEmpty(message.getUserIds())) { + message.getUserIds().forEach(key -> { + sseEmitterManager.sendMessage(key, message.getMessage()); + }); + } else { + sseEmitterManager.sendMessage(message.getMessage()); + } + }); + log.info("初始化SSE主题订阅监听器成功"); + } + + @Override + public int getOrder() { + return -1; + } +} diff --git a/ruoyi-common/ruoyi-common-sse/src/main/java/org/dromara/common/sse/utils/SseMessageUtils.java b/ruoyi-common/ruoyi-common-sse/src/main/java/org/dromara/common/sse/utils/SseMessageUtils.java new file mode 100644 index 00000000..c6abdc8f --- /dev/null +++ b/ruoyi-common/ruoyi-common-sse/src/main/java/org/dromara/common/sse/utils/SseMessageUtils.java @@ -0,0 +1,58 @@ +package org.dromara.common.sse.utils; + +import lombok.AccessLevel; +import lombok.NoArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.dromara.common.core.utils.SpringUtils; +import org.dromara.common.sse.core.SseEmitterManager; +import org.dromara.common.sse.dto.SseMessageDto; + +/** + * SSE工具类 + * + * @author Lion Li + */ +@Slf4j +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public class SseMessageUtils { + + private final static SseEmitterManager MANAGER = SpringUtils.getBean(SseEmitterManager.class); + + /** + * 向指定的WebSocket会话发送消息 + * + * @param userId 要发送消息的用户id + * @param message 要发送的消息内容 + */ + public static void sendMessage(Long userId, String message) { + MANAGER.sendMessage(userId, message); + } + + /** + * 本机全用户会话发送消息 + * + * @param message 要发送的消息内容 + */ + public static void sendMessage(String message) { + MANAGER.sendMessage(message); + } + + /** + * 发布SSE订阅消息 + * + * @param sseMessageDto 要发布的SSE消息对象 + */ + public static void publishMessage(SseMessageDto sseMessageDto) { + MANAGER.publishMessage(sseMessageDto); + } + + /** + * 向所有的用户发布订阅的消息(群发) + * + * @param message 要发布的消息内容 + */ + public static void publishAll(String message) { + MANAGER.publishAll(message); + } + +} diff --git a/ruoyi-common/ruoyi-common-sse/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/ruoyi-common/ruoyi-common-sse/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports new file mode 100644 index 00000000..b8097139 --- /dev/null +++ b/ruoyi-common/ruoyi-common-sse/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports @@ -0,0 +1 @@ +org.dromara.common.sse.config.SseAutoConfiguration diff --git a/ruoyi-common/ruoyi-common-tenant/src/main/java/org/dromara/common/tenant/helper/TenantHelper.java b/ruoyi-common/ruoyi-common-tenant/src/main/java/org/dromara/common/tenant/helper/TenantHelper.java index 9d087e11..b1856126 100644 --- a/ruoyi-common/ruoyi-common-tenant/src/main/java/org/dromara/common/tenant/helper/TenantHelper.java +++ b/ruoyi-common/ruoyi-common-tenant/src/main/java/org/dromara/common/tenant/helper/TenantHelper.java @@ -1,8 +1,9 @@ package org.dromara.common.tenant.helper; import cn.dev33.satoken.stp.StpUtil; +import cn.hutool.core.collection.CollectionUtil; import cn.hutool.core.convert.Convert; -import com.alibaba.ttl.TransmittableThreadLocal; +import cn.hutool.core.util.ObjectUtil; import com.baomidou.mybatisplus.core.plugins.IgnoreStrategy; import com.baomidou.mybatisplus.core.plugins.InterceptorIgnoreHelper; import lombok.AccessLevel; @@ -11,9 +12,11 @@ import lombok.extern.slf4j.Slf4j; import org.dromara.common.core.constant.GlobalConstants; import org.dromara.common.core.utils.SpringUtils; import org.dromara.common.core.utils.StringUtils; +import org.dromara.common.core.utils.reflect.ReflectUtils; import org.dromara.common.redis.utils.RedisUtils; import org.dromara.common.satoken.utils.LoginHelper; +import java.util.Stack; import java.util.function.Supplier; /** @@ -27,7 +30,9 @@ public class TenantHelper { private static final String DYNAMIC_TENANT_KEY = GlobalConstants.GLOBAL_REDIS_KEY + "dynamicTenant"; - private static final ThreadLocal TEMP_DYNAMIC_TENANT = new TransmittableThreadLocal<>(); + private static final ThreadLocal TEMP_DYNAMIC_TENANT = new ThreadLocal<>(); + + private static final ThreadLocal> REENTRANT_IGNORE = ThreadLocal.withInitial(Stack::new); /** * 租户功能是否启用 @@ -36,18 +41,49 @@ public class TenantHelper { return Convert.toBool(SpringUtils.getProperty("tenant.enable"), false); } + private static IgnoreStrategy getIgnoreStrategy() { + Object ignoreStrategyLocal = ReflectUtils.getStaticFieldValue(ReflectUtils.getField(InterceptorIgnoreHelper.class, "IGNORE_STRATEGY_LOCAL")); + if (ignoreStrategyLocal instanceof ThreadLocal IGNORE_STRATEGY_LOCAL) { + if (IGNORE_STRATEGY_LOCAL.get() instanceof IgnoreStrategy ignoreStrategy) { + return ignoreStrategy; + } + } + return null; + } + /** * 开启忽略租户(开启后需手动调用 {@link #disableIgnore()} 关闭) */ public static void enableIgnore() { - InterceptorIgnoreHelper.handle(IgnoreStrategy.builder().tenantLine(true).build()); + IgnoreStrategy ignoreStrategy = getIgnoreStrategy(); + if (ObjectUtil.isNull(ignoreStrategy)) { + InterceptorIgnoreHelper.handle(IgnoreStrategy.builder().tenantLine(true).build()); + } else { + ignoreStrategy.setTenantLine(true); + } + Stack reentrantStack = REENTRANT_IGNORE.get(); + reentrantStack.push(reentrantStack.size() + 1); } /** * 关闭忽略租户 */ public static void disableIgnore() { - InterceptorIgnoreHelper.clearIgnoreStrategy(); + IgnoreStrategy ignoreStrategy = getIgnoreStrategy(); + if (ObjectUtil.isNotNull(ignoreStrategy)) { + boolean noOtherIgnoreStrategy = !Boolean.TRUE.equals(ignoreStrategy.getDynamicTableName()) + && !Boolean.TRUE.equals(ignoreStrategy.getBlockAttack()) + && !Boolean.TRUE.equals(ignoreStrategy.getIllegalSql()) + && !Boolean.TRUE.equals(ignoreStrategy.getDataPermission()) + && CollectionUtil.isEmpty(ignoreStrategy.getOthers()); + Stack reentrantStack = REENTRANT_IGNORE.get(); + boolean empty = reentrantStack.isEmpty() || reentrantStack.pop() == 1; + if (noOtherIgnoreStrategy && empty) { + InterceptorIgnoreHelper.clearIgnoreStrategy(); + } else if (empty) { + ignoreStrategy.setTenantLine(false); + } + } } /** diff --git a/ruoyi-common/ruoyi-common-tenant/src/main/java/org/dromara/common/tenant/manager/TenantSpringCacheManager.java b/ruoyi-common/ruoyi-common-tenant/src/main/java/org/dromara/common/tenant/manager/TenantSpringCacheManager.java index d230afc1..346e36f1 100644 --- a/ruoyi-common/ruoyi-common-tenant/src/main/java/org/dromara/common/tenant/manager/TenantSpringCacheManager.java +++ b/ruoyi-common/ruoyi-common-tenant/src/main/java/org/dromara/common/tenant/manager/TenantSpringCacheManager.java @@ -1,5 +1,7 @@ package org.dromara.common.tenant.manager; +import com.baomidou.mybatisplus.core.plugins.InterceptorIgnoreHelper; +import lombok.extern.slf4j.Slf4j; import org.dromara.common.core.constant.GlobalConstants; import org.dromara.common.core.utils.StringUtils; import org.dromara.common.redis.manager.PlusSpringCacheManager; @@ -11,6 +13,7 @@ import org.springframework.cache.Cache; * * @author Lion Li */ +@Slf4j public class TenantSpringCacheManager extends PlusSpringCacheManager { public TenantSpringCacheManager() { @@ -18,10 +21,16 @@ public class TenantSpringCacheManager extends PlusSpringCacheManager { @Override public Cache getCache(String name) { + if (InterceptorIgnoreHelper.willIgnoreTenantLine("")) { + return super.getCache(name); + } if (StringUtils.contains(name, GlobalConstants.GLOBAL_REDIS_KEY)) { return super.getCache(name); } String tenantId = TenantHelper.getTenantId(); + if (StringUtils.isBlank(tenantId)) { + log.error("无法获取有效的租户id -> Null"); + } if (StringUtils.startsWith(name, tenantId)) { // 如果存在则直接返回 return super.getCache(name); diff --git a/ruoyi-common/ruoyi-common-web/pom.xml b/ruoyi-common/ruoyi-common-web/pom.xml index 5ef7e928..7e920d16 100644 --- a/ruoyi-common/ruoyi-common-web/pom.xml +++ b/ruoyi-common/ruoyi-common-web/pom.xml @@ -39,6 +39,19 @@ spring-boot-starter-undertow + + io.undertow + undertow-core + + + io.undertow + undertow-servlet + + + io.undertow + undertow-websockets-jsr + + org.springframework.boot diff --git a/ruoyi-common/ruoyi-common-web/src/main/java/org/dromara/common/web/handler/GlobalExceptionHandler.java b/ruoyi-common/ruoyi-common-web/src/main/java/org/dromara/common/web/handler/GlobalExceptionHandler.java index bd47c189..061d3aa4 100644 --- a/ruoyi-common/ruoyi-common-web/src/main/java/org/dromara/common/web/handler/GlobalExceptionHandler.java +++ b/ruoyi-common/ruoyi-common-web/src/main/java/org/dromara/common/web/handler/GlobalExceptionHandler.java @@ -16,10 +16,13 @@ import org.springframework.web.HttpRequestMethodNotSupportedException; import org.springframework.web.bind.MethodArgumentNotValidException; import org.springframework.web.bind.MissingPathVariableException; import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.bind.annotation.ResponseStatus; import org.springframework.web.bind.annotation.RestControllerAdvice; import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException; import org.springframework.web.servlet.NoHandlerFoundException; +import java.io.IOException; + /** * 全局异常处理器 * @@ -89,6 +92,20 @@ public class GlobalExceptionHandler { return R.fail(HttpStatus.HTTP_NOT_FOUND, e.getMessage()); } + /** + * 拦截未知的运行时异常 + */ + @ResponseStatus(org.springframework.http.HttpStatus.INTERNAL_SERVER_ERROR) + @ExceptionHandler(IOException.class) + public void handleRuntimeException(IOException e, HttpServletRequest request) { + String requestURI = request.getRequestURI(); + if (requestURI.contains("sse")) { + // sse 经常性连接中断 例如关闭浏览器 直接屏蔽 + return; + } + log.error("请求地址'{}',连接中断", requestURI, e); + } + /** * 拦截未知的运行时异常 */ diff --git a/ruoyi-common/ruoyi-common-websocket/src/main/java/org/dromara/common/websocket/utils/WebSocketUtils.java b/ruoyi-common/ruoyi-common-websocket/src/main/java/org/dromara/common/websocket/utils/WebSocketUtils.java index 696ac3c5..35320c6e 100644 --- a/ruoyi-common/ruoyi-common-websocket/src/main/java/org/dromara/common/websocket/utils/WebSocketUtils.java +++ b/ruoyi-common/ruoyi-common-websocket/src/main/java/org/dromara/common/websocket/utils/WebSocketUtils.java @@ -113,7 +113,7 @@ public class WebSocketUtils { * @param session WebSocket会话 * @param message 要发送的WebSocket消息对象 */ - private static void sendMessage(WebSocketSession session, WebSocketMessage message) { + private synchronized static void sendMessage(WebSocketSession session, WebSocketMessage message) { if (session == null || !session.isOpen()) { log.warn("[send] session会话已经关闭"); } else { diff --git a/ruoyi-example/ruoyi-demo/pom.xml b/ruoyi-example/ruoyi-demo/pom.xml index f9ca57a6..5238e6ef 100644 --- a/ruoyi-example/ruoyi-demo/pom.xml +++ b/ruoyi-example/ruoyi-demo/pom.xml @@ -82,17 +82,6 @@ ruoyi-common-tenant - - - - - - - - - - - org.dromara ruoyi-common-elasticsearch diff --git a/ruoyi-example/ruoyi-demo/src/main/java/org/dromara/demo/mapper/TestDemoMapper.java b/ruoyi-example/ruoyi-demo/src/main/java/org/dromara/demo/mapper/TestDemoMapper.java index 54a80146..2bee5623 100644 --- a/ruoyi-example/ruoyi-demo/src/main/java/org/dromara/demo/mapper/TestDemoMapper.java +++ b/ruoyi-example/ruoyi-demo/src/main/java/org/dromara/demo/mapper/TestDemoMapper.java @@ -11,6 +11,7 @@ import org.dromara.demo.domain.TestDemo; import org.dromara.demo.domain.vo.TestDemoVo; import org.apache.ibatis.annotations.Param; +import java.io.Serializable; import java.util.Collection; import java.util.List; @@ -44,16 +45,17 @@ public interface TestDemoMapper extends BaseMapperPlus { List selectList(@Param(Constants.WRAPPER) Wrapper queryWrapper); @Override - @DataPermission({ + @DataPermission(value = { @DataColumn(key = "deptName", value = "dept_id"), @DataColumn(key = "userName", value = "user_id") - }) - int updateById(@Param(Constants.ENTITY) TestDemo entity); + }, joinStr = "AND") + List selectBatchIds(@Param(Constants.COLL) Collection idList); @Override @DataPermission({ @DataColumn(key = "deptName", value = "dept_id"), @DataColumn(key = "userName", value = "user_id") }) - int deleteByIds(@Param(Constants.COLL) Collection idList); + int updateById(@Param(Constants.ENTITY) TestDemo entity); + } diff --git a/ruoyi-example/ruoyi-demo/src/main/java/org/dromara/demo/service/impl/TestDemoServiceImpl.java b/ruoyi-example/ruoyi-demo/src/main/java/org/dromara/demo/service/impl/TestDemoServiceImpl.java index 761b337c..f27ec498 100644 --- a/ruoyi-example/ruoyi-demo/src/main/java/org/dromara/demo/service/impl/TestDemoServiceImpl.java +++ b/ruoyi-example/ruoyi-demo/src/main/java/org/dromara/demo/service/impl/TestDemoServiceImpl.java @@ -4,6 +4,7 @@ import cn.hutool.core.bean.BeanUtil; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.toolkit.Wrappers; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import org.dromara.common.core.exception.ServiceException; import org.dromara.common.core.utils.StringUtils; import org.dromara.common.mybatis.core.page.PageQuery; import org.dromara.common.mybatis.core.page.TableDataInfo; @@ -99,7 +100,11 @@ public class TestDemoServiceImpl implements ITestDemoService { @Override public Boolean deleteWithValidByIds(Collection ids, Boolean isValid) { if (isValid) { - //TODO 做一些业务上的校验,判断是否需要校验 + // 做一些业务上的校验,判断是否需要校验 + List list = baseMapper.selectBatchIds(ids); + if (list.size() != ids.size()) { + throw new ServiceException("您没有删除权限!"); + } } return baseMapper.deleteByIds(ids) > 0; } diff --git a/ruoyi-example/ruoyi-test-mq/README.md b/ruoyi-example/ruoyi-test-mq/README.md index 1f7c5fb3..1039f1c2 100644 --- a/ruoyi-example/ruoyi-test-mq/README.md +++ b/ruoyi-example/ruoyi-test-mq/README.md @@ -4,7 +4,7 @@ 1. rabbitmq: 普通消息、延迟队列 2. rocketmq:普通消息、事务消息、延迟消息 -3. kafka:普通消息、stream流的使用 +3. kafka:普通消息 ## 使用方式 diff --git a/ruoyi-example/ruoyi-test-mq/pom.xml b/ruoyi-example/ruoyi-test-mq/pom.xml index a37d75ee..dc29d327 100644 --- a/ruoyi-example/ruoyi-test-mq/pom.xml +++ b/ruoyi-example/ruoyi-test-mq/pom.xml @@ -33,10 +33,6 @@ org.springframework.kafka spring-kafka - - org.apache.kafka - kafka-streams - org.dromara diff --git a/ruoyi-example/ruoyi-test-mq/src/main/java/org/dromara/stream/config/KafkaStreamsConfig.java b/ruoyi-example/ruoyi-test-mq/src/main/java/org/dromara/stream/config/KafkaStreamsConfig.java deleted file mode 100644 index a73cb420..00000000 --- a/ruoyi-example/ruoyi-test-mq/src/main/java/org/dromara/stream/config/KafkaStreamsConfig.java +++ /dev/null @@ -1,29 +0,0 @@ -package org.dromara.stream.config; - -import org.apache.kafka.streams.StreamsBuilder; -import org.apache.kafka.streams.kstream.KStream; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.kafka.annotation.EnableKafkaStreams; - -/** - * kafka stream 配置 - * - * @author LionLi - */ -@Configuration -@EnableKafkaStreams -public class KafkaStreamsConfig { - - @Bean - public KStream demoStream(StreamsBuilder builder) { - // 输入主题 - KStream source = builder.stream("input-topic"); - // 转换逻辑:这里只是简单地将消息转换为大写 - KStream processed = source.mapValues(value -> value.toUpperCase()); - // 输出到另一个主题 - processed.to("output-topic"); - return source; - } - -} diff --git a/ruoyi-example/ruoyi-test-mq/src/main/resources/application.yml b/ruoyi-example/ruoyi-test-mq/src/main/resources/application.yml index f6d578fc..13561bad 100644 --- a/ruoyi-example/ruoyi-test-mq/src/main/resources/application.yml +++ b/ruoyi-example/ruoyi-test-mq/src/main/resources/application.yml @@ -30,11 +30,12 @@ spring: producer: key-serializer: org.apache.kafka.common.serialization.StringSerializer value-serializer: org.apache.kafka.common.serialization.StringSerializer - streams: - properties: - application.id: kafka-streams-id # 应用ID + # 以下配置均应该在 kafka 配置文件内编写 写到此处是为了方便调试 properties: - auto.create.topics.enable: true # 开启自动创建话题功能,默认是false,根据需要设置 + # 开启自动创建话题功能,默认是false,根据需要设置 + auto.create.topics.enable: true + # 默认副本数 1 避免单机使用无法创建 topic + default.replication.factor: 1 --- # rocketmq 配置 rocketmq: diff --git a/ruoyi-gateway/src/main/java/org/dromara/gateway/filter/AuthFilter.java b/ruoyi-gateway/src/main/java/org/dromara/gateway/filter/AuthFilter.java index 943b0bad..d3dbba34 100644 --- a/ruoyi-gateway/src/main/java/org/dromara/gateway/filter/AuthFilter.java +++ b/ruoyi-gateway/src/main/java/org/dromara/gateway/filter/AuthFilter.java @@ -1,12 +1,14 @@ package org.dromara.gateway.filter; import cn.dev33.satoken.exception.NotLoginException; +import cn.dev33.satoken.httpauth.basic.SaHttpBasicUtil; import cn.dev33.satoken.reactor.context.SaReactorSyncHolder; import cn.dev33.satoken.reactor.filter.SaReactorFilter; import cn.dev33.satoken.router.SaRouter; import cn.dev33.satoken.stp.StpUtil; import cn.dev33.satoken.util.SaResult; import org.dromara.common.core.constant.HttpStatus; +import org.dromara.common.core.utils.SpringUtils; import org.dromara.common.core.utils.StringUtils; import org.dromara.common.satoken.utils.LoginHelper; import org.dromara.gateway.config.properties.IgnoreWhiteProperties; @@ -30,7 +32,7 @@ public class AuthFilter { return new SaReactorFilter() // 拦截地址 .addInclude("/**") - .addExclude("/favicon.ico", "/actuator/**") + .addExclude("/favicon.ico", "/actuator", "/actuator/**") // 鉴权方法:每次访问进入 .setAuth(obj -> { // 登录校验 -- 拦截所有路由 @@ -65,4 +67,20 @@ public class AuthFilter { return SaResult.error("认证失败,无法访问系统资源").setCode(HttpStatus.UNAUTHORIZED); }); } + + /** + * 对 actuator 健康检查接口 做账号密码鉴权 + */ + @Bean + public SaReactorFilter actuatorFilter() { + String username = SpringUtils.getProperty("spring.cloud.nacos.discovery.metadata.username"); + String password = SpringUtils.getProperty("spring.cloud.nacos.discovery.metadata.userpassword"); + return new SaReactorFilter() + .addInclude("/actuator", "/actuator/**") + .setAuth(obj -> { + SaHttpBasicUtil.check(username + ":" + password); + }) + .setError(e -> SaResult.error(e.getMessage()).setCode(HttpStatus.UNAUTHORIZED)); + } + } diff --git a/ruoyi-gateway/src/main/java/org/dromara/gateway/filter/GlobalLogFilter.java b/ruoyi-gateway/src/main/java/org/dromara/gateway/filter/GlobalLogFilter.java index 2c776513..fbfa329a 100644 --- a/ruoyi-gateway/src/main/java/org/dromara/gateway/filter/GlobalLogFilter.java +++ b/ruoyi-gateway/src/main/java/org/dromara/gateway/filter/GlobalLogFilter.java @@ -2,11 +2,11 @@ package org.dromara.gateway.filter; import cn.hutool.core.map.MapUtil; import cn.hutool.core.util.ObjectUtil; +import lombok.extern.slf4j.Slf4j; import org.dromara.common.json.utils.JsonUtils; import org.dromara.gateway.config.properties.ApiDecryptProperties; import org.dromara.gateway.config.properties.CustomGatewayProperties; import org.dromara.gateway.utils.WebFluxUtils; -import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.cloud.gateway.filter.GatewayFilterChain; import org.springframework.cloud.gateway.filter.GlobalFilter; @@ -75,6 +75,9 @@ public class GlobalLogFilter implements GlobalFilter, Ordered { @Override public int getOrder() { + // 日志处理器在负载均衡器之后执行 负载均衡器会导致线程切换 无法获取上下文内容 + // 如需在日志内操作线程上下文 例如获取登录用户数据等 可以打开下方注释代码 + // return ReactiveLoadBalancerClientFilter.LOAD_BALANCER_CLIENT_FILTER_ORDER - 1; return Ordered.LOWEST_PRECEDENCE; } diff --git a/ruoyi-modules/ruoyi-gen/pom.xml b/ruoyi-modules/ruoyi-gen/pom.xml index 3450e7cf..adb95a07 100644 --- a/ruoyi-modules/ruoyi-gen/pom.xml +++ b/ruoyi-modules/ruoyi-gen/pom.xml @@ -64,6 +64,37 @@ ruoyi-common-security + + org.anyline + anyline-environment-spring-data-jdbc + ${anyline.version} + + + + org.anyline + anyline-data-jdbc-mysql + ${anyline.version} + + + + + + + + + + + + + + + + + + + + + diff --git a/ruoyi-modules/ruoyi-gen/src/main/java/org/dromara/gen/config/GenConfig.java b/ruoyi-modules/ruoyi-gen/src/main/java/org/dromara/gen/config/GenConfig.java index e973e324..4b4fd16c 100644 --- a/ruoyi-modules/ruoyi-gen/src/main/java/org/dromara/gen/config/GenConfig.java +++ b/ruoyi-modules/ruoyi-gen/src/main/java/org/dromara/gen/config/GenConfig.java @@ -11,6 +11,7 @@ import org.springframework.stereotype.Component; @Component @ConfigurationProperties(prefix = "gen") public class GenConfig { + /** * 作者 */ diff --git a/ruoyi-modules/ruoyi-gen/src/main/java/org/dromara/gen/config/MyBatisDataSourceMonitor.java b/ruoyi-modules/ruoyi-gen/src/main/java/org/dromara/gen/config/MyBatisDataSourceMonitor.java new file mode 100644 index 00000000..f9deedbf --- /dev/null +++ b/ruoyi-modules/ruoyi-gen/src/main/java/org/dromara/gen/config/MyBatisDataSourceMonitor.java @@ -0,0 +1,105 @@ +package org.dromara.gen.config; + +import com.baomidou.dynamic.datasource.DynamicRoutingDataSource; +import com.baomidou.dynamic.datasource.toolkit.DynamicDataSourceContextHolder; +import lombok.extern.slf4j.Slf4j; +import org.anyline.data.datasource.DataSourceMonitor; +import org.anyline.data.runtime.DataRuntime; +import org.anyline.util.ConfigTable; +import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.jdbc.datasource.DataSourceUtils; +import org.springframework.stereotype.Component; + +import javax.sql.DataSource; +import java.sql.Connection; +import java.sql.DatabaseMetaData; +import java.util.HashMap; +import java.util.Map; + +/** + * anyline 适配 动态数据源改造 + * + * @author Lion Li + */ +@Slf4j +@Component +public class MyBatisDataSourceMonitor implements DataSourceMonitor { + + public MyBatisDataSourceMonitor() { + // 调整执行模式为自定义 + ConfigTable.KEEP_ADAPTER = 2; + // 禁用缓存 + ConfigTable.METADATA_CACHE_SCOPE = 0; + } + + private final Map features = new HashMap<>(); + + /** + * 数据源特征 用来定准 adapter 包含数据库或JDBC协议关键字
+ * 一般会通过 产品名_url 合成 如果返回null 上层方法会通过driver_产品名_url合成 + * + * @param datasource 数据源 + * @return String 返回null由上层自动提取 + */ + @Override + public String feature(DataRuntime runtime, Object datasource) { + String feature = null; + if (datasource instanceof JdbcTemplate jdbc) { + DataSource ds = jdbc.getDataSource(); + if (ds instanceof DynamicRoutingDataSource) { + String key = DynamicDataSourceContextHolder.peek(); + feature = features.get(key); + if (null == feature) { + Connection con = null; + try { + con = DataSourceUtils.getConnection(ds); + DatabaseMetaData meta = con.getMetaData(); + String url = meta.getURL(); + feature = meta.getDatabaseProductName().toLowerCase().replace(" ", "") + "_" + url; + features.put(key, feature); + } catch (Exception e) { + log.error(e.getMessage(), e); + } finally { + if (null != con && !DataSourceUtils.isConnectionTransactional(con, ds)) { + DataSourceUtils.releaseConnection(con, ds); + } + } + } + } + } + return feature; + } + + /** + * 数据源唯一标识 如果不实现则默认feature + * @param datasource 数据源 + * @return String 返回null由上层自动提取 + */ + @Override + public String key(DataRuntime runtime, Object datasource) { + if(datasource instanceof JdbcTemplate jdbc){ + DataSource ds = jdbc.getDataSource(); + if(ds instanceof DynamicRoutingDataSource){ + return DynamicDataSourceContextHolder.peek(); + } + } + return runtime.getKey(); + } + + /** + * ConfigTable.KEEP_ADAPTER=2 : 根据当前接口判断是否保持同一个数据源绑定同一个adapter
+ * DynamicRoutingDataSource类型的返回false,因为同一个DynamicRoutingDataSource可能对应多类数据库, 如果项目中只有一种数据库 应该直接返回true + * + * @param datasource 数据源 + * @return boolean + */ + @Override + public boolean keepAdapter(DataRuntime runtime, Object datasource) { + if (datasource instanceof JdbcTemplate jdbc) { + DataSource ds = jdbc.getDataSource(); + return !(ds instanceof DynamicRoutingDataSource); + } + return true; + } + +} diff --git a/ruoyi-modules/ruoyi-gen/src/main/java/org/dromara/gen/controller/GenController.java b/ruoyi-modules/ruoyi-gen/src/main/java/org/dromara/gen/controller/GenController.java index a7c61eb4..c7daa07d 100644 --- a/ruoyi-modules/ruoyi-gen/src/main/java/org/dromara/gen/controller/GenController.java +++ b/ruoyi-modules/ruoyi-gen/src/main/java/org/dromara/gen/controller/GenController.java @@ -56,7 +56,7 @@ public class GenController extends BaseController { GenTable table = genTableService.selectGenTableById(tableId); List tables = genTableService.selectGenTableAll(); List list = genTableService.selectGenTableColumnListByTableId(tableId); - Map map = new HashMap<>(); + Map map = new HashMap<>(3); map.put("info", table); map.put("rows", list); map.put("tables", tables); diff --git a/ruoyi-modules/ruoyi-gen/src/main/java/org/dromara/gen/domain/GenTableColumn.java b/ruoyi-modules/ruoyi-gen/src/main/java/org/dromara/gen/domain/GenTableColumn.java index 52ad6f16..80ef2040 100644 --- a/ruoyi-modules/ruoyi-gen/src/main/java/org/dromara/gen/domain/GenTableColumn.java +++ b/ruoyi-modules/ruoyi-gen/src/main/java/org/dromara/gen/domain/GenTableColumn.java @@ -16,7 +16,6 @@ import org.dromara.common.mybatis.core.domain.BaseEntity; * * @author Lion Li */ - @Data @EqualsAndHashCode(callSuper = true) @TableName("gen_table_column") diff --git a/ruoyi-modules/ruoyi-gen/src/main/java/org/dromara/gen/mapper/GenTableColumnMapper.java b/ruoyi-modules/ruoyi-gen/src/main/java/org/dromara/gen/mapper/GenTableColumnMapper.java index 501f0c2b..eee041a2 100644 --- a/ruoyi-modules/ruoyi-gen/src/main/java/org/dromara/gen/mapper/GenTableColumnMapper.java +++ b/ruoyi-modules/ruoyi-gen/src/main/java/org/dromara/gen/mapper/GenTableColumnMapper.java @@ -1,13 +1,9 @@ package org.dromara.gen.mapper; -import com.baomidou.dynamic.datasource.annotation.DS; import com.baomidou.mybatisplus.annotation.InterceptorIgnore; -import org.apache.ibatis.annotations.Param; import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; import org.dromara.gen.domain.GenTableColumn; -import java.util.List; - /** * 业务字段 数据层 * @@ -15,14 +11,5 @@ import java.util.List; */ @InterceptorIgnore(dataPermission = "true", tenantLine = "true") public interface GenTableColumnMapper extends BaseMapperPlus { - /** - * 根据表名称查询列信息 - * - * @param tableName 表名称 - * @param dataName 数据源名称 - * @return 列信息 - */ - @DS("#dataName") - List selectDbTableColumnsByName(@Param("tableName") String tableName, String dataName); } diff --git a/ruoyi-modules/ruoyi-gen/src/main/java/org/dromara/gen/mapper/GenTableMapper.java b/ruoyi-modules/ruoyi-gen/src/main/java/org/dromara/gen/mapper/GenTableMapper.java index 2567c89f..5911ab20 100644 --- a/ruoyi-modules/ruoyi-gen/src/main/java/org/dromara/gen/mapper/GenTableMapper.java +++ b/ruoyi-modules/ruoyi-gen/src/main/java/org/dromara/gen/mapper/GenTableMapper.java @@ -2,8 +2,6 @@ package org.dromara.gen.mapper; import com.baomidou.dynamic.datasource.annotation.DS; import com.baomidou.mybatisplus.annotation.InterceptorIgnore; -import com.baomidou.mybatisplus.extension.plugins.pagination.Page; -import org.apache.ibatis.annotations.Param; import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; import org.dromara.gen.domain.GenTable; @@ -17,22 +15,6 @@ import java.util.List; @InterceptorIgnore(dataPermission = "true", tenantLine = "true") public interface GenTableMapper extends BaseMapperPlus { - /** - * 查询据库列表 - * - * @param genTable 查询条件 - * @return 数据库表集合 - */ - Page selectPageDbTableList(@Param("page") Page page, @Param("genTable") GenTable genTable); - - /** - * 查询据库列表 - * - * @param tableNames 表名称组 - * @return 数据库表集合 - */ - List selectDbTableListByNames(String[] tableNames); - /** * 查询所有表信息 * diff --git a/ruoyi-modules/ruoyi-gen/src/main/java/org/dromara/gen/service/GenTableServiceImpl.java b/ruoyi-modules/ruoyi-gen/src/main/java/org/dromara/gen/service/GenTableServiceImpl.java index 078a2484..b7ecc23f 100644 --- a/ruoyi-modules/ruoyi-gen/src/main/java/org/dromara/gen/service/GenTableServiceImpl.java +++ b/ruoyi-modules/ruoyi-gen/src/main/java/org/dromara/gen/service/GenTableServiceImpl.java @@ -9,15 +9,20 @@ import com.baomidou.dynamic.datasource.annotation.DSTransactional; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.core.incrementer.IdentifierGenerator; +import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.core.toolkit.Wrappers; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; +import org.anyline.metadata.Column; +import org.anyline.metadata.Table; +import org.anyline.proxy.ServiceProxy; import org.apache.velocity.Template; import org.apache.velocity.VelocityContext; import org.apache.velocity.app.Velocity; import org.dromara.common.core.constant.Constants; import org.dromara.common.core.exception.ServiceException; +import org.dromara.common.core.utils.SpringUtils; import org.dromara.common.core.utils.StreamUtils; import org.dromara.common.core.utils.StringUtils; import org.dromara.common.core.utils.file.FileUtils; @@ -59,6 +64,8 @@ public class GenTableServiceImpl implements IGenTableService { private final GenTableColumnMapper genTableColumnMapper; private final IdentifierGenerator identifierGenerator; + private static final String[] TABLE_IGNORE = new String[]{"sj_", "act_", "flw_", "gen_"}; + /** * 查询业务字段列表 * @@ -95,7 +102,7 @@ public class GenTableServiceImpl implements IGenTableService { Map params = genTable.getParams(); QueryWrapper wrapper = Wrappers.query(); wrapper - .eq(StringUtils.isNotEmpty(genTable.getDataName()),"data_name", genTable.getDataName()) + .eq(StringUtils.isNotEmpty(genTable.getDataName()), "data_name", genTable.getDataName()) .like(StringUtils.isNotBlank(genTable.getTableName()), "lower(table_name)", StringUtils.lowerCase(genTable.getTableName())) .like(StringUtils.isNotBlank(genTable.getTableComment()), "lower(table_comment)", StringUtils.lowerCase(genTable.getTableComment())) .between(params.get("beginTime") != null && params.get("endTime") != null, @@ -103,11 +110,67 @@ public class GenTableServiceImpl implements IGenTableService { return wrapper; } + /** + * 查询数据库列表 + * + * @param genTable 包含查询条件的GenTable对象 + * @param pageQuery 包含分页信息的PageQuery对象 + * @return 包含分页结果的TableDataInfo对象 + */ @DS("#genTable.dataName") @Override public TableDataInfo selectPageDbTableList(GenTable genTable, PageQuery pageQuery) { - genTable.getParams().put("genTableNames",baseMapper.selectTableNameList(genTable.getDataName())); - Page page = baseMapper.selectPageDbTableList(pageQuery.build(), genTable); + // 获取查询条件 + String tableName = genTable.getTableName(); + String tableComment = genTable.getTableComment(); + + LinkedHashMap> tablesMap = ServiceProxy.metadata().tables(); + if (CollUtil.isEmpty(tablesMap)) { + return TableDataInfo.build(); + } + List tableNames = baseMapper.selectTableNameList(genTable.getDataName()); + String[] tableArrays; + if (CollUtil.isNotEmpty(tableNames)) { + tableArrays = tableNames.toArray(new String[0]); + } else { + tableArrays = new String[0]; + } + // 过滤并转换表格数据 + List tables = tablesMap.values().stream() + .filter(x -> !StringUtils.containsAnyIgnoreCase(x.getName(), TABLE_IGNORE)) + .filter(x -> { + if (CollUtil.isEmpty(tableNames)) { + return true; + } + return !StringUtils.equalsAnyIgnoreCase(x.getName(), tableArrays); + }) + .filter(x -> { + boolean nameMatches = true; + boolean commentMatches = true; + // 进行表名称的模糊查询 + if (StringUtils.isNotBlank(tableName)) { + nameMatches = StringUtils.containsIgnoreCase(x.getName(), tableName); + } + // 进行表描述的模糊查询 + if (StringUtils.isNotBlank(tableComment)) { + commentMatches = StringUtils.containsIgnoreCase(x.getComment(), tableComment); + } + // 同时匹配名称和描述 + return nameMatches && commentMatches; + }) + .map(x -> { + GenTable gen = new GenTable(); + gen.setTableName(x.getName()); + gen.setTableComment(x.getComment()); + gen.setCreateTime(x.getCreateTime()); + gen.setUpdateTime(x.getUpdateTime()); + return gen; + }).toList(); + + IPage page = pageQuery.build(); + page.setTotal(tables.size()); + // 手动分页 set数据 + page.setRecords(CollUtil.page((int) page.getCurrent() - 1, (int) page.getSize(), tables)); return TableDataInfo.build(page); } @@ -121,7 +184,29 @@ public class GenTableServiceImpl implements IGenTableService { @DS("#dataName") @Override public List selectDbTableListByNames(String[] tableNames, String dataName) { - return baseMapper.selectDbTableListByNames(tableNames); + Set tableNameSet = new HashSet<>(List.of(tableNames)); + LinkedHashMap> tablesMap = ServiceProxy.metadata().tables(); + + if (CollUtil.isEmpty(tablesMap)) { + return new ArrayList<>(); + } + + List> tableList = tablesMap.values().stream() + .filter(x -> !StringUtils.containsAnyIgnoreCase(x.getName(), TABLE_IGNORE)) + .filter(x -> tableNameSet.contains(x.getName())).toList(); + + if (CollUtil.isEmpty(tableList)) { + return new ArrayList<>(); + } + return tableList.stream().map(x -> { + GenTable gen = new GenTable(); + gen.setDataName(dataName); + gen.setTableName(x.getName()); + gen.setTableComment(x.getComment()); + gen.setCreateTime(x.getCreateTime()); + gen.setUpdateTime(x.getUpdateTime()); + return gen; + }).toList(); } /** @@ -183,7 +268,7 @@ public class GenTableServiceImpl implements IGenTableService { int row = baseMapper.insert(table); if (row > 0) { // 保存列信息 - List genTableColumns = genTableColumnMapper.selectDbTableColumnsByName(tableName, dataName); + List genTableColumns = SpringUtils.getAopProxy(this).selectDbTableColumnsByName(tableName, dataName); List saveColumns = new ArrayList<>(); for (GenTableColumn column : genTableColumns) { GenUtils.initColumnField(column, table); @@ -199,6 +284,32 @@ public class GenTableServiceImpl implements IGenTableService { } } + /** + * 根据表名称查询列信息 + * + * @param tableName 表名称 + * @param dataName 数据源名称 + * @return 列信息 + */ + @DS("#dataName") + @Override + public List selectDbTableColumnsByName(String tableName, String dataName) { + LinkedHashMap columns = ServiceProxy.metadata().columns(tableName); + List tableColumns = new ArrayList<>(); + columns.forEach((columnName, column) -> { + GenTableColumn tableColumn = new GenTableColumn(); + tableColumn.setIsPk(String.valueOf(column.isPrimaryKey())); + tableColumn.setColumnName(column.getName()); + tableColumn.setColumnComment(column.getComment()); + tableColumn.setColumnType(column.getTypeName().toLowerCase()); + tableColumn.setSort(column.getPosition()); + tableColumn.setIsRequired(column.isNullable() == 0 ? "1" : "0"); + tableColumn.setIsIncrement(column.isAutoIncrement() == -1 ? "0" : "1"); + tableColumns.add(tableColumn); + }); + return tableColumns; + } + /** * 预览代码 * @@ -294,7 +405,7 @@ public class GenTableServiceImpl implements IGenTableService { List tableColumns = table.getColumns(); Map tableColumnMap = StreamUtils.toIdentityMap(tableColumns, GenTableColumn::getColumnName); - List dbTableColumns = genTableColumnMapper.selectDbTableColumnsByName(table.getTableName(), table.getDataName()); + List dbTableColumns = SpringUtils.getAopProxy(this).selectDbTableColumnsByName(table.getTableName(), table.getDataName()); if (CollUtil.isEmpty(dbTableColumns)) { throw new ServiceException("同步数据失败,原表结构不存在"); } diff --git a/ruoyi-modules/ruoyi-gen/src/main/java/org/dromara/gen/service/IGenTableService.java b/ruoyi-modules/ruoyi-gen/src/main/java/org/dromara/gen/service/IGenTableService.java index ea23c53d..4389f129 100644 --- a/ruoyi-modules/ruoyi-gen/src/main/java/org/dromara/gen/service/IGenTableService.java +++ b/ruoyi-modules/ruoyi-gen/src/main/java/org/dromara/gen/service/IGenTableService.java @@ -85,6 +85,15 @@ public interface IGenTableService { */ void importGenTable(List tableList, String dataName); + /** + * 根据表名称查询列信息 + * + * @param tableName 表名称 + * @param dataName 数据源名称 + * @return 列信息 + */ + List selectDbTableColumnsByName(String tableName, String dataName); + /** * 预览代码 * diff --git a/ruoyi-modules/ruoyi-gen/src/main/java/org/dromara/gen/util/VelocityUtils.java b/ruoyi-modules/ruoyi-gen/src/main/java/org/dromara/gen/util/VelocityUtils.java index bdb80e18..61cd55e9 100644 --- a/ruoyi-modules/ruoyi-gen/src/main/java/org/dromara/gen/util/VelocityUtils.java +++ b/ruoyi-modules/ruoyi-gen/src/main/java/org/dromara/gen/util/VelocityUtils.java @@ -213,6 +213,9 @@ public class VelocityUtils { importList.add("com.fasterxml.jackson.annotation.JsonFormat"); } else if (!column.isSuperColumn() && GenConstants.TYPE_BIGDECIMAL.equals(column.getJavaType())) { importList.add("java.math.BigDecimal"); + } else if (!column.isSuperColumn() && "imageUpload".equals(column.getHtmlType())) { + importList.add("org.dromara.common.translation.annotation.Translation"); + importList.add("org.dromara.common.translation.constant.TransConstant"); } } return importList; diff --git a/ruoyi-modules/ruoyi-gen/src/main/resources/mapper/generator/GenTableColumnMapper.xml b/ruoyi-modules/ruoyi-gen/src/main/resources/mapper/generator/GenTableColumnMapper.xml index 8fedeb00..f48af47f 100644 --- a/ruoyi-modules/ruoyi-gen/src/main/resources/mapper/generator/GenTableColumnMapper.xml +++ b/ruoyi-modules/ruoyi-gen/src/main/resources/mapper/generator/GenTableColumnMapper.xml @@ -7,72 +7,4 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" - - diff --git a/ruoyi-modules/ruoyi-gen/src/main/resources/mapper/generator/GenTableMapper.xml b/ruoyi-modules/ruoyi-gen/src/main/resources/mapper/generator/GenTableMapper.xml index 858ad30e..14818209 100644 --- a/ruoyi-modules/ruoyi-gen/src/main/resources/mapper/generator/GenTableMapper.xml +++ b/ruoyi-modules/ruoyi-gen/src/main/resources/mapper/generator/GenTableMapper.xml @@ -14,188 +14,25 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" - - - - - - - + where t.table_id = #{tableId} order by c.sort diff --git a/ruoyi-modules/ruoyi-gen/src/main/resources/vm/java/vo.java.vm b/ruoyi-modules/ruoyi-gen/src/main/resources/vm/java/vo.java.vm index f99a2ed9..c896afbe 100644 --- a/ruoyi-modules/ruoyi-gen/src/main/resources/vm/java/vo.java.vm +++ b/ruoyi-modules/ruoyi-gen/src/main/resources/vm/java/vo.java.vm @@ -53,6 +53,13 @@ public class ${ClassName}Vo implements Serializable { #end private $column.javaType $column.javaField; +#if($column.htmlType == "imageUpload") + /** + * ${column.columnComment}Url + */ + @Translation(type = TransConstant.OSS_ID_TO_URL, mapper = "${column.javaField}") + private String ${column.javaField}Url"; +#end #end #end diff --git a/ruoyi-modules/ruoyi-gen/src/main/resources/vm/ts/types.ts.vm b/ruoyi-modules/ruoyi-gen/src/main/resources/vm/ts/types.ts.vm index c3f6ed1f..35a468e8 100644 --- a/ruoyi-modules/ruoyi-gen/src/main/resources/vm/ts/types.ts.vm +++ b/ruoyi-modules/ruoyi-gen/src/main/resources/vm/ts/types.ts.vm @@ -9,6 +9,12 @@ export interface ${BusinessName}VO { #elseif($column.javaType == 'Boolean') boolean; #else string; #end +#if($column.htmlType == "imageUpload") + /** + * ${column.columnComment}Url + */ + ${column.javaField}Url: string; +#end #end #end #if ($table.tree) diff --git a/ruoyi-modules/ruoyi-gen/src/main/resources/vm/vue/index-tree.vue.vm b/ruoyi-modules/ruoyi-gen/src/main/resources/vm/vue/index-tree.vue.vm index d13ef2f2..caf3472e 100644 --- a/ruoyi-modules/ruoyi-gen/src/main/resources/vm/vue/index-tree.vue.vm +++ b/ruoyi-modules/ruoyi-gen/src/main/resources/vm/vue/index-tree.vue.vm @@ -99,9 +99,9 @@ #elseif($column.list && $column.htmlType == "imageUpload") - + #elseif($column.list && $column.dictType && "" != $column.dictType) diff --git a/ruoyi-modules/ruoyi-gen/src/main/resources/vm/vue/index.vue.vm b/ruoyi-modules/ruoyi-gen/src/main/resources/vm/vue/index.vue.vm index 886f4ab7..a92d19ad 100644 --- a/ruoyi-modules/ruoyi-gen/src/main/resources/vm/vue/index.vue.vm +++ b/ruoyi-modules/ruoyi-gen/src/main/resources/vm/vue/index.vue.vm @@ -101,9 +101,9 @@ #elseif($column.list && $column.htmlType == "imageUpload") - + #elseif($column.list && $column.dictType && "" != $column.dictType) diff --git a/ruoyi-modules/ruoyi-resource/pom.xml b/ruoyi-modules/ruoyi-resource/pom.xml index 5e20b624..8a623d66 100644 --- a/ruoyi-modules/ruoyi-resource/pom.xml +++ b/ruoyi-modules/ruoyi-resource/pom.xml @@ -72,17 +72,6 @@ ruoyi-common-sms - - - - - - - - - - - org.dromara ruoyi-common-mybatis @@ -108,6 +97,11 @@ ruoyi-common-websocket + + org.dromara + ruoyi-common-sse + + org.dromara diff --git a/ruoyi-modules/ruoyi-resource/src/main/java/org/dromara/resource/dubbo/RemoteMessageServiceImpl.java b/ruoyi-modules/ruoyi-resource/src/main/java/org/dromara/resource/dubbo/RemoteMessageServiceImpl.java index f3e5e3f8..393f0f5b 100644 --- a/ruoyi-modules/ruoyi-resource/src/main/java/org/dromara/resource/dubbo/RemoteMessageServiceImpl.java +++ b/ruoyi-modules/ruoyi-resource/src/main/java/org/dromara/resource/dubbo/RemoteMessageServiceImpl.java @@ -3,8 +3,8 @@ package org.dromara.resource.dubbo; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.apache.dubbo.config.annotation.DubboService; -import org.dromara.common.websocket.dto.WebSocketMessageDto; -import org.dromara.common.websocket.utils.WebSocketUtils; +import org.dromara.common.sse.dto.SseMessageDto; +import org.dromara.common.sse.utils.SseMessageUtils; import org.dromara.resource.api.RemoteMessageService; import org.springframework.stereotype.Service; @@ -29,10 +29,10 @@ public class RemoteMessageServiceImpl implements RemoteMessageService { */ @Override public void publishMessage(Long sessionKey, String message) { - WebSocketMessageDto dto = new WebSocketMessageDto(); + SseMessageDto dto = new SseMessageDto(); dto.setMessage(message); - dto.setSessionKeys(List.of(sessionKey)); - WebSocketUtils.publishMessage(dto); + dto.setUserIds(List.of(sessionKey)); + SseMessageUtils.publishMessage(dto); } /** @@ -42,7 +42,7 @@ public class RemoteMessageServiceImpl implements RemoteMessageService { */ @Override public void publishAll(String message) { - WebSocketUtils.publishAll(message); + SseMessageUtils.publishAll(message); } } diff --git a/ruoyi-modules/ruoyi-resource/src/main/java/org/dromara/resource/service/impl/SysOssServiceImpl.java b/ruoyi-modules/ruoyi-resource/src/main/java/org/dromara/resource/service/impl/SysOssServiceImpl.java index 0c950189..a05f2a33 100644 --- a/ruoyi-modules/ruoyi-resource/src/main/java/org/dromara/resource/service/impl/SysOssServiceImpl.java +++ b/ruoyi-modules/ruoyi-resource/src/main/java/org/dromara/resource/service/impl/SysOssServiceImpl.java @@ -74,8 +74,9 @@ public class SysOssServiceImpl implements ISysOssService { @Override public List listByIds(Collection ossIds) { List list = new ArrayList<>(); + SysOssServiceImpl ossService = SpringUtils.getAopProxy(this); for (Long id : ossIds) { - SysOssVo vo = getById(id); + SysOssVo vo = ossService.getById(id); if (ObjectUtil.isNotNull(vo)) { try { list.add(this.matchingUrl(vo)); @@ -97,8 +98,9 @@ public class SysOssServiceImpl implements ISysOssService { @Override public String selectUrlByIds(String ossIds) { List list = new ArrayList<>(); + SysOssServiceImpl ossService = SpringUtils.getAopProxy(this); for (Long id : StringUtils.splitTo(ossIds, Convert::toLong)) { - SysOssVo vo = SpringUtils.getAopProxy(this).getById(id); + SysOssVo vo = ossService.getById(id); if (ObjectUtil.isNotNull(vo)) { try { list.add(this.matchingUrl(vo).getUrl()); diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/monitor/SysLogininforController.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/monitor/SysLogininforController.java index 0f23e5c3..2e88bb7a 100644 --- a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/monitor/SysLogininforController.java +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/monitor/SysLogininforController.java @@ -1,23 +1,23 @@ package org.dromara.system.controller.monitor; import cn.dev33.satoken.annotation.SaCheckPermission; +import jakarta.servlet.http.HttpServletResponse; import lombok.RequiredArgsConstructor; -import org.dromara.common.core.constant.GlobalConstants; +import org.dromara.common.core.constant.CacheConstants; import org.dromara.common.core.domain.R; -import org.dromara.common.web.core.BaseController; import org.dromara.common.excel.utils.ExcelUtil; import org.dromara.common.log.annotation.Log; import org.dromara.common.log.enums.BusinessType; import org.dromara.common.mybatis.core.page.PageQuery; import org.dromara.common.mybatis.core.page.TableDataInfo; import org.dromara.common.redis.utils.RedisUtils; +import org.dromara.common.web.core.BaseController; import org.dromara.system.domain.bo.SysLogininforBo; import org.dromara.system.domain.vo.SysLogininforVo; import org.dromara.system.service.ISysLogininforService; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; -import jakarta.servlet.http.HttpServletResponse; import java.util.List; /** @@ -79,7 +79,7 @@ public class SysLogininforController extends BaseController { @Log(title = "账户解锁", businessType = BusinessType.OTHER) @GetMapping("/unlock/{userName}") public R unlock(@PathVariable("userName") String userName) { - String loginName = GlobalConstants.PWD_ERR_CNT_KEY + userName; + String loginName = CacheConstants.PWD_ERR_CNT_KEY + userName; if (RedisUtils.hasKey(loginName)) { RedisUtils.deleteObject(loginName); } diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysDeptController.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysDeptController.java index 07901bce..1855a208 100644 --- a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysDeptController.java +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysDeptController.java @@ -12,6 +12,7 @@ import org.dromara.common.web.core.BaseController; import org.dromara.system.domain.bo.SysDeptBo; import org.dromara.system.domain.vo.SysDeptVo; import org.dromara.system.service.ISysDeptService; +import org.dromara.system.service.ISysPostService; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; @@ -29,6 +30,7 @@ import java.util.List; public class SysDeptController extends BaseController { private final ISysDeptService deptService; + private final ISysPostService postService; /** * 获取部门列表 @@ -117,6 +119,9 @@ public class SysDeptController extends BaseController { if (deptService.checkDeptExistUser(deptId)) { return R.warn("部门存在用户,不允许删除"); } + if (postService.countPostByDeptId(deptId) > 0) { + return R.warn("部门存在岗位,不允许删除"); + } deptService.checkDeptDataScope(deptId); return toAjax(deptService.deleteDeptById(deptId)); } diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysProfileController.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysProfileController.java index 2408bb42..31bc9dfe 100644 --- a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysProfileController.java +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysProfileController.java @@ -13,6 +13,7 @@ import org.dromara.common.encrypt.annotation.ApiEncrypt; import org.dromara.common.idempotent.annotation.RepeatSubmit; import org.dromara.common.log.annotation.Log; import org.dromara.common.log.enums.BusinessType; +import org.dromara.common.mybatis.helper.DataPermissionHelper; import org.dromara.common.satoken.utils.LoginHelper; import org.dromara.common.web.core.BaseController; import org.dromara.resource.api.RemoteFileService; @@ -77,7 +78,8 @@ public class SysProfileController extends BaseController { if (StringUtils.isNotEmpty(user.getEmail()) && !userService.checkEmailUnique(user)) { return R.fail("修改用户'" + username + "'失败,邮箱账号已存在"); } - if (userService.updateUserProfile(user) > 0) { + int rows = DataPermissionHelper.ignore(() -> userService.updateUserProfile(user)); + if (rows > 0) { return R.ok(); } return R.fail("修改个人信息异常,请联系管理员"); diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysTenantController.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysTenantController.java index 86827f5c..8c1d7e52 100644 --- a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysTenantController.java +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysTenantController.java @@ -20,6 +20,7 @@ import org.dromara.common.tenant.helper.TenantHelper; import org.dromara.system.domain.bo.SysTenantBo; import org.dromara.system.domain.vo.SysTenantVo; import org.dromara.system.service.ISysTenantService; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; @@ -39,6 +40,7 @@ import java.util.List; @RequiredArgsConstructor @RestController @RequestMapping("/tenant") +@ConditionalOnProperty(value = "tenant.enable", havingValue = "true") public class SysTenantController extends BaseController { private final ISysTenantService tenantService; diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysTenantPackageController.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysTenantPackageController.java index d01a4b01..0b22db5a 100644 --- a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysTenantPackageController.java +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysTenantPackageController.java @@ -17,6 +17,7 @@ import org.dromara.common.mybatis.core.page.TableDataInfo; import org.dromara.system.domain.bo.SysTenantPackageBo; import org.dromara.system.domain.vo.SysTenantPackageVo; import org.dromara.system.service.ISysTenantPackageService; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; @@ -35,6 +36,7 @@ import java.util.List; @RequiredArgsConstructor @RestController @RequestMapping("/tenant/package") +@ConditionalOnProperty(value = "tenant.enable", havingValue = "true") public class SysTenantPackageController extends BaseController { private final ISysTenantPackageService tenantPackageService; @@ -93,6 +95,9 @@ public class SysTenantPackageController extends BaseController { @RepeatSubmit() @PostMapping() public R add(@Validated(AddGroup.class) @RequestBody SysTenantPackageBo bo) { + if (!tenantPackageService.checkPackageNameUnique(bo)) { + return R.fail("新增套餐'" + bo.getPackageName() + "'失败,套餐名称已存在"); + } return toAjax(tenantPackageService.insertByBo(bo)); } @@ -105,6 +110,9 @@ public class SysTenantPackageController extends BaseController { @RepeatSubmit() @PutMapping() public R edit(@Validated(EditGroup.class) @RequestBody SysTenantPackageBo bo) { + if (!tenantPackageService.checkPackageNameUnique(bo)) { + return R.fail("修改套餐'" + bo.getPackageName() + "'失败,套餐名称已存在"); + } return toAjax(tenantPackageService.updateByBo(bo)); } diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysUserVo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysUserVo.java index d1f40591..86249d20 100644 --- a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysUserVo.java +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysUserVo.java @@ -61,13 +61,13 @@ public class SysUserVo implements Serializable { /** * 用户邮箱 */ - @Sensitive(strategy = SensitiveStrategy.EMAIL) + @Sensitive(strategy = SensitiveStrategy.EMAIL, perms = "system:user:edit") private String email; /** * 手机号码 */ - @Sensitive(strategy = SensitiveStrategy.PHONE) + @Sensitive(strategy = SensitiveStrategy.PHONE, perms = "system:user:edit") private String phonenumber; /** diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/dubbo/RemoteDataScopeServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/dubbo/RemoteDataScopeServiceImpl.java index b09f682c..c26111a6 100644 --- a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/dubbo/RemoteDataScopeServiceImpl.java +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/dubbo/RemoteDataScopeServiceImpl.java @@ -2,6 +2,7 @@ package org.dromara.system.dubbo; import cn.hutool.core.collection.CollUtil; import cn.hutool.core.convert.Convert; +import cn.hutool.core.util.ObjectUtil; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import lombok.RequiredArgsConstructor; import org.apache.dubbo.config.annotation.DubboService; @@ -40,6 +41,9 @@ public class RemoteDataScopeServiceImpl implements RemoteDataScopeService { */ @Override public String getRoleCustom(Long roleId) { + if (ObjectUtil.isNull(roleId)) { + return "-1"; + } List list = roleDeptMapper.selectList( new LambdaQueryWrapper() .select(SysRoleDept::getDeptId) @@ -47,7 +51,7 @@ public class RemoteDataScopeServiceImpl implements RemoteDataScopeService { if (CollUtil.isNotEmpty(list)) { return StreamUtils.join(list, rd -> Convert.toStr(rd.getDeptId())); } - return null; + return "-1"; } /** @@ -58,6 +62,9 @@ public class RemoteDataScopeServiceImpl implements RemoteDataScopeService { */ @Override public String getDeptAndChild(Long deptId) { + if (ObjectUtil.isNull(deptId)) { + return "-1"; + } List deptList = deptMapper.selectList(new LambdaQueryWrapper() .select(SysDept::getDeptId) .apply(DataBaseHelper.findInSet(deptId, "ancestors"))); @@ -66,7 +73,7 @@ public class RemoteDataScopeServiceImpl implements RemoteDataScopeService { if (CollUtil.isNotEmpty(ids)) { return StreamUtils.join(ids, Convert::toStr); } - return null; + return "-1"; } } diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/dubbo/RemoteUserServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/dubbo/RemoteUserServiceImpl.java index 5c017abf..fe2cbe69 100644 --- a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/dubbo/RemoteUserServiceImpl.java +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/dubbo/RemoteUserServiceImpl.java @@ -1,6 +1,7 @@ package org.dromara.system.dubbo; import cn.hutool.core.bean.BeanUtil; +import cn.hutool.core.lang.Opt; import cn.hutool.core.util.ObjectUtil; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import lombok.RequiredArgsConstructor; @@ -10,6 +11,7 @@ import org.dromara.common.core.exception.ServiceException; import org.dromara.common.core.exception.user.UserException; import org.dromara.common.core.utils.DateUtils; import org.dromara.common.core.utils.MapstructUtils; +import org.dromara.common.core.utils.StringUtils; import org.dromara.common.mybatis.helper.DataPermissionHelper; import org.dromara.common.tenant.helper.TenantHelper; import org.dromara.system.api.RemoteUserService; @@ -257,16 +259,13 @@ public class RemoteUserServiceImpl implements RemoteUserService { loginUser.setUserType(userVo.getUserType()); loginUser.setMenuPermission(permissionService.getMenuPermission(userVo.getUserId())); loginUser.setRolePermission(permissionService.getRolePermission(userVo.getUserId())); - TenantHelper.dynamic(userVo.getTenantId(), () -> { - SysDeptVo dept = null; - if (ObjectUtil.isNotNull(userVo.getDeptId())) { - dept = deptService.selectDeptById(userVo.getDeptId()); - } - loginUser.setDeptName(ObjectUtil.isNull(dept) ? "" : dept.getDeptName()); - loginUser.setDeptCategory(ObjectUtil.isNull(dept) ? "" : dept.getDeptCategory()); - List roles = roleService.selectRolesByUserId(userVo.getUserId()); - loginUser.setRoles(BeanUtil.copyToList(roles, RoleDTO.class)); - }); + if (ObjectUtil.isNotNull(userVo.getDeptId())) { + Opt deptOpt = Opt.of(userVo.getDeptId()).map(deptService::selectDeptById); + loginUser.setDeptName(deptOpt.map(SysDeptVo::getDeptName).orElse(StringUtils.EMPTY)); + loginUser.setDeptCategory(deptOpt.map(SysDeptVo::getDeptCategory).orElse(StringUtils.EMPTY)); + } + List roles = roleService.selectRolesByUserId(userVo.getUserId()); + loginUser.setRoles(BeanUtil.copyToList(roles, RoleDTO.class)); return loginUser; } diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysPostService.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysPostService.java index c43f0395..3751b23b 100644 --- a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysPostService.java +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysPostService.java @@ -80,6 +80,14 @@ public interface ISysPostService { */ long countUserPostById(Long postId); + /** + * 通过部门ID查询岗位使用数量 + * + * @param deptId 部门id + * @return 结果 + */ + long countPostByDeptId(Long deptId); + /** * 删除岗位信息 * diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysTenantPackageService.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysTenantPackageService.java index cdb887ca..bd2970c8 100644 --- a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysTenantPackageService.java +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysTenantPackageService.java @@ -45,6 +45,11 @@ public interface ISysTenantPackageService { */ Boolean updateByBo(SysTenantPackageBo bo); + /** + * 校验套餐名称是否唯一 + */ + boolean checkPackageNameUnique(SysTenantPackageBo bo); + /** * 修改套餐状态 */ diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysDeptServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysDeptServiceImpl.java index f4c1a40b..79e89cf6 100644 --- a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysDeptServiceImpl.java +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysDeptServiceImpl.java @@ -77,7 +77,7 @@ public class SysDeptServiceImpl implements ISysDeptService { private LambdaQueryWrapper buildQueryWrapper(SysDeptBo bo) { LambdaQueryWrapper lqw = Wrappers.lambdaQuery(); - lqw.eq(SysDept::getDelFlag, "0"); + lqw.eq(SysDept::getDelFlag, UserConstants.DEL_FLAG_NORMAL); lqw.eq(ObjectUtil.isNotNull(bo.getDeptId()), SysDept::getDeptId, bo.getDeptId()); lqw.eq(ObjectUtil.isNotNull(bo.getParentId()), SysDept::getParentId, bo.getParentId()); lqw.like(StringUtils.isNotBlank(bo.getDeptName()), SysDept::getDeptName, bo.getDeptName()); diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysPostServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysPostServiceImpl.java index b8a7e607..2c38129a 100644 --- a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysPostServiceImpl.java +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysPostServiceImpl.java @@ -177,6 +177,17 @@ public class SysPostServiceImpl implements ISysPostService { return userPostMapper.selectCount(new LambdaQueryWrapper().eq(SysUserPost::getPostId, postId)); } + /** + * 通过部门ID查询岗位使用数量 + * + * @param deptId 部门id + * @return 结果 + */ + @Override + public long countPostByDeptId(Long deptId) { + return baseMapper.selectCount(new LambdaQueryWrapper().eq(SysPost::getDeptId, deptId)); + } + /** * 删除岗位信息 * diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysRoleServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysRoleServiceImpl.java index 49ceacf1..2751c9b6 100644 --- a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysRoleServiceImpl.java +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysRoleServiceImpl.java @@ -293,6 +293,10 @@ public class SysRoleServiceImpl implements ISysRoleService { @Transactional(rollbackFor = Exception.class) public int updateRole(SysRoleBo bo) { SysRole role = MapstructUtils.convert(bo, SysRole.class); + + if (UserConstants.ROLE_DISABLE.equals(role.getStatus()) && this.countUserRoleByRoleId(role.getRoleId()) > 0) { + throw new ServiceException("角色已分配,不能禁用!"); + } // 修改角色信息 baseMapper.updateById(role); // 删除角色与菜单关联 diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysTenantPackageServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysTenantPackageServiceImpl.java index 5fd04af8..d2a72f61 100644 --- a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysTenantPackageServiceImpl.java +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysTenantPackageServiceImpl.java @@ -1,6 +1,7 @@ package org.dromara.system.service.impl; import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.ObjectUtil; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.toolkit.Wrappers; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; @@ -116,6 +117,17 @@ public class SysTenantPackageServiceImpl implements ISysTenantPackageService { return baseMapper.updateById(update) > 0; } + /** + * 校验套餐名称是否唯一 + */ + @Override + public boolean checkPackageNameUnique(SysTenantPackageBo bo) { + boolean exist = baseMapper.exists(new LambdaQueryWrapper() + .eq(SysTenantPackage::getPackageName, bo.getPackageName()) + .ne(ObjectUtil.isNotNull(bo.getPackageId()), SysTenantPackage::getPackageId, bo.getPackageId())); + return !exist; + } + /** * 修改套餐状态 * diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysUserServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysUserServiceImpl.java index 68e4ae85..bacf9ebf 100644 --- a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysUserServiceImpl.java +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysUserServiceImpl.java @@ -23,10 +23,7 @@ import org.dromara.common.mybatis.core.page.PageQuery; import org.dromara.common.mybatis.core.page.TableDataInfo; import org.dromara.common.mybatis.helper.DataBaseHelper; import org.dromara.common.satoken.utils.LoginHelper; -import org.dromara.system.domain.SysDept; -import org.dromara.system.domain.SysUser; -import org.dromara.system.domain.SysUserPost; -import org.dromara.system.domain.SysUserRole; +import org.dromara.system.domain.*; import org.dromara.system.domain.bo.SysUserBo; import org.dromara.system.domain.vo.SysPostVo; import org.dromara.system.domain.vo.SysRoleVo; @@ -188,8 +185,7 @@ public class SysUserServiceImpl implements ISysUserService { @Override public List selectUserByIds(List userIds, Long deptId) { return baseMapper.selectUserList(new LambdaQueryWrapper() - .select(SysUser::getUserId, SysUser::getUserName, SysUser::getNickName) - .eq(SysUser::getStatus, UserConstants.USER_NORMAL) + .select(SysUser::getUserId, SysUser::getUserName, SysUser::getNickName, SysUser::getEmail, SysUser::getPhonenumber) .eq(SysUser::getStatus, UserConstants.USER_NORMAL) .eq(ObjectUtil.isNotNull(deptId), SysUser::getDeptId, deptId) .in(CollUtil.isNotEmpty(userIds), SysUser::getUserId, userIds)); } @@ -470,17 +466,14 @@ public class SysUserServiceImpl implements ISysUserService { */ private void insertUserRole(Long userId, Long[] roleIds, boolean clear) { if (ArrayUtil.isNotEmpty(roleIds)) { - // 判断是否具有此角色的操作权限 - List roles = roleMapper.selectRoleList(new LambdaQueryWrapper<>()); - if (CollUtil.isEmpty(roles)) { - throw new ServiceException("没有权限访问角色的数据"); - } - List roleList = StreamUtils.toList(roles, SysRoleVo::getRoleId); + List roleList = new ArrayList<>(List.of(roleIds)); if (!LoginHelper.isSuperAdmin(userId)) { roleList.remove(UserConstants.SUPER_ADMIN_ID); } - List canDoRoleList = StreamUtils.filter(List.of(roleIds), roleList::contains); - if (CollUtil.isEmpty(canDoRoleList)) { + // 判断是否具有此角色的操作权限 + List roles = roleMapper.selectRoleList( + new QueryWrapper().in("r.role_id", roleList)); + if (CollUtil.isEmpty(roles)) { throw new ServiceException("没有权限访问角色的数据"); } if (clear) { @@ -488,7 +481,7 @@ public class SysUserServiceImpl implements ISysUserService { userRoleMapper.delete(new LambdaQueryWrapper().eq(SysUserRole::getUserId, userId)); } // 新增用户与角色管理 - List list = StreamUtils.toList(canDoRoleList, roleId -> { + List list = StreamUtils.toList(roleList, roleId -> { SysUserRole ur = new SysUserRole(); ur.setUserId(userId); ur.setRoleId(roleId); diff --git a/ruoyi-modules/ruoyi-workflow/pom.xml b/ruoyi-modules/ruoyi-workflow/pom.xml index a41e978c..13fdfc51 100644 --- a/ruoyi-modules/ruoyi-workflow/pom.xml +++ b/ruoyi-modules/ruoyi-workflow/pom.xml @@ -61,7 +61,7 @@ org.apache.xmlgraphics batik-all - 1.10 + 1.17 xalan diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/controller/ActModelController.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/controller/ActModelController.java index 3332f86a..842d3d66 100644 --- a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/controller/ActModelController.java +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/controller/ActModelController.java @@ -18,6 +18,7 @@ import org.dromara.workflow.domain.vo.ModelVo; import org.dromara.workflow.service.IActModelService; import org.flowable.engine.RepositoryService; import org.flowable.engine.repository.Model; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.transaction.annotation.Transactional; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; @@ -36,8 +37,8 @@ import java.util.List; @RequestMapping("/workflow/model") public class ActModelController extends BaseController { - private final RepositoryService repositoryService; - + @Autowired(required = false) + private RepositoryService repositoryService; private final IActModelService actModelService; diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/controller/ActTaskController.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/controller/ActTaskController.java index 7fc9b95f..c7e9474b 100644 --- a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/controller/ActTaskController.java +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/controller/ActTaskController.java @@ -21,6 +21,7 @@ import org.dromara.workflow.service.IActTaskService; import org.dromara.workflow.service.IWfTaskBackNodeService; import org.dromara.workflow.utils.QueryUtils; import org.flowable.engine.TaskService; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; @@ -38,10 +39,9 @@ import java.util.Map; @RequestMapping("/workflow/task") public class ActTaskController extends BaseController { + @Autowired(required = false) + private TaskService taskService; private final IActTaskService actTaskService; - - private final TaskService taskService; - private final IWfTaskBackNodeService wfTaskBackNodeService; diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/ActModelServiceImpl.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/ActModelServiceImpl.java index 8e870f86..290bb8db 100644 --- a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/ActModelServiceImpl.java +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/ActModelServiceImpl.java @@ -39,6 +39,7 @@ import org.flowable.engine.repository.Model; import org.flowable.engine.repository.ModelQuery; import org.flowable.engine.repository.ProcessDefinition; import org.flowable.validation.ValidationError; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -65,7 +66,8 @@ import java.util.zip.ZipOutputStream; @Service public class ActModelServiceImpl implements IActModelService { - private final RepositoryService repositoryService; + @Autowired(required = false) + private RepositoryService repositoryService; private final IWfNodeConfigService wfNodeConfigService; private final IWfDefinitionConfigService wfDefinitionConfigService; diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/ActProcessDefinitionServiceImpl.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/ActProcessDefinitionServiceImpl.java index 6a17289a..77fb257b 100644 --- a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/ActProcessDefinitionServiceImpl.java +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/ActProcessDefinitionServiceImpl.java @@ -37,6 +37,7 @@ import org.flowable.engine.RepositoryService; import org.flowable.engine.history.HistoricProcessInstance; import org.flowable.engine.impl.bpmn.deployer.ResourceNameUtil; import org.flowable.engine.repository.*; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.web.multipart.MultipartFile; @@ -61,8 +62,10 @@ import java.util.zip.ZipInputStream; @Service public class ActProcessDefinitionServiceImpl implements IActProcessDefinitionService { - private final RepositoryService repositoryService; - private final ProcessMigrationService processMigrationService; + @Autowired(required = false) + private RepositoryService repositoryService; + @Autowired(required = false) + private ProcessMigrationService processMigrationService; private final IWfCategoryService wfCategoryService; private final IWfDefinitionConfigService wfDefinitionConfigService; private final WfDefinitionConfigMapper wfDefinitionConfigMapper; @@ -288,6 +291,7 @@ public class ActProcessDefinitionServiceImpl implements IActProcessDefinitionSer Model modelData = repositoryService.newModel(); modelData.setKey(pd.getKey()); modelData.setName(pd.getName()); + modelData.setCategory(pd.getCategory()); modelData.setTenantId(pd.getTenantId()); repositoryService.saveModel(modelData); repositoryService.addModelEditorSource(modelData.getId(), IoUtil.readBytes(inputStream)); @@ -350,8 +354,7 @@ public class ActProcessDefinitionServiceImpl implements IActProcessDefinitionSer initWfDefConfig(); } else { String originalFilename = file.getOriginalFilename(); - String bpmnResourceSuffix = ResourceNameUtil.BPMN_RESOURCE_SUFFIXES[0]; - if (originalFilename.contains(bpmnResourceSuffix)) { + if (StringUtils.containsAny(originalFilename, ResourceNameUtil.BPMN_RESOURCE_SUFFIXES)) { // 文件名 = 流程名称-流程key String[] splitFilename = originalFilename.substring(0, originalFilename.lastIndexOf(".")).split("-"); if (splitFilename.length < 2) { diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/ActProcessInstanceServiceImpl.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/ActProcessInstanceServiceImpl.java index 4b90554a..af7a9a2d 100644 --- a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/ActProcessInstanceServiceImpl.java +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/ActProcessInstanceServiceImpl.java @@ -49,6 +49,7 @@ import org.flowable.engine.task.Comment; import org.flowable.task.api.Task; import org.flowable.task.api.history.HistoricTaskInstance; import org.springframework.beans.BeanUtils; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -70,12 +71,17 @@ import java.util.stream.Collectors; @Service public class ActProcessInstanceServiceImpl implements IActProcessInstanceService { - private final RepositoryService repositoryService; - private final RuntimeService runtimeService; - private final HistoryService historyService; - private final TaskService taskService; + @Autowired(required = false) + private RepositoryService repositoryService; + @Autowired(required = false) + private RuntimeService runtimeService; + @Autowired(required = false) + private HistoryService historyService; + @Autowired(required = false) + private TaskService taskService; + @Autowired(required = false) + private ManagementService managementService; private final IActHiProcinstService actHiProcinstService; - private final ManagementService managementService; private final IWfTaskBackNodeService wfTaskBackNodeService; private final IWfNodeConfigService wfNodeConfigService; private final FlowProcessEventHandler flowProcessEventHandler; diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/ActTaskServiceImpl.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/ActTaskServiceImpl.java index 78cb19d5..f6acba3e 100644 --- a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/ActTaskServiceImpl.java +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/ActTaskServiceImpl.java @@ -53,6 +53,7 @@ import org.flowable.task.api.TaskQuery; import org.flowable.task.api.history.HistoricTaskInstance; import org.flowable.task.service.impl.persistence.entity.TaskEntity; import org.flowable.variable.api.persistence.entity.VariableInstance; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.scheduling.annotation.Async; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -72,11 +73,16 @@ import static org.dromara.workflow.common.constant.FlowConstant.*; @Service public class ActTaskServiceImpl implements IActTaskService { - private final RuntimeService runtimeService; - private final TaskService taskService; - private final HistoryService historyService; - private final IdentityService identityService; - private final ManagementService managementService; + @Autowired(required = false) + private RuntimeService runtimeService; + @Autowired(required = false) + private TaskService taskService; + @Autowired(required = false) + private HistoryService historyService; + @Autowired(required = false) + private IdentityService identityService; + @Autowired(required = false) + private ManagementService managementService; private final ActTaskMapper actTaskMapper; private final IWfTaskBackNodeService wfTaskBackNodeService; private final ActHiTaskinstMapper actHiTaskinstMapper; @@ -264,7 +270,7 @@ public class ActTaskServiceImpl implements IActTaskService { queryWrapper.eq("t.business_status_", BusinessStatusEnum.WAITING.getStatus()); queryWrapper.eq(TenantHelper.isEnable(), "t.tenant_id_", TenantHelper.getTenantId()); String ids = StreamUtils.join(roleIds, x -> "'" + x + "'"); - queryWrapper.and(w1 -> w1.eq("t.assignee_", userId).or(w2 -> w2.isNull("t.assignee_").apply("exists ( select LINK.ID_ from ACT_RU_IDENTITYLINK LINK where LINK.TASK_ID_ = t.ID_ and LINK.TYPE_ = 'candidate' and (LINK.USER_ID_ = {0} or ( LINK.GROUP_ID_ IN ({1}) ) ))", userId, ids))); + queryWrapper.and(w1 -> w1.eq("t.assignee_", userId).or(w2 -> w2.isNull("t.assignee_").apply("exists ( select LINK.ID_ from ACT_RU_IDENTITYLINK LINK where LINK.TASK_ID_ = t.ID_ and LINK.TYPE_ = 'candidate' and (LINK.USER_ID_ = {0} or ( LINK.GROUP_ID_ IN (" + ids + ") ) ))", userId))); if (StringUtils.isNotBlank(taskBo.getName())) { queryWrapper.like("t.name_", taskBo.getName()); } diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/WfCategoryServiceImpl.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/WfCategoryServiceImpl.java index b498262c..e5628232 100644 --- a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/WfCategoryServiceImpl.java +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/WfCategoryServiceImpl.java @@ -15,6 +15,7 @@ import org.flowable.engine.RepositoryService; import org.flowable.engine.repository.Deployment; import org.flowable.engine.repository.Model; import org.flowable.engine.repository.ProcessDefinition; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -32,8 +33,8 @@ import java.util.List; public class WfCategoryServiceImpl implements IWfCategoryService { private final WfCategoryMapper baseMapper; - - private final RepositoryService repositoryService; + @Autowired(required = false) + private RepositoryService repositoryService; /** * 查询流程分类 diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/WorkflowServiceImpl.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/WorkflowServiceImpl.java index 3c17f6e0..86e43965 100644 --- a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/WorkflowServiceImpl.java +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/WorkflowServiceImpl.java @@ -8,6 +8,7 @@ import org.dromara.workflow.service.IActProcessInstanceService; import org.dromara.workflow.service.WorkflowService; import org.dromara.workflow.utils.WorkflowUtils; import org.flowable.engine.RuntimeService; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import java.util.List; @@ -22,8 +23,9 @@ import java.util.Map; @Service public class WorkflowServiceImpl implements WorkflowService { + @Autowired(required = false) + private RuntimeService runtimeService; private final IActProcessInstanceService actProcessInstanceService; - private final RuntimeService runtimeService; private final IActHiProcinstService actHiProcinstService; /** * 运行中的实例 删除程实例,删除历史记录,删除业务与流程关联信息 diff --git a/ruoyi-modules/ruoyi-workflow/src/main/resources/banner.txt b/ruoyi-modules/ruoyi-workflow/src/main/resources/banner.txt index fbd45f53..29aa26c0 100644 --- a/ruoyi-modules/ruoyi-workflow/src/main/resources/banner.txt +++ b/ruoyi-modules/ruoyi-workflow/src/main/resources/banner.txt @@ -1,10 +1,10 @@ Spring Boot Version: ${spring-boot.version} Spring Application Name: ${spring.application.name} - _ _ - (_) | | - _ __ _ _ ___ _ _ _ ______ ___ _ _ ___ | |_ ___ _ __ ___ -| '__|| | | | / _ \ | | | || ||______|/ __|| | | |/ __|| __| / _ \| '_ ` _ \ -| | | |_| || (_) || |_| || | \__ \| |_| |\__ \| |_ | __/| | | | | | -|_| \__,_| \___/ \__, ||_| |___/ \__, ||___/ \__| \___||_| |_| |_| - __/ | __/ | - |___/ |___/ \ No newline at end of file + _ _ __ _ + (_) | | / _| | + _ __ _ _ ___ _ _ _ ________ _____ _ __| | _| |_| | _____ __ +| '__| | | |/ _ \| | | | |______\ \ /\ / / _ \| '__| |/ / _| |/ _ \ \ /\ / / +| | | |_| | (_) | |_| | | \ V V / (_) | | | <| | | | (_) \ V V / +|_| \__,_|\___/ \__, |_| \_/\_/ \___/|_| |_|\_\_| |_|\___/ \_/\_/ + __/ | + |___/ diff --git a/ruoyi-visual/ruoyi-monitor/pom.xml b/ruoyi-visual/ruoyi-monitor/pom.xml index be14c707..2afc02b9 100644 --- a/ruoyi-visual/ruoyi-monitor/pom.xml +++ b/ruoyi-visual/ruoyi-monitor/pom.xml @@ -28,9 +28,21 @@ ruoyi-common-nacos + - org.dromara - ruoyi-common-web + org.springframework.boot + spring-boot-starter-web + + + spring-boot-starter-tomcat + org.springframework.boot + + + + + + org.springframework.boot + spring-boot-starter-undertow diff --git a/ruoyi-visual/ruoyi-monitor/src/main/java/org/dromara/modules/monitor/config/WebSecurityConfigurer.java b/ruoyi-visual/ruoyi-monitor/src/main/java/org/dromara/modules/monitor/config/WebSecurityConfigurer.java index 686200b8..994ca73c 100644 --- a/ruoyi-visual/ruoyi-monitor/src/main/java/org/dromara/modules/monitor/config/WebSecurityConfigurer.java +++ b/ruoyi-visual/ruoyi-monitor/src/main/java/org/dromara/modules/monitor/config/WebSecurityConfigurer.java @@ -39,9 +39,7 @@ public class WebSecurityConfigurer { .authorizeHttpRequests((authorize) -> authorize.requestMatchers( new AntPathRequestMatcher(adminContextPath + "/assets/**"), - new AntPathRequestMatcher(adminContextPath + "/login"), - new AntPathRequestMatcher("/actuator"), - new AntPathRequestMatcher("/actuator/**") + new AntPathRequestMatcher(adminContextPath + "/login") ).permitAll() .anyRequest().authenticated()) .formLogin((formLogin) -> diff --git a/ruoyi-visual/ruoyi-monitor/src/main/java/org/dromara/modules/monitor/notifier/CustomNotifier.java b/ruoyi-visual/ruoyi-monitor/src/main/java/org/dromara/modules/monitor/notifier/CustomNotifier.java index 165e28e7..4bae134d 100644 --- a/ruoyi-visual/ruoyi-monitor/src/main/java/org/dromara/modules/monitor/notifier/CustomNotifier.java +++ b/ruoyi-visual/ruoyi-monitor/src/main/java/org/dromara/modules/monitor/notifier/CustomNotifier.java @@ -4,14 +4,13 @@ import de.codecentric.boot.admin.server.domain.entities.Instance; import de.codecentric.boot.admin.server.domain.entities.InstanceRepository; import de.codecentric.boot.admin.server.domain.events.InstanceEvent; import de.codecentric.boot.admin.server.domain.events.InstanceStatusChangedEvent; -import de.codecentric.boot.admin.server.domain.values.InstanceId; import de.codecentric.boot.admin.server.notify.AbstractEventNotifier; -import io.micrometer.core.lang.NonNullApi; -import lombok.NonNull; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Component; import reactor.core.publisher.Mono; +import static de.codecentric.boot.admin.server.domain.values.StatusInfo.*; + /** * 自定义事件通知处理 * @@ -31,10 +30,25 @@ public class CustomNotifier extends AbstractEventNotifier { return Mono.fromRunnable(() -> { // 实例状态改变事件 if (event instanceof InstanceStatusChangedEvent) { + // 获取实例注册名称 String registName = instance.getRegistration().getName(); + // 获取实例ID String instanceId = event.getInstance().getValue(); + // 获取实例状态 String status = ((InstanceStatusChangedEvent) event).getStatusInfo().getStatus(); - log.info("Instance Status Change: [{}],[{}],[{}]", registName, instanceId, status); + // 获取服务URL + String serviceUrl = instance.getRegistration().getServiceUrl(); + String statusName = switch (status) { + case STATUS_UP -> "服务上线"; // 实例成功启动并可以正常处理请求 + case STATUS_OFFLINE -> "服务离线"; //实例被手动或自动地从服务中移除 + case STATUS_RESTRICTED -> "服务受限"; //表示实例在某些方面受限,可能无法完全提供所有服务 + case STATUS_OUT_OF_SERVICE -> "停止服务状态"; //表示实例已被标记为停止提供服务,可能是计划内维护或测试 + case STATUS_DOWN -> "服务下线"; //实例因崩溃、错误或其他原因停止运行 + case STATUS_UNKNOWN -> "服务未知异常"; //监控系统无法确定实例的当前状态 + default -> "未知状态"; //没有匹配的状态 + }; + log.info("Instance Status Change: 状态名称【{}】, 注册名称【{}】, 实例ID【{}】, 状态【{}】, 服务URL【{}】", + statusName, registName, instanceId, status, serviceUrl); } }); diff --git a/ruoyi-visual/ruoyi-nacos/pom.xml b/ruoyi-visual/ruoyi-nacos/pom.xml index 18f11f8b..21d577c8 100644 --- a/ruoyi-visual/ruoyi-nacos/pom.xml +++ b/ruoyi-visual/ruoyi-nacos/pom.xml @@ -188,21 +188,12 @@ org.springframework.boot spring-boot-starter-web - - spring-boot-starter-tomcat - org.springframework.boot - log4j-to-slf4j org.apache.logging.log4j - - - org.springframework.boot - spring-boot-starter-undertow - org.springframework.boot spring-boot-starter-jdbc diff --git a/ruoyi-visual/ruoyi-nacos/src/main/java/com/alibaba/nacos/config/ActuatorAuthFilter.java b/ruoyi-visual/ruoyi-nacos/src/main/java/com/alibaba/nacos/config/ActuatorAuthFilter.java new file mode 100644 index 00000000..1b857c39 --- /dev/null +++ b/ruoyi-visual/ruoyi-nacos/src/main/java/com/alibaba/nacos/config/ActuatorAuthFilter.java @@ -0,0 +1,63 @@ +package com.alibaba.nacos.config; + +import javax.servlet.*; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.util.Base64; + +public class ActuatorAuthFilter implements Filter { + + private final String username; + private final String password; + + public ActuatorAuthFilter(String username, String password) { + this.username = username; + this.password = password; + } + + @Override + public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { + HttpServletRequest request = (HttpServletRequest) servletRequest; + HttpServletResponse response = (HttpServletResponse) servletResponse; + + // 获取 Authorization 头 + String authHeader = request.getHeader("Authorization"); + + if (authHeader == null || !authHeader.startsWith("Basic ")) { + // 如果没有提供 Authorization 或者格式不对,则返回 401 + response.setHeader("WWW-Authenticate", "Basic realm=\"realm\""); + response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Unauthorized"); + return; + } + + // 解码 Base64 编码的用户名和密码 + String base64Credentials = authHeader.substring("Basic ".length()); + byte[] credDecoded = Base64.getDecoder().decode(base64Credentials); + String credentials = new String(credDecoded, StandardCharsets.UTF_8); + String[] split = credentials.split(":"); + if (split.length != 2) { + response.setHeader("WWW-Authenticate", "Basic realm=\"realm\""); + response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Unauthorized"); + return; + } + // 验证用户名和密码 + if (!username.equals(split[0]) && password.equals(split[1])) { + response.setHeader("WWW-Authenticate", "Basic realm=\"realm\""); + response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Unauthorized"); + return; + } + // 如果认证成功,继续处理请求 + filterChain.doFilter(request, response); + } + + @Override + public void init(FilterConfig filterConfig) { + } + + @Override + public void destroy() { + } + +} diff --git a/ruoyi-visual/ruoyi-nacos/src/main/java/com/alibaba/nacos/config/SecurityConfig.java b/ruoyi-visual/ruoyi-nacos/src/main/java/com/alibaba/nacos/config/SecurityConfig.java new file mode 100644 index 00000000..e38ae3f6 --- /dev/null +++ b/ruoyi-visual/ruoyi-nacos/src/main/java/com/alibaba/nacos/config/SecurityConfig.java @@ -0,0 +1,29 @@ +package com.alibaba.nacos.config; + +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.web.servlet.FilterRegistrationBean; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +/** + * 权限安全配置 + * + * @author Lion Li + */ +@Configuration +public class SecurityConfig { + + @Value("${spring.boot.admin.client.username}") + private String username; + @Value("${spring.boot.admin.client.password}") + private String password; + + @Bean + public FilterRegistrationBean actuatorFilterRegistrationBean() { + FilterRegistrationBean registrationBean = new FilterRegistrationBean<>(); + registrationBean.setFilter(new ActuatorAuthFilter(username, password)); + registrationBean.addUrlPatterns("/actuator", "/actuator/**"); + return registrationBean; + } + +} diff --git a/ruoyi-visual/ruoyi-nacos/src/main/resources/application.properties b/ruoyi-visual/ruoyi-nacos/src/main/resources/application.properties index fa4b52de..f4b94fcf 100644 --- a/ruoyi-visual/ruoyi-nacos/src/main/resources/application.properties +++ b/ruoyi-visual/ruoyi-nacos/src/main/resources/application.properties @@ -88,6 +88,8 @@ spring.boot.admin.client.url=http://127.0.0.1:9100 spring.boot.admin.client.username=ruoyi spring.boot.admin.client.password=123456 spring.boot.admin.client.instance.service-host-type=IP +spring.boot.admin.client.instance.metadata.username: ${spring.boot.admin.client.username} +spring.boot.admin.client.instance.metadata.userpassword: ${spring.boot.admin.client.password} ### Metrics for prometheus management.endpoints.web.exposure.include=* diff --git a/ruoyi-visual/ruoyi-seata-server/Dockerfile b/ruoyi-visual/ruoyi-seata-server/Dockerfile index be9fb62a..46a8c833 100644 --- a/ruoyi-visual/ruoyi-seata-server/Dockerfile +++ b/ruoyi-visual/ruoyi-seata-server/Dockerfile @@ -10,7 +10,7 @@ RUN mkdir -p /ruoyi/seata-server/logs \ WORKDIR /ruoyi/seata-server -ENV TZ=PRC LANG=C.UTF-8 LC_ALL=C.UTF-8 JAVA_OPTS="" +ENV TZ=PRC LANG=C.UTF-8 LC_ALL=C.UTF-8 JAVA_OPTS="" SEATA_IP="" SEATA_PORT="" RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone EXPOSE 7091 diff --git a/ruoyi-visual/ruoyi-seata-server/pom.xml b/ruoyi-visual/ruoyi-seata-server/pom.xml index 61a1e52c..3660f26e 100644 --- a/ruoyi-visual/ruoyi-seata-server/pom.xml +++ b/ruoyi-visual/ruoyi-seata-server/pom.xml @@ -28,10 +28,7 @@ 1.7.1 - 1.82 - 1.2.12 2.7.18 - 0.9.20 7.2 3.8.0 @@ -46,20 +43,6 @@ pom import - - io.seata - seata-bom - ${seata.version} - pom - import - - - io.seata - seata-dependencies - ${seata.version} - pom - import - @@ -69,110 +52,23 @@ org.springframework.boot spring-boot-starter-web - - spring-boot-starter-tomcat - org.springframework.boot - * org.apache.logging.log4j - - - org.springframework.boot - spring-boot-starter-undertow - io.seata - seata-spring-autoconfigure-server + seata-server ${seata.version} - - - - io.seata - seata-core - - - io.seata - seata-config-all - log4j - log4j + slf4j-reload4j + org.slf4j - - io.seata - seata-discovery-all - - - io.seata - seata-serializer-all - - - io.seata - seata-compressor-all - - - - io.seata - seata-metrics-all - - - - io.seata - seata-console - ${seata.version} - - - - - com.alibaba - druid - ${druid.version} - - - org.apache.commons - commons-dbcp2 - - - com.zaxxer - HikariCP - - - com.h2database - h2 - - - com.mysql - mysql-connector-j - - - org.postgresql - postgresql - - - - - com.beust - jcommander - ${jcommander.version} - - - - - com.google.guava - guava - @@ -181,30 +77,12 @@ ${jedis.version} - - com.alibaba - fastjson - - - - - ch.qos.logback - logback-classic - - - ch.qos.logback - logback-core - net.logstash.logback logstash-logback-encoder ${logstash-logback-encoder.version} - - org.codehaus.janino - janino - diff --git a/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/AbstractTCInboundHandler.java b/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/AbstractTCInboundHandler.java deleted file mode 100644 index fdf0d28c..00000000 --- a/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/AbstractTCInboundHandler.java +++ /dev/null @@ -1,327 +0,0 @@ -/* - * Copyright 1999-2019 Seata.io Group. - * - * Licensed 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 io.seata.server; - -import io.seata.common.exception.StoreException; -import io.seata.core.exception.AbstractExceptionHandler; -import io.seata.core.exception.TransactionException; -import io.seata.core.exception.TransactionExceptionCode; -import io.seata.core.model.GlobalStatus; -import io.seata.core.protocol.transaction.*; -import io.seata.core.rpc.RpcContext; -import io.seata.server.session.GlobalSession; -import io.seata.server.session.SessionHolder; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * The type Abstract tc inbound handler. - * - * @author sharajava - */ -public abstract class AbstractTCInboundHandler extends AbstractExceptionHandler implements TCInboundHandler { - - private static final Logger LOGGER = LoggerFactory.getLogger(AbstractTCInboundHandler.class); - - @Override - public GlobalBeginResponse handle(GlobalBeginRequest request, final RpcContext rpcContext) { - GlobalBeginResponse response = new GlobalBeginResponse(); - exceptionHandleTemplate(new AbstractCallback() { - @Override - public void execute(GlobalBeginRequest request, GlobalBeginResponse response) throws TransactionException { - try { - doGlobalBegin(request, response, rpcContext); - } catch (StoreException e) { - throw new TransactionException(TransactionExceptionCode.FailedStore, - String.format("begin global request failed. xid=%s, msg=%s", response.getXid(), e.getMessage()), - e); - } - } - }, request, response); - return response; - } - - /** - * Do global begin. - * - * @param request the request - * @param response the response - * @param rpcContext the rpc context - * @throws TransactionException the transaction exception - */ - protected abstract void doGlobalBegin(GlobalBeginRequest request, GlobalBeginResponse response, - RpcContext rpcContext) throws TransactionException; - - @Override - public GlobalCommitResponse handle(GlobalCommitRequest request, final RpcContext rpcContext) { - GlobalCommitResponse response = new GlobalCommitResponse(); - response.setGlobalStatus(GlobalStatus.Committing); - exceptionHandleTemplate(new AbstractCallback() { - @Override - public void execute(GlobalCommitRequest request, GlobalCommitResponse response) - throws TransactionException { - try { - doGlobalCommit(request, response, rpcContext); - } catch (StoreException e) { - throw new TransactionException(TransactionExceptionCode.FailedStore, - String.format("global commit request failed. xid=%s, msg=%s", request.getXid(), e.getMessage()), - e); - } - } - @Override - public void onTransactionException(GlobalCommitRequest request, GlobalCommitResponse response, - TransactionException tex) { - super.onTransactionException(request, response, tex); - checkTransactionStatus(request, response); - } - - @Override - public void onException(GlobalCommitRequest request, GlobalCommitResponse response, Exception rex) { - super.onException(request, response, rex); - checkTransactionStatus(request, response); - } - - - }, request, response); - return response; - } - - /** - * Do global commit. - * - * @param request the request - * @param response the response - * @param rpcContext the rpc context - * @throws TransactionException the transaction exception - */ - protected abstract void doGlobalCommit(GlobalCommitRequest request, GlobalCommitResponse response, - RpcContext rpcContext) throws TransactionException; - - @Override - public GlobalRollbackResponse handle(GlobalRollbackRequest request, final RpcContext rpcContext) { - GlobalRollbackResponse response = new GlobalRollbackResponse(); - response.setGlobalStatus(GlobalStatus.Rollbacking); - exceptionHandleTemplate(new AbstractCallback() { - @Override - public void execute(GlobalRollbackRequest request, GlobalRollbackResponse response) - throws TransactionException { - try { - doGlobalRollback(request, response, rpcContext); - } catch (StoreException e) { - throw new TransactionException(TransactionExceptionCode.FailedStore, String - .format("global rollback request failed. xid=%s, msg=%s", request.getXid(), e.getMessage()), e); - } - } - - @Override - public void onTransactionException(GlobalRollbackRequest request, GlobalRollbackResponse response, - TransactionException tex) { - super.onTransactionException(request, response, tex); - // may be appears StoreException outer layer method catch - checkTransactionStatus(request, response); - } - - @Override - public void onException(GlobalRollbackRequest request, GlobalRollbackResponse response, Exception rex) { - super.onException(request, response, rex); - // may be appears StoreException outer layer method catch - checkTransactionStatus(request, response); - } - }, request, response); - return response; - } - - /** - * Do global rollback. - * - * @param request the request - * @param response the response - * @param rpcContext the rpc context - * @throws TransactionException the transaction exception - */ - protected abstract void doGlobalRollback(GlobalRollbackRequest request, GlobalRollbackResponse response, - RpcContext rpcContext) throws TransactionException; - - @Override - public BranchRegisterResponse handle(BranchRegisterRequest request, final RpcContext rpcContext) { - BranchRegisterResponse response = new BranchRegisterResponse(); - exceptionHandleTemplate(new AbstractCallback() { - @Override - public void execute(BranchRegisterRequest request, BranchRegisterResponse response) - throws TransactionException { - try { - doBranchRegister(request, response, rpcContext); - } catch (StoreException e) { - throw new TransactionException(TransactionExceptionCode.FailedStore, String - .format("branch register request failed. xid=%s, msg=%s", request.getXid(), e.getMessage()), e); - } - } - }, request, response); - return response; - } - - /** - * Do branch register. - * - * @param request the request - * @param response the response - * @param rpcContext the rpc context - * @throws TransactionException the transaction exception - */ - protected abstract void doBranchRegister(BranchRegisterRequest request, BranchRegisterResponse response, - RpcContext rpcContext) throws TransactionException; - - @Override - public BranchReportResponse handle(BranchReportRequest request, final RpcContext rpcContext) { - BranchReportResponse response = new BranchReportResponse(); - exceptionHandleTemplate(new AbstractCallback() { - @Override - public void execute(BranchReportRequest request, BranchReportResponse response) - throws TransactionException { - try { - doBranchReport(request, response, rpcContext); - } catch (StoreException e) { - throw new TransactionException(TransactionExceptionCode.FailedStore, String - .format("branch report request failed. xid=%s, branchId=%s, msg=%s", request.getXid(), - request.getBranchId(), e.getMessage()), e); - } - } - }, request, response); - return response; - } - - /** - * Do branch report. - * - * @param request the request - * @param rpcContext the rpc context - * @throws TransactionException the transaction exception - */ - protected abstract void doBranchReport(BranchReportRequest request, BranchReportResponse response, - RpcContext rpcContext) throws TransactionException; - - @Override - public GlobalLockQueryResponse handle(GlobalLockQueryRequest request, final RpcContext rpcContext) { - GlobalLockQueryResponse response = new GlobalLockQueryResponse(); - exceptionHandleTemplate(new AbstractCallback() { - @Override - public void execute(GlobalLockQueryRequest request, GlobalLockQueryResponse response) - throws TransactionException { - try { - doLockCheck(request, response, rpcContext); - } catch (StoreException e) { - throw new TransactionException(TransactionExceptionCode.FailedStore, String - .format("global lock query request failed. xid=%s, msg=%s", request.getXid(), e.getMessage()), - e); - } - } - }, request, response); - return response; - } - - /** - * Do lock check. - * - * @param request the request - * @param response the response - * @param rpcContext the rpc context - * @throws TransactionException the transaction exception - */ - protected abstract void doLockCheck(GlobalLockQueryRequest request, GlobalLockQueryResponse response, - RpcContext rpcContext) throws TransactionException; - - @Override - public GlobalStatusResponse handle(GlobalStatusRequest request, final RpcContext rpcContext) { - GlobalStatusResponse response = new GlobalStatusResponse(); - response.setGlobalStatus(GlobalStatus.UnKnown); - exceptionHandleTemplate(new AbstractCallback() { - @Override - public void execute(GlobalStatusRequest request, GlobalStatusResponse response) - throws TransactionException { - try { - doGlobalStatus(request, response, rpcContext); - } catch (StoreException e) { - throw new TransactionException(TransactionExceptionCode.FailedStore, - String.format("global status request failed. xid=%s, msg=%s", request.getXid(), e.getMessage()), - e); - } - } - - @Override - public void onTransactionException(GlobalStatusRequest request, GlobalStatusResponse response, - TransactionException tex) { - super.onTransactionException(request, response, tex); - checkTransactionStatus(request, response); - } - - @Override - public void onException(GlobalStatusRequest request, GlobalStatusResponse response, Exception rex) { - super.onException(request, response, rex); - checkTransactionStatus(request, response); - } - }, request, response); - return response; - } - - /** - * Do global status. - * - * @param request the request - * @param response the response - * @param rpcContext the rpc context - * @throws TransactionException the transaction exception - */ - protected abstract void doGlobalStatus(GlobalStatusRequest request, GlobalStatusResponse response, - RpcContext rpcContext) throws TransactionException; - - @Override - public GlobalReportResponse handle(GlobalReportRequest request, final RpcContext rpcContext) { - GlobalReportResponse response = new GlobalReportResponse(); - response.setGlobalStatus(request.getGlobalStatus()); - exceptionHandleTemplate(new AbstractCallback() { - @Override - public void execute(GlobalReportRequest request, GlobalReportResponse response) - throws TransactionException { - doGlobalReport(request, response, rpcContext); - } - }, request, response); - return response; - } - - /** - * Do global report. - * - * @param request the request - * @param response the response - * @param rpcContext the rpc context - * @throws TransactionException the transaction exception - */ - protected abstract void doGlobalReport(GlobalReportRequest request, GlobalReportResponse response, - RpcContext rpcContext) throws TransactionException; - - private void checkTransactionStatus(AbstractGlobalEndRequest request, AbstractGlobalEndResponse response) { - try { - GlobalSession globalSession = SessionHolder.findGlobalSession(request.getXid(), false); - if (globalSession != null) { - response.setGlobalStatus(globalSession.getStatus()); - } else { - response.setGlobalStatus(GlobalStatus.Finished); - } - } catch (Exception exx) { - LOGGER.error("check transaction status error,{}]", exx.getMessage()); - } - } -} diff --git a/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/ParameterParser.java b/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/ParameterParser.java deleted file mode 100644 index 55690fca..00000000 --- a/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/ParameterParser.java +++ /dev/null @@ -1,200 +0,0 @@ -/* - * Copyright 1999-2019 Seata.io Group. - * - * Licensed 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 io.seata.server; - -import com.beust.jcommander.JCommander; -import com.beust.jcommander.Parameter; -import com.beust.jcommander.ParameterException; -import io.seata.common.util.StringUtils; -import io.seata.config.Configuration; -import io.seata.config.ConfigurationFactory; -import io.seata.server.env.ContainerHelper; -import io.seata.server.store.StoreConfig; - -import static io.seata.config.ConfigurationFactory.ENV_PROPERTY_KEY; - -/** - * The type Parameter parser. - * - * @author xingfudeshi @gmail.com - */ -public class ParameterParser { - - private static final String PROGRAM_NAME - = "sh seata-server.sh(for linux and mac) or cmd seata-server.bat(for windows)"; - - private static final Configuration CONFIG = ConfigurationFactory.getInstance(); - - @Parameter(names = "--help", help = true) - private boolean help; - @Parameter(names = {"--host", "-h"}, description = "The ip to register to registry center.", order = 1) - private String host; - @Parameter(names = {"--port", "-p"}, description = "The port to listen.", order = 2) - private int port; - @Parameter(names = {"--storeMode", "-m"}, description = "log store mode : file, db, redis", order = 3) - private String storeMode; - @Parameter(names = {"--serverNode", "-n"}, description = "server node id, such as 1, 2, 3.it will be generated according to the snowflake by default", order = 4) - private Long serverNode; - @Parameter(names = {"--seataEnv", "-e"}, description = "The name used for multi-configuration isolation.", - order = 5) - private String seataEnv; - @Parameter(names = {"--sessionStoreMode", "-ssm"}, description = "session log store mode : file, db, redis", - order = 6) - private String sessionStoreMode; - @Parameter(names = {"--lockStoreMode", "-lsm"}, description = "lock log store mode : file, db, redis", order = 7) - private String lockStoreMode; - - /** - * Instantiates a new Parameter parser. - * - * @param args the args - */ - public ParameterParser(String... args) { - this.init(args); - } - - /** - * startup args > docker env - * @param args - */ - private void init(String[] args) { - try { - getCommandParameters(args); - getEnvParameters(); - if (StringUtils.isNotBlank(seataEnv)) { - System.setProperty(ENV_PROPERTY_KEY, seataEnv); - } - StoreConfig.setStartupParameter(storeMode, sessionStoreMode, lockStoreMode); - } catch (ParameterException e) { - printError(e); - } - - } - - private void getCommandParameters(String[] args) { - JCommander jCommander = JCommander.newBuilder().addObject(this).build(); - jCommander.parse(args); - if (help) { - jCommander.setProgramName(PROGRAM_NAME); - jCommander.usage(); - System.exit(0); - } - } - - private void getEnvParameters() { - if (StringUtils.isBlank(seataEnv)) { - seataEnv = ContainerHelper.getEnv(); - } - if (StringUtils.isBlank(host)) { - host = ContainerHelper.getHost(); - } - if (port == 0) { - port = ContainerHelper.getPort(); - } - if (serverNode == null) { - serverNode = ContainerHelper.getServerNode(); - } - } - - private void printError(ParameterException e) { - System.err.println("Option error " + e.getMessage()); - e.getJCommander().setProgramName(PROGRAM_NAME); - e.usage(); - System.exit(0); - } - - /** - * Gets host. - * - * @return the host - */ - public String getHost() { - return host; - } - - /** - * Gets port. - * - * @return the port - */ - public int getPort() { - return port; - } - - /** - * Gets store mode. - * - * @return the store mode - */ - public String getStoreMode() { - return storeMode; - } - - /** - * Gets lock store mode. - * - * @return the store mode - */ - public String getLockStoreMode() { - return lockStoreMode; - } - - /** - * Gets session store mode. - * - * @return the store mode - */ - public String getSessionStoreMode() { - return sessionStoreMode; - } - - /** - * Is help boolean. - * - * @return the boolean - */ - public boolean isHelp() { - return help; - } - - /** - * Gets server node. - * - * @return the server node - */ - public Long getServerNode() { - return serverNode; - } - - /** - * Gets seata env - * - * @return the name used for multi-configuration isolation. - */ - public String getSeataEnv() { - return seataEnv; - } - - /** - * Clean up. - */ - public void cleanUp() { - if (null != System.getProperty(ENV_PROPERTY_KEY)) { - System.clearProperty(ENV_PROPERTY_KEY); - } - } - -} diff --git a/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/Server.java b/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/Server.java deleted file mode 100644 index 81eb1119..00000000 --- a/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/Server.java +++ /dev/null @@ -1,89 +0,0 @@ -/* - * Copyright 1999-2019 Seata.io Group. - * - * Licensed 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 io.seata.server; - -import io.seata.common.XID; -import io.seata.common.thread.NamedThreadFactory; -import io.seata.common.util.NetUtil; -import io.seata.common.util.StringUtils; -import io.seata.config.ConfigurationFactory; -import io.seata.core.rpc.netty.NettyRemotingServer; -import io.seata.core.rpc.netty.NettyServerConfig; -import io.seata.server.coordinator.DefaultCoordinator; -import io.seata.server.lock.LockerManagerFactory; -import io.seata.server.metrics.MetricsManager; -import io.seata.server.session.SessionHolder; - -import java.util.concurrent.LinkedBlockingQueue; -import java.util.concurrent.ThreadPoolExecutor; -import java.util.concurrent.TimeUnit; - -import static io.seata.spring.boot.autoconfigure.StarterConstants.REGEX_SPLIT_CHAR; -import static io.seata.spring.boot.autoconfigure.StarterConstants.REGISTRY_PREFERED_NETWORKS; - -/** - * The type Server. - * - * @author slievrly - */ -public class Server { - /** - * The entry point of application. - * - * @param args the input arguments - */ - public static void start(String[] args) { - //initialize the parameter parser - //Note that the parameter parser should always be the first line to execute. - //Because, here we need to parse the parameters needed for startup. - ParameterParser parameterParser = new ParameterParser(args); - - //initialize the metrics - MetricsManager.get().init(); - - ThreadPoolExecutor workingThreads = new ThreadPoolExecutor(NettyServerConfig.getMinServerPoolSize(), - NettyServerConfig.getMaxServerPoolSize(), NettyServerConfig.getKeepAliveTime(), TimeUnit.SECONDS, - new LinkedBlockingQueue<>(NettyServerConfig.getMaxTaskQueueSize()), - new NamedThreadFactory("ServerHandlerThread", NettyServerConfig.getMaxServerPoolSize()), new ThreadPoolExecutor.CallerRunsPolicy()); - - //127.0.0.1 and 0.0.0.0 are not valid here. - if (NetUtil.isValidIp(parameterParser.getHost(), false)) { - XID.setIpAddress(parameterParser.getHost()); - } else { - String preferredNetworks = ConfigurationFactory.getInstance().getConfig(REGISTRY_PREFERED_NETWORKS); - if (StringUtils.isNotBlank(preferredNetworks)) { - XID.setIpAddress(NetUtil.getLocalIp(preferredNetworks.split(REGEX_SPLIT_CHAR))); - } else { - XID.setIpAddress(NetUtil.getLocalIp()); - } - } - - NettyRemotingServer nettyRemotingServer = new NettyRemotingServer(workingThreads); - XID.setPort(nettyRemotingServer.getListenPort()); - UUIDGenerator.init(parameterParser.getServerNode()); - //log store mode : file, db, redis - SessionHolder.init(); - LockerManagerFactory.init(); - DefaultCoordinator coordinator = DefaultCoordinator.getInstance(nettyRemotingServer); - coordinator.init(); - nettyRemotingServer.setHandler(coordinator); - - // let ServerRunner do destroy instead ShutdownHook, see https://github.com/seata/seata/issues/4028 - ServerRunner.addDisposable(coordinator); - - nettyRemotingServer.init(); - } -} diff --git a/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/ServerRunner.java b/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/ServerRunner.java deleted file mode 100644 index 30343405..00000000 --- a/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/ServerRunner.java +++ /dev/null @@ -1,105 +0,0 @@ -/* - * Copyright 1999-2019 Seata.io Group. - * - * Licensed 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 io.seata.server; - -import io.seata.core.rpc.Disposable; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.DisposableBean; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.boot.CommandLineRunner; -import org.springframework.boot.web.context.WebServerInitializedEvent; -import org.springframework.context.ApplicationEvent; -import org.springframework.context.ApplicationListener; -import org.springframework.core.Ordered; -import org.springframework.stereotype.Component; - -import java.util.List; -import java.util.concurrent.CopyOnWriteArrayList; - - -/** - * @author spilledyear@outlook.com - */ -@Component -public class ServerRunner implements CommandLineRunner, DisposableBean, - ApplicationListener, Ordered { - - private static final Logger LOGGER = LoggerFactory.getLogger(ServerRunner.class); - - private boolean started = Boolean.FALSE; - - private int port; - - @Value("${logging.file.path}") - private String logPath; - - private static final List DISPOSABLE_LIST = new CopyOnWriteArrayList<>(); - - public static void addDisposable(Disposable disposable) { - DISPOSABLE_LIST.add(disposable); - } - - @Override - public void run(String... args) { - try { - long start = System.currentTimeMillis(); - Server.start(args); - started = true; - - long cost = System.currentTimeMillis() - start; - LOGGER.info("\r\n you can visit seata console UI on http://127.0.0.1:{}. \r\n log path: {}.", this.port, this.logPath); - LOGGER.info("seata server started in {} millSeconds", cost); - } catch (Throwable e) { - started = Boolean.FALSE; - LOGGER.error("seata server start error: {} ", e.getMessage(), e); - System.exit(-1); - } - } - - - public boolean started() { - return started; - } - - @Override - public void destroy() throws Exception { - - if (LOGGER.isDebugEnabled()) { - LOGGER.debug("destoryAll starting"); - } - - for (Disposable disposable : DISPOSABLE_LIST) { - disposable.destroy(); - } - - if (LOGGER.isDebugEnabled()) { - LOGGER.debug("destoryAll finish"); - } - } - - @Override - public void onApplicationEvent(ApplicationEvent event) { - if (event instanceof WebServerInitializedEvent) { - this.port = ((WebServerInitializedEvent)event).getWebServer().getPort(); - } - } - - @Override - public int getOrder() { - return Ordered.LOWEST_PRECEDENCE; - } -} diff --git a/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/UUIDGenerator.java b/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/UUIDGenerator.java deleted file mode 100644 index 11aa492e..00000000 --- a/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/UUIDGenerator.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright 1999-2019 Seata.io Group. - * - * Licensed 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 io.seata.server; - -import io.seata.common.util.IdWorker; - -/** - * The type Uuid generator. - * - * @author sharajava - */ -public class UUIDGenerator { - - private static volatile IdWorker idWorker; - - /** - * generate UUID using snowflake algorithm - * @return UUID - */ - public static long generateUUID() { - if (idWorker == null) { - synchronized (UUIDGenerator.class) { - if (idWorker == null) { - init(null); - } - } - } - return idWorker.nextId(); - } - - /** - * init IdWorker - * @param serverNode the server node id, consider as machine id in snowflake - */ - public static void init(Long serverNode) { - idWorker = new IdWorker(serverNode); - } -} diff --git a/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/auth/AbstractCheckAuthHandler.java b/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/auth/AbstractCheckAuthHandler.java deleted file mode 100644 index ecfbfc12..00000000 --- a/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/auth/AbstractCheckAuthHandler.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright 1999-2019 Seata.io Group. - * - * Licensed 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 io.seata.server.auth; - -import io.seata.config.ConfigurationFactory; -import io.seata.core.constants.ConfigurationKeys; -import io.seata.core.protocol.RegisterRMRequest; -import io.seata.core.protocol.RegisterTMRequest; -import io.seata.core.rpc.RegisterCheckAuthHandler; - -import static io.seata.common.DefaultValues.DEFAULT_SERVER_ENABLE_CHECK_AUTH; - -/** - * @author slievrly - */ -public abstract class AbstractCheckAuthHandler implements RegisterCheckAuthHandler { - - private static final Boolean ENABLE_CHECK_AUTH = ConfigurationFactory.getInstance().getBoolean( - ConfigurationKeys.SERVER_ENABLE_CHECK_AUTH, DEFAULT_SERVER_ENABLE_CHECK_AUTH); - - @Override - public boolean regTransactionManagerCheckAuth(RegisterTMRequest request) { - if (!ENABLE_CHECK_AUTH) { - return true; - } - return doRegTransactionManagerCheck(request); - } - - public abstract boolean doRegTransactionManagerCheck(RegisterTMRequest request); - - @Override - public boolean regResourceManagerCheckAuth(RegisterRMRequest request) { - if (!ENABLE_CHECK_AUTH) { - return true; - } - return doRegResourceManagerCheck(request); - } - - public abstract boolean doRegResourceManagerCheck(RegisterRMRequest request); -} diff --git a/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/auth/DefaultCheckAuthHandler.java b/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/auth/DefaultCheckAuthHandler.java deleted file mode 100644 index ed3e9343..00000000 --- a/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/auth/DefaultCheckAuthHandler.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright 1999-2019 Seata.io Group. - * - * Licensed 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 io.seata.server.auth; - -import io.seata.common.loader.LoadLevel; -import io.seata.core.protocol.RegisterRMRequest; -import io.seata.core.protocol.RegisterTMRequest; - -/** - * @author slievrly - */ -@LoadLevel(name = "defaultCheckAuthHandler", order = 100) -public class DefaultCheckAuthHandler extends AbstractCheckAuthHandler { - - @Override - public boolean doRegTransactionManagerCheck(RegisterTMRequest request) { - return true; - } - - @Override - public boolean doRegResourceManagerCheck(RegisterRMRequest request) { - return true; - } -} diff --git a/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/console/controller/BranchSessionController.java b/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/console/controller/BranchSessionController.java deleted file mode 100644 index f3ebf3f6..00000000 --- a/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/console/controller/BranchSessionController.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright 1999-2019 Seata.io Group. - * - * Licensed 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 io.seata.server.console.controller; - -import io.seata.server.console.service.BranchSessionService; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; - -import javax.annotation.Resource; - -/** - * Branch Session Controller - * - * @author zhongxiang.wang - */ -@RestController -@RequestMapping("console/branchSession") -public class BranchSessionController { - - @Resource(type = BranchSessionService.class) - private BranchSessionService branchSessionService; - -} diff --git a/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/console/controller/GlobalLockController.java b/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/console/controller/GlobalLockController.java deleted file mode 100644 index e5fc3d01..00000000 --- a/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/console/controller/GlobalLockController.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright 1999-2019 Seata.io Group. - * - * Licensed 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 io.seata.server.console.controller; - -import io.seata.console.result.PageResult; -import io.seata.server.console.param.GlobalLockParam; -import io.seata.server.console.service.GlobalLockService; -import io.seata.server.console.vo.GlobalLockVO; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.ModelAttribute; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; - -import javax.annotation.Resource; - -/** - * Global Lock Controller - * - * @author zhongxiang.wang - */ -@RestController -@RequestMapping("/api/v1/console/globalLock") -public class GlobalLockController { - - @Resource(type = GlobalLockService.class) - private GlobalLockService globalLockService; - - /** - * Query locks by param - * - * @param param the param - * @return the list of GlobalLockVO - */ - @GetMapping("query") - public PageResult query(@ModelAttribute GlobalLockParam param) { - return globalLockService.query(param); - } - -} diff --git a/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/console/controller/GlobalSessionController.java b/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/console/controller/GlobalSessionController.java deleted file mode 100644 index 14335479..00000000 --- a/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/console/controller/GlobalSessionController.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright 1999-2019 Seata.io Group. - * - * Licensed 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 io.seata.server.console.controller; - -import io.seata.console.result.PageResult; -import io.seata.server.console.param.GlobalSessionParam; -import io.seata.server.console.service.GlobalSessionService; -import io.seata.server.console.vo.GlobalSessionVO; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.ModelAttribute; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; - -import javax.annotation.Resource; - -/** - * Global Session Controller - * - * @author zhongxiang.wang - */ -@RestController -@RequestMapping("/api/v1/console/globalSession") -public class GlobalSessionController { - - @Resource(type = GlobalSessionService.class) - private GlobalSessionService globalSessionService; - - /** - * Query all globalSession - * - * @param param param for query globalSession - * @return the list of GlobalSessionVO - */ - @GetMapping("query") - public PageResult query(@ModelAttribute GlobalSessionParam param) { - return globalSessionService.query(param); - } - -} diff --git a/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/console/impl/db/BranchSessionDBServiceImpl.java b/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/console/impl/db/BranchSessionDBServiceImpl.java deleted file mode 100644 index 963b273c..00000000 --- a/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/console/impl/db/BranchSessionDBServiceImpl.java +++ /dev/null @@ -1,101 +0,0 @@ -/* - * Copyright 1999-2019 Seata.io Group. - * - * Licensed 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 io.seata.server.console.impl.db; - -import io.seata.common.ConfigurationKeys; -import io.seata.common.exception.StoreException; -import io.seata.common.loader.EnhancedServiceLoader; -import io.seata.common.util.IOUtil; -import io.seata.common.util.StringUtils; -import io.seata.config.Configuration; -import io.seata.config.ConfigurationFactory; -import io.seata.console.result.PageResult; -import io.seata.core.store.db.DataSourceProvider; -import io.seata.core.store.db.sql.log.LogStoreSqlsFactory; -import io.seata.server.console.service.BranchSessionService; -import io.seata.server.console.vo.BranchSessionVO; -import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; -import org.springframework.stereotype.Component; - -import javax.sql.DataSource; -import java.sql.Connection; -import java.sql.PreparedStatement; -import java.sql.ResultSet; -import java.sql.SQLException; -import java.util.ArrayList; -import java.util.List; - -import static io.seata.common.DefaultValues.DEFAULT_STORE_DB_BRANCH_TABLE; - -/** - * Branch Session DataBase ServiceImpl - * - * @author zhongxiang.wang - * @author lvekee 734843455@qq.com - */ -@Component -@org.springframework.context.annotation.Configuration -@ConditionalOnExpression("#{'db'.equals('${sessionMode}')}") -public class BranchSessionDBServiceImpl implements BranchSessionService { - - private String branchTable; - - private String dbType; - - private DataSource dataSource; - - public BranchSessionDBServiceImpl() { - Configuration configuration = ConfigurationFactory.getInstance(); - branchTable = configuration.getConfig(ConfigurationKeys.STORE_DB_BRANCH_TABLE, DEFAULT_STORE_DB_BRANCH_TABLE); - dbType = configuration.getConfig(ConfigurationKeys.STORE_DB_TYPE); - if (StringUtils.isBlank(dbType)) { - throw new IllegalArgumentException(ConfigurationKeys.STORE_DB_TYPE + " should not be blank"); - } - String dbDataSource = configuration.getConfig(ConfigurationKeys.STORE_DB_DATASOURCE_TYPE); - if (StringUtils.isBlank(dbDataSource)) { - throw new IllegalArgumentException(ConfigurationKeys.STORE_DB_DATASOURCE_TYPE + " should not be blank"); - } - dataSource = EnhancedServiceLoader.load(DataSourceProvider.class, dbDataSource).provide(); - } - - @Override - public PageResult queryByXid(String xid) { - if (StringUtils.isBlank(xid)) { - throw new IllegalArgumentException("xid should not be blank"); - } - - String whereCondition = " where xid = ? "; - String branchSessionSQL = LogStoreSqlsFactory.getLogStoreSqls(dbType).getAllBranchSessionSQL(branchTable, whereCondition); - - List list = new ArrayList<>(); - ResultSet rs = null; - - try (Connection conn = dataSource.getConnection(); - PreparedStatement ps = conn.prepareStatement(branchSessionSQL)) { - ps.setObject(1, xid); - rs = ps.executeQuery(); - while (rs.next()) { - list.add(BranchSessionVO.convert(rs)); - } - } catch (SQLException e) { - throw new StoreException(e); - } finally { - IOUtil.close(rs); - } - return PageResult.success(list, list.size(), 0, 0, 0); - } - -} diff --git a/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/console/impl/db/GlobalLockDBServiceImpl.java b/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/console/impl/db/GlobalLockDBServiceImpl.java deleted file mode 100644 index 41d61efe..00000000 --- a/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/console/impl/db/GlobalLockDBServiceImpl.java +++ /dev/null @@ -1,145 +0,0 @@ -/* - * Copyright 1999-2019 Seata.io Group. - * - * Licensed 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 io.seata.server.console.impl.db; - -import io.seata.common.ConfigurationKeys; -import io.seata.common.exception.StoreException; -import io.seata.common.loader.EnhancedServiceLoader; -import io.seata.common.util.IOUtil; -import io.seata.common.util.PageUtil; -import io.seata.common.util.StringUtils; -import io.seata.config.Configuration; -import io.seata.config.ConfigurationFactory; -import io.seata.console.result.PageResult; -import io.seata.core.store.db.DataSourceProvider; -import io.seata.core.store.db.sql.lock.LockStoreSqlFactory; -import io.seata.server.console.param.GlobalLockParam; -import io.seata.server.console.service.GlobalLockService; -import io.seata.server.console.vo.GlobalLockVO; -import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; -import org.springframework.stereotype.Component; - -import javax.sql.DataSource; -import java.sql.Connection; -import java.sql.PreparedStatement; -import java.sql.ResultSet; -import java.sql.SQLException; -import java.util.ArrayList; -import java.util.List; - -import static io.seata.common.DefaultValues.DEFAULT_LOCK_DB_TABLE; - - -/** - * Global Lock DB ServiceImpl - * - * @author zhongxiang.wang - * @author lvekee 734843455@qq.com - */ -@Component -@org.springframework.context.annotation.Configuration -@ConditionalOnExpression("#{'db'.equals('${lockMode}')}") -public class GlobalLockDBServiceImpl implements GlobalLockService { - - private String lockTable; - - private String dbType; - - private DataSource dataSource; - - public GlobalLockDBServiceImpl() { - Configuration configuration = ConfigurationFactory.getInstance(); - lockTable = configuration.getConfig(ConfigurationKeys.LOCK_DB_TABLE, DEFAULT_LOCK_DB_TABLE); - dbType = configuration.getConfig(ConfigurationKeys.STORE_DB_TYPE); - if (StringUtils.isBlank(dbType)) { - throw new IllegalArgumentException(ConfigurationKeys.STORE_DB_TYPE + " should not be blank"); - } - String dbDataSource = configuration.getConfig(ConfigurationKeys.STORE_DB_DATASOURCE_TYPE); - if (StringUtils.isBlank(dbDataSource)) { - throw new IllegalArgumentException(ConfigurationKeys.STORE_DB_DATASOURCE_TYPE + " should not be blank"); - } - dataSource = EnhancedServiceLoader.load(DataSourceProvider.class, dbDataSource).provide(); - } - - @Override - public PageResult query(GlobalLockParam param) { - PageUtil.checkParam(param.getPageNum(), param.getPageSize()); - - List sqlParamList = new ArrayList<>(); - String whereCondition = this.getWhereConditionByParam(param, sqlParamList); - - String sourceSql = LockStoreSqlFactory.getLogStoreSql(dbType).getAllLockSql(lockTable, whereCondition); - String queryLockSql = PageUtil.pageSql(sourceSql, dbType, param.getPageNum(), param.getPageSize()); - String lockCountSql = PageUtil.countSql(sourceSql, dbType); - - List list = new ArrayList<>(); - int count = 0; - - ResultSet rs = null; - ResultSet countRs = null; - - try (Connection conn = dataSource.getConnection(); - PreparedStatement ps = conn.prepareStatement(queryLockSql); - PreparedStatement countPs = conn.prepareStatement(lockCountSql)) { - PageUtil.setObject(ps, sqlParamList); - rs = ps.executeQuery(); - while (rs.next()) { - list.add(GlobalLockVO.convert(rs)); - } - PageUtil.setObject(countPs, sqlParamList); - countRs = countPs.executeQuery(); - if (countRs.next()) { - count = countRs.getInt(1); - } - } catch (SQLException e) { - throw new StoreException(e); - } finally { - IOUtil.close(rs, countRs); - } - return PageResult.success(list, count, param.getPageNum(), param.getPageSize()); - } - - private String getWhereConditionByParam(GlobalLockParam param, List sqlParamList) { - StringBuilder whereConditionBuilder = new StringBuilder(); - if (StringUtils.isNotBlank(param.getXid())) { - whereConditionBuilder.append(" and xid = ? "); - sqlParamList.add(param.getXid()); - } - if (StringUtils.isNotBlank(param.getTableName())) { - whereConditionBuilder.append(" and table_name = ? "); - sqlParamList.add(param.getTableName()); - } - if (StringUtils.isNotBlank(param.getTransactionId())) { - whereConditionBuilder.append(" and transaction_id = ? "); - sqlParamList.add(param.getTransactionId()); - } - if (StringUtils.isNotBlank(param.getBranchId())) { - whereConditionBuilder.append(" and branch_id = ? "); - sqlParamList.add(param.getBranchId()); - } - if (param.getTimeStart() != null) { - whereConditionBuilder.append(" and gmt_create >= ? "); - sqlParamList.add(param.getTimeStart()); - } - if (param.getTimeEnd() != null) { - whereConditionBuilder.append(" and gmt_create <= ? "); - sqlParamList.add(param.getTimeEnd()); - } - String whereCondition = whereConditionBuilder.toString(); - return whereCondition.replaceFirst("and", "where"); - } - -} diff --git a/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/console/impl/db/GlobalSessionDBServiceImpl.java b/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/console/impl/db/GlobalSessionDBServiceImpl.java deleted file mode 100644 index 31877347..00000000 --- a/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/console/impl/db/GlobalSessionDBServiceImpl.java +++ /dev/null @@ -1,160 +0,0 @@ -/* - * Copyright 1999-2019 Seata.io Group. - * - * Licensed 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 io.seata.server.console.impl.db; - -import io.seata.common.ConfigurationKeys; -import io.seata.common.exception.StoreException; -import io.seata.common.loader.EnhancedServiceLoader; -import io.seata.common.util.IOUtil; -import io.seata.common.util.PageUtil; -import io.seata.common.util.StringUtils; -import io.seata.config.Configuration; -import io.seata.config.ConfigurationFactory; -import io.seata.console.result.PageResult; -import io.seata.core.store.db.DataSourceProvider; -import io.seata.core.store.db.sql.log.LogStoreSqlsFactory; -import io.seata.server.console.param.GlobalSessionParam; -import io.seata.server.console.service.BranchSessionService; -import io.seata.server.console.service.GlobalSessionService; -import io.seata.server.console.vo.BranchSessionVO; -import io.seata.server.console.vo.GlobalSessionVO; -import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; -import org.springframework.stereotype.Component; - -import javax.annotation.Resource; -import javax.sql.DataSource; -import java.sql.Connection; -import java.sql.PreparedStatement; -import java.sql.ResultSet; -import java.sql.SQLException; -import java.util.ArrayList; -import java.util.Date; -import java.util.HashSet; -import java.util.List; - -import static io.seata.common.DefaultValues.DEFAULT_STORE_DB_GLOBAL_TABLE; - -/** - * Global Session DataBase ServiceImpl - * - * @author zhongxiang.wang - * @author lvekee 734843455@qq.com - */ -@Component -@org.springframework.context.annotation.Configuration -@ConditionalOnExpression("#{'db'.equals('${sessionMode}')}") -public class GlobalSessionDBServiceImpl implements GlobalSessionService { - - private String globalTable; - - private String dbType; - - private DataSource dataSource; - - @Resource(type = BranchSessionService.class) - private BranchSessionService branchSessionService; - - public GlobalSessionDBServiceImpl() { - Configuration configuration = ConfigurationFactory.getInstance(); - globalTable = configuration.getConfig(ConfigurationKeys.STORE_DB_GLOBAL_TABLE, DEFAULT_STORE_DB_GLOBAL_TABLE); - dbType = configuration.getConfig(ConfigurationKeys.STORE_DB_TYPE); - if (StringUtils.isBlank(dbType)) { - throw new IllegalArgumentException(ConfigurationKeys.STORE_DB_TYPE + " should not be blank"); - } - String dbDataSource = configuration.getConfig(ConfigurationKeys.STORE_DB_DATASOURCE_TYPE); - if (StringUtils.isBlank(dbDataSource)) { - throw new IllegalArgumentException(ConfigurationKeys.STORE_DB_DATASOURCE_TYPE + " should not be blank"); - } - dataSource = EnhancedServiceLoader.load(DataSourceProvider.class, dbDataSource).provide(); - } - - @Override - public PageResult query(GlobalSessionParam param) { - PageUtil.checkParam(param.getPageNum(), param.getPageSize()); - - List sqlParamList = new ArrayList<>(); - String whereCondition = getWhereConditionByParam(param, sqlParamList); - - String sourceSql = LogStoreSqlsFactory.getLogStoreSqls(dbType).getAllGlobalSessionSql(globalTable, whereCondition); - String querySessionSql = PageUtil.pageSql(sourceSql, dbType, param.getPageNum(), param.getPageSize()); - String sessionCountSql = PageUtil.countSql(sourceSql, dbType); - - List list = new ArrayList<>(); - int count = 0; - - - ResultSet rs = null; - ResultSet countRs = null; - - try (Connection conn = dataSource.getConnection(); - PreparedStatement ps = conn.prepareStatement(querySessionSql); - PreparedStatement countPs = conn.prepareStatement(sessionCountSql)) { - PageUtil.setObject(ps, sqlParamList); - rs = ps.executeQuery(); - while (rs.next()) { - list.add(GlobalSessionVO.convert(rs)); - } - - PageUtil.setObject(countPs, sqlParamList); - countRs = countPs.executeQuery(); - if (countRs.next()) { - count = countRs.getInt(1); - } - if (param.isWithBranch()) { - for (GlobalSessionVO globalSessionVO : list) { - PageResult pageResp = branchSessionService.queryByXid(globalSessionVO.getXid()); - globalSessionVO.setBranchSessionVOs(new HashSet<>(pageResp.getData())); - } - } - } catch (SQLException e) { - throw new StoreException(e); - } finally { - IOUtil.close(rs, countRs); - } - return PageResult.success(list, count, param.getPageNum(), param.getPageSize()); - } - - private String getWhereConditionByParam(GlobalSessionParam param, List sqlParamList) { - StringBuilder whereConditionBuilder = new StringBuilder(); - if (StringUtils.isNotBlank(param.getXid())) { - whereConditionBuilder.append(" and xid = ? "); - sqlParamList.add(param.getXid()); - } - if (StringUtils.isNotBlank(param.getApplicationId())) { - whereConditionBuilder.append(" and application_id = ? "); - sqlParamList.add(param.getApplicationId()); - } - if (param.getStatus() != null) { - whereConditionBuilder.append(" and status = ? "); - sqlParamList.add(param.getStatus()); - } - if (StringUtils.isNotBlank(param.getTransactionName())) { - whereConditionBuilder.append(" and transaction_name = ? "); - sqlParamList.add(param.getTransactionName()); - } - if (param.getTimeStart() != null) { - whereConditionBuilder.append(" and gmt_create >= ? "); - sqlParamList.add(new Date(param.getTimeStart())); - } - if (param.getTimeEnd() != null) { - whereConditionBuilder.append(" and gmt_create <= ? "); - sqlParamList.add(new Date(param.getTimeEnd())); - } - String whereCondition = whereConditionBuilder.toString(); - return whereCondition.replaceFirst("and", "where"); - } - -} diff --git a/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/console/impl/file/BranchSessionFileServiceImpl.java b/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/console/impl/file/BranchSessionFileServiceImpl.java deleted file mode 100644 index 2f710d0e..00000000 --- a/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/console/impl/file/BranchSessionFileServiceImpl.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright 1999-2019 Seata.io Group. - * - * Licensed 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 io.seata.server.console.impl.file; - -import io.seata.common.exception.NotSupportYetException; -import io.seata.console.result.PageResult; -import io.seata.server.console.service.BranchSessionService; -import io.seata.server.console.vo.BranchSessionVO; -import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; -import org.springframework.stereotype.Component; - -/** - * Branch Session File ServiceImpl - * - * @author zhongxiang.wang - */ -@Component -@org.springframework.context.annotation.Configuration -@ConditionalOnExpression("#{'file'.equals('${sessionMode}')}") -public class BranchSessionFileServiceImpl implements BranchSessionService { - - @Override - public PageResult queryByXid(String xid) { - throw new NotSupportYetException(); - } -} diff --git a/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/console/impl/file/GlobalLockFileServiceImpl.java b/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/console/impl/file/GlobalLockFileServiceImpl.java deleted file mode 100644 index d3c3f18b..00000000 --- a/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/console/impl/file/GlobalLockFileServiceImpl.java +++ /dev/null @@ -1,173 +0,0 @@ -/* - * Copyright 1999-2019 Seata.io Group. - * - * Licensed 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 io.seata.server.console.impl.file; - -import io.seata.common.util.CollectionUtils; -import io.seata.common.util.StringUtils; -import io.seata.console.result.PageResult; -import io.seata.core.lock.RowLock; -import io.seata.server.console.param.GlobalLockParam; -import io.seata.server.console.service.GlobalLockService; -import io.seata.server.console.vo.GlobalLockVO; -import io.seata.server.lock.LockerManagerFactory; -import io.seata.server.session.BranchSession; -import io.seata.server.session.GlobalSession; -import io.seata.server.session.SessionHolder; -import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; -import org.springframework.stereotype.Component; - -import java.util.Collection; -import java.util.List; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.function.Predicate; -import java.util.stream.Collectors; -import java.util.stream.Stream; - -import static io.seata.common.util.StringUtils.isBlank; -import static io.seata.server.console.vo.GlobalLockVO.convert; -import static java.util.Objects.isNull; - -/** - * Global Lock File ServiceImpl - * - * @author zhongxiang.wang - * @author miaoxueyu - */ -@Component -@org.springframework.context.annotation.Configuration -@ConditionalOnExpression("#{'file'.equals('${lockMode}')}") -public class GlobalLockFileServiceImpl implements GlobalLockService { - - @Override - public PageResult query(GlobalLockParam param) { - checkParam(param); - - final Collection allSessions = SessionHolder.getRootSessionManager().allSessions(); - - final AtomicInteger total = new AtomicInteger(); - List result = allSessions - .parallelStream() - .filter(obtainGlobalSessionPredicate(param)) - .flatMap(globalSession -> globalSession.getBranchSessions().stream()) - .filter(obtainBranchSessionPredicate(param)) - .flatMap(branchSession -> filterAndMap(param, branchSession)) - .peek(globalSession -> total.incrementAndGet()) - .collect(Collectors.toList()); - - return PageResult.build(convert(result), param.getPageNum(), param.getPageSize()); - - } - - /** - * filter with tableName and generate RowLock - * - * @param param the query param - * @param branchSession the branch session - * @return the RowLock list - */ - private Stream filterAndMap(GlobalLockParam param, BranchSession branchSession) { - if (CollectionUtils.isEmpty(branchSession.getLockHolder())) { - return Stream.empty(); - } - - final String tableName = param.getTableName(); - - // get rowLock from branchSession - final List rowLocks = LockerManagerFactory.getLockManager().collectRowLocks(branchSession); - - if (StringUtils.isNotBlank(tableName)) { - return rowLocks.parallelStream().filter(rowLock -> rowLock.getTableName().contains(param.getTableName())); - } - - return rowLocks.stream(); - } - - - /** - * check the param - * - * @param param the param - */ - private void checkParam(GlobalLockParam param) { - if (param.getPageSize() <= 0 || param.getPageNum() <= 0) { - throw new IllegalArgumentException("wrong pageSize or pageNum"); - } - - // verification data type - try { - Long.parseLong(param.getTransactionId()); - } catch (NumberFormatException e) { - param.setTransactionId(null); - } - try { - Long.parseLong(param.getBranchId()); - } catch (NumberFormatException e) { - param.setBranchId(null); - } - - - } - - /** - * obtain the branch session condition - * - * @param param condition for query branch session - * @return the filter condition - */ - private Predicate obtainBranchSessionPredicate(GlobalLockParam param) { - return branchSession -> { - // transactionId - return (isBlank(param.getTransactionId()) || - String.valueOf(branchSession.getTransactionId()).contains(param.getTransactionId())) - - && - // branch id - (isBlank(param.getBranchId()) || - String.valueOf(branchSession.getBranchId()).contains(param.getBranchId())) - ; - }; - } - - - /** - * obtain the global session condition - * - * @param param condition for query global session - * @return the filter condition - */ - private Predicate obtainGlobalSessionPredicate(GlobalLockParam param) { - - return globalSession -> { - // first, there must be withBranchSession - return CollectionUtils.isNotEmpty(globalSession.getBranchSessions()) - - && - // The second is other conditions - // xid - (isBlank(param.getXid()) || globalSession.getXid().contains(param.getXid())) - - && - // timeStart - (isNull(param.getTimeStart()) || param.getTimeStart() <= globalSession.getBeginTime()) - - && - // timeEnd - (isNull(param.getTimeEnd()) || param.getTimeEnd() >= globalSession.getBeginTime()); - }; - } - - -} diff --git a/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/console/impl/file/GlobalSessionFileServiceImpl.java b/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/console/impl/file/GlobalSessionFileServiceImpl.java deleted file mode 100644 index 51ece1d5..00000000 --- a/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/console/impl/file/GlobalSessionFileServiceImpl.java +++ /dev/null @@ -1,102 +0,0 @@ -/* - * Copyright 1999-2019 Seata.io Group. - * - * Licensed 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 io.seata.server.console.impl.file; - -import io.seata.console.result.PageResult; -import io.seata.server.console.param.GlobalSessionParam; -import io.seata.server.console.service.GlobalSessionService; -import io.seata.server.console.vo.GlobalSessionVO; -import io.seata.server.session.GlobalSession; -import io.seata.server.session.SessionHolder; -import io.seata.server.storage.SessionConverter; -import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; -import org.springframework.stereotype.Component; - -import java.util.Collection; -import java.util.List; -import java.util.Objects; -import java.util.function.Predicate; -import java.util.stream.Collectors; - -import static io.seata.common.util.StringUtils.isBlank; -import static java.util.Objects.isNull; - -/** - * Global Session File ServiceImpl - * - * @author zhongxiang.wang - * @author miaoxueyu - */ -@Component -@org.springframework.context.annotation.Configuration -@ConditionalOnExpression("#{'file'.equals('${sessionMode}')}") -public class GlobalSessionFileServiceImpl implements GlobalSessionService { - - @Override - public PageResult query(GlobalSessionParam param) { - if (param.getPageSize() <= 0 || param.getPageNum() <= 0) { - throw new IllegalArgumentException("wrong pageSize or pageNum"); - } - - final Collection allSessions = SessionHolder.getRootSessionManager().allSessions(); - - final List filteredSessions = allSessions - .parallelStream() - .filter(obtainPredicate(param)) - .collect(Collectors.toList()); - - return PageResult.build(SessionConverter.convertGlobalSession(filteredSessions), param.getPageNum(), param.getPageSize()); - } - - - - /** - * obtain the condition - * - * @param param condition for query global session - * @return the filter condition - */ - private Predicate obtainPredicate(GlobalSessionParam param) { - - return session -> { - return - // xid - (isBlank(param.getXid()) || session.getXid().contains(param.getXid())) - - && - // applicationId - (isBlank(param.getApplicationId()) || session.getApplicationId().contains(param.getApplicationId())) - - && - // status - (isNull(param.getStatus()) || Objects.equals(session.getStatus().getCode(), param.getStatus())) - - && - // transactionName - (isBlank(param.getTransactionName()) || session.getTransactionName().contains(param.getTransactionName())) - - && - // timeStart - (isNull(param.getTimeStart()) || param.getTimeStart() <= session.getBeginTime()) - - && - // timeEnd - (isNull(param.getTimeEnd()) || param.getTimeEnd() >= session.getBeginTime()); - - }; - } - -} diff --git a/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/console/impl/redis/BranchSessionRedisServiceImpl.java b/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/console/impl/redis/BranchSessionRedisServiceImpl.java deleted file mode 100644 index c8e9e91a..00000000 --- a/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/console/impl/redis/BranchSessionRedisServiceImpl.java +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright 1999-2019 Seata.io Group. - * - * Licensed 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 io.seata.server.console.impl.redis; - -import io.seata.common.util.CollectionUtils; -import io.seata.common.util.StringUtils; -import io.seata.console.result.PageResult; -import io.seata.core.store.BranchTransactionDO; -import io.seata.server.console.service.BranchSessionService; -import io.seata.server.console.vo.BranchSessionVO; -import io.seata.server.storage.redis.store.RedisTransactionStoreManager; -import org.springframework.beans.BeanUtils; -import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; -import org.springframework.stereotype.Component; - -import java.util.ArrayList; -import java.util.List; - -/** - * Branch Session Redis ServiceImpl - * - * @author zhongxiang.wang - * @author doubleDimple - */ -@Component -@org.springframework.context.annotation.Configuration -@ConditionalOnExpression("#{'redis'.equals('${sessionMode}')}") -public class BranchSessionRedisServiceImpl implements BranchSessionService { - - @Override - public PageResult queryByXid(String xid) { - if (StringUtils.isBlank(xid)) { - return PageResult.success(); - } - - List branchSessionVos = new ArrayList<>(); - - RedisTransactionStoreManager instance = RedisTransactionStoreManager.getInstance(); - - List branchSessionDos = instance.findBranchSessionByXid(xid); - - if (CollectionUtils.isNotEmpty(branchSessionDos)) { - for (BranchTransactionDO branchSessionDo : branchSessionDos) { - BranchSessionVO branchSessionVO = new BranchSessionVO(); - BeanUtils.copyProperties(branchSessionDo, branchSessionVO); - branchSessionVos.add(branchSessionVO); - } - } - - return PageResult.success(branchSessionVos, branchSessionVos.size(), 0, branchSessionVos.size()); - } -} diff --git a/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/console/impl/redis/GlobalLockRedisServiceImpl.java b/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/console/impl/redis/GlobalLockRedisServiceImpl.java deleted file mode 100644 index 17f30b89..00000000 --- a/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/console/impl/redis/GlobalLockRedisServiceImpl.java +++ /dev/null @@ -1,119 +0,0 @@ -/* - * Copyright 1999-2019 Seata.io Group. - * - * Licensed 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 io.seata.server.console.impl.redis; - -import io.seata.common.util.BeanUtils; -import io.seata.common.util.CollectionUtils; -import io.seata.console.result.PageResult; -import io.seata.server.console.param.GlobalLockParam; -import io.seata.server.console.service.GlobalLockService; -import io.seata.server.console.vo.GlobalLockVO; -import io.seata.server.storage.redis.JedisPooledFactory; -import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; -import org.springframework.stereotype.Component; -import redis.clients.jedis.Jedis; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import java.util.Map; - -import static io.seata.common.Constants.ROW_LOCK_KEY_SPLIT_CHAR; -import static io.seata.common.exception.FrameworkErrorCode.ParameterRequired; -import static io.seata.common.util.StringUtils.isNotBlank; -import static io.seata.console.result.PageResult.checkPage; -import static io.seata.core.constants.RedisKeyConstants.*; - -/** - * Global Lock Redis Service Impl - * @author zhongxiang.wang - * @author doubleDimple - */ -@Component -@org.springframework.context.annotation.Configuration -@ConditionalOnExpression("#{'redis'.equals('${lockMode}')}") -public class GlobalLockRedisServiceImpl implements GlobalLockService { - - @Override - public PageResult query(GlobalLockParam param) { - - int total = 0; - List globalLockVos; - checkPage(param); - if (isNotBlank(param.getXid())) { - globalLockVos = queryGlobalByXid(param.getXid()); - total = globalLockVos.size(); - return PageResult.success(globalLockVos,total,param.getPageNum(),param.getPageSize()); - } else if (isNotBlank(param.getTableName()) && isNotBlank(param.getPk()) && isNotBlank(param.getResourceId())) { - //SEATA_ROW_LOCK_jdbc:mysql://116.62.62.26/seata-order^^^order^^^2188 - String tableName = param.getTableName(); - String pk = param.getPk(); - String resourceId = param.getResourceId(); - globalLockVos = queryGlobalLockByRowKey(buildRowKey(tableName,pk,resourceId)); - total = globalLockVos.size(); - return PageResult.success(globalLockVos,total,param.getPageNum(),param.getPageSize()); - } else { - return PageResult.failure(ParameterRequired.getErrCode(),"only three parameters of tableName,pk,resourceId or Xid are supported"); - } - } - - private List queryGlobalLockByRowKey(String buildRowKey) { - return readGlobalLockByRowKey(buildRowKey); - } - - private String buildRowKey(String tableName, String pk,String resourceId) { - return DEFAULT_REDIS_SEATA_ROW_LOCK_PREFIX + resourceId + SPLIT + tableName + SPLIT + pk; - } - - - private List queryGlobalByXid(String xid) { - return readGlobalLockByXid(DEFAULT_REDIS_SEATA_GLOBAL_LOCK_PREFIX + xid); - } - - private List readGlobalLockByXid(String key) { - List vos = new ArrayList<>(); - try (Jedis jedis = JedisPooledFactory.getJedisInstance()) { - Map mapGlobalKeys = jedis.hgetAll(key); - if (CollectionUtils.isNotEmpty(mapGlobalKeys)) { - List rowLockKeys = new ArrayList<>(); - mapGlobalKeys.forEach((k,v) -> rowLockKeys.addAll(Arrays.asList(v.split(ROW_LOCK_KEY_SPLIT_CHAR)))); - for (String rowLoclKey : rowLockKeys) { - Map mapRowLockKey = jedis.hgetAll(rowLoclKey); - GlobalLockVO vo = (GlobalLockVO)BeanUtils.mapToObject(mapRowLockKey, GlobalLockVO.class); - if (vo != null) { - vos.add(vo); - } - } - } - } - - return vos; - } - - - private List readGlobalLockByRowKey(String key) { - List vos = new ArrayList<>(); - try (Jedis jedis = JedisPooledFactory.getJedisInstance()) { - Map map = jedis.hgetAll(key); - GlobalLockVO vo = (GlobalLockVO)BeanUtils.mapToObject(map, GlobalLockVO.class); - if (vo != null) { - vos.add(vo); - } - } - return vos; - } - -} diff --git a/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/console/impl/redis/GlobalSessionRedisServiceImpl.java b/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/console/impl/redis/GlobalSessionRedisServiceImpl.java deleted file mode 100644 index 9ca2fdb7..00000000 --- a/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/console/impl/redis/GlobalSessionRedisServiceImpl.java +++ /dev/null @@ -1,110 +0,0 @@ -/* - * Copyright 1999-2019 Seata.io Group. - * - * Licensed 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 io.seata.server.console.impl.redis; - -import io.seata.common.util.CollectionUtils; -import io.seata.console.result.PageResult; -import io.seata.core.model.GlobalStatus; -import io.seata.server.console.param.GlobalSessionParam; -import io.seata.server.console.service.GlobalSessionService; -import io.seata.server.console.vo.GlobalSessionVO; -import io.seata.server.session.GlobalSession; -import io.seata.server.session.SessionCondition; -import io.seata.server.storage.redis.store.RedisTransactionStoreManager; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; -import org.springframework.stereotype.Component; - -import java.util.ArrayList; -import java.util.List; -import java.util.stream.Collectors; - -import static io.seata.common.exception.FrameworkErrorCode.ParameterRequired; -import static io.seata.common.util.StringUtils.isBlank; -import static io.seata.common.util.StringUtils.isNotBlank; -import static io.seata.console.result.PageResult.checkPage; -import static io.seata.server.storage.SessionConverter.convertToGlobalSessionVo; - -/** - * Global Session Redis ServiceImpl - * @author zhongxiang.wang - * @author doubleDimple - */ -@Component -@org.springframework.context.annotation.Configuration -@ConditionalOnExpression("#{'redis'.equals('${sessionMode}')}") -public class GlobalSessionRedisServiceImpl implements GlobalSessionService { - - private static final Logger LOGGER = LoggerFactory.getLogger(GlobalSessionRedisServiceImpl.class); - - @Override - public PageResult query(GlobalSessionParam param) { - List result = new ArrayList<>(); - Long total = 0L; - if (param.getTimeStart() != null || param.getTimeEnd() != null) { - //not support time range query - LOGGER.debug("not supported according to time range query"); - return PageResult.failure(ParameterRequired.getErrCode(),"not supported according to time range query"); - } - List globalSessions = new ArrayList<>(); - - RedisTransactionStoreManager instance = RedisTransactionStoreManager.getInstance(); - - checkPage(param); - - if (isBlank(param.getXid()) && param.getStatus() == null) { - total = instance.countByGlobalSessions(GlobalStatus.values()); - globalSessions = instance.findGlobalSessionByPage(param.getPageNum(), param.getPageSize(),param.isWithBranch()); - } else { - List globalSessionsNew = new ArrayList<>(); - if (isNotBlank(param.getXid())) { - SessionCondition sessionCondition = new SessionCondition(); - sessionCondition.setXid(param.getXid()); - sessionCondition.setLazyLoadBranch(!param.isWithBranch()); - globalSessions = instance.readSession(sessionCondition); - total = (long)globalSessions.size(); - } - - if (param.getStatus() != null && GlobalStatus.get(param.getStatus()) != null) { - if (CollectionUtils.isNotEmpty(globalSessions)) { - globalSessionsNew = globalSessions.stream().filter(globalSession -> globalSession.getStatus().getCode() == (param.getStatus())).collect(Collectors.toList()); - total = (long)globalSessionsNew.size(); - } else { - total = instance.countByGlobalSessions(new GlobalStatus[] {GlobalStatus.get(param.getStatus())}); - globalSessionsNew = instance.readSessionStatusByPage(param); - } - } - - if (LOGGER.isDebugEnabled()) { - if (isNotBlank(param.getApplicationId())) { - //not support - LOGGER.debug("not supported according to applicationId query"); - } - if (isNotBlank(param.getTransactionName())) { - //not support - LOGGER.debug("not supported according to transactionName query"); - } - } - globalSessions = globalSessionsNew.size() > 0 ? globalSessionsNew : globalSessions; - } - - convertToGlobalSessionVo(result,globalSessions); - - return PageResult.success(result,total.intValue(),param.getPageNum(),param.getPageSize()); - } - -} diff --git a/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/console/param/GlobalLockParam.java b/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/console/param/GlobalLockParam.java deleted file mode 100644 index dcc43012..00000000 --- a/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/console/param/GlobalLockParam.java +++ /dev/null @@ -1,114 +0,0 @@ -/* - * Copyright 1999-2019 Seata.io Group. - * - * Licensed 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 io.seata.server.console.param; - -import io.seata.console.param.BaseParam; - -import java.io.Serializable; - -/** - * Global lock param - * @author zhongxiang.wang - */ -public class GlobalLockParam extends BaseParam implements Serializable { - - private static final long serialVersionUID = 615412528070131284L; - - /** - * the xid - */ - private String xid; - /** - * the table name - */ - private String tableName; - /** - * the transaction id - */ - private String transactionId; - /** - * the branch id - */ - private String branchId; - /** - * the primary Key - */ - private String pk; - /** - * the resourceId - */ - private String resourceId; - - public String getTransactionId() { - return transactionId; - } - - public void setTransactionId(String transactionId) { - this.transactionId = transactionId; - } - - public String getBranchId() { - return branchId; - } - - public void setBranchId(String branchId) { - this.branchId = branchId; - } - - public String getXid() { - return xid; - } - - public void setXid(String xid) { - this.xid = xid; - } - - public String getTableName() { - return tableName; - } - - public void setTableName(String tableName) { - this.tableName = tableName; - } - - public String getPk() { - return pk; - } - - public void setPk(String pk) { - this.pk = pk; - } - - public String getResourceId() { - return resourceId; - } - - public void setResourceId(String resourceId) { - this.resourceId = resourceId; - } - - @Override - public String toString() { - return "GlobalLockParam{" + - "xid='" + xid + '\'' + - ", tableName='" + tableName + '\'' + - ", transactionId='" + transactionId + '\'' + - ", branchId='" + branchId + '\'' + - ", pk='" + pk + '\'' + - ", resourceId='" + resourceId + '\'' + - '}'; - } -} diff --git a/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/console/param/GlobalSessionParam.java b/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/console/param/GlobalSessionParam.java deleted file mode 100644 index 88673039..00000000 --- a/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/console/param/GlobalSessionParam.java +++ /dev/null @@ -1,102 +0,0 @@ -/* - * Copyright 1999-2019 Seata.io Group. - * - * Licensed 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 io.seata.server.console.param; - -import io.seata.console.param.BaseParam; - -import java.io.Serializable; - -/** - * Global session param - * @author zhongxiang.wang - */ -public class GlobalSessionParam extends BaseParam implements Serializable { - - private static final long serialVersionUID = 115488252809011284L; - /** - * the xid - */ - private String xid; - /** - * the application id - */ - private String applicationId; - /** - * the global session status - */ - private Integer status; - /** - * the transaction name - */ - private String transactionName; - /** - * if with branch - * true: with branch session - * false: no branch session - */ - private boolean withBranch; - - public String getXid() { - return xid; - } - - public void setXid(String xid) { - this.xid = xid; - } - - public String getTransactionName() { - return transactionName; - } - - public void setTransactionName(String transactionName) { - this.transactionName = transactionName; - } - - public String getApplicationId() { - return applicationId; - } - - public void setApplicationId(String applicationId) { - this.applicationId = applicationId; - } - - public Integer getStatus() { - return status; - } - - public void setStatus(Integer status) { - this.status = status; - } - - public boolean isWithBranch() { - return withBranch; - } - - public void setWithBranch(boolean withBranch) { - this.withBranch = withBranch; - } - - @Override - public String toString() { - return "GlobalSessionParam{" + - "xid='" + xid + '\'' + - ", applicationId='" + applicationId + '\'' + - ", status=" + status + - ", transactionName='" + transactionName + '\'' + - ", withBranch=" + withBranch + - '}'; - } -} diff --git a/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/console/service/BranchSessionService.java b/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/console/service/BranchSessionService.java deleted file mode 100644 index 5f1b3fdc..00000000 --- a/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/console/service/BranchSessionService.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright 1999-2019 Seata.io Group. - * - * Licensed 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 io.seata.server.console.service; - -import io.seata.console.result.PageResult; -import io.seata.server.console.vo.BranchSessionVO; - -/** - * Branch session service - * @author wangzhongxiang - */ -public interface BranchSessionService { - - /** - * Query branch session by xid - * @param xid the xid - * @return the BranchSessionVO list - */ - PageResult queryByXid(String xid); - -} diff --git a/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/console/service/GlobalLockService.java b/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/console/service/GlobalLockService.java deleted file mode 100644 index 87b3a790..00000000 --- a/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/console/service/GlobalLockService.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright 1999-2019 Seata.io Group. - * - * Licensed 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 io.seata.server.console.service; - -import io.seata.console.result.PageResult; -import io.seata.server.console.param.GlobalLockParam; -import io.seata.server.console.vo.GlobalLockVO; - - -/** - * Global lock service - * @author wangzhongxiang - */ -public interface GlobalLockService { - - /** - * Query locks by param - * @param param the param - * @return the list of GlobalLockVO - */ - PageResult query(GlobalLockParam param); - - -} diff --git a/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/console/service/GlobalSessionService.java b/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/console/service/GlobalSessionService.java deleted file mode 100644 index 45260538..00000000 --- a/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/console/service/GlobalSessionService.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright 1999-2019 Seata.io Group. - * - * Licensed 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 io.seata.server.console.service; - -import io.seata.console.result.PageResult; -import io.seata.server.console.param.GlobalSessionParam; -import io.seata.server.console.vo.GlobalSessionVO; - -/** - * Global session service - * @author wangzhongxiang - */ -public interface GlobalSessionService { - - /** - * Query global session - * @param param the param - * @return the GlobalSessionVO list - */ - PageResult query(GlobalSessionParam param); - -} diff --git a/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/console/vo/BranchSessionVO.java b/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/console/vo/BranchSessionVO.java deleted file mode 100644 index fa1e7b87..00000000 --- a/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/console/vo/BranchSessionVO.java +++ /dev/null @@ -1,241 +0,0 @@ -/* - * Copyright 1999-2019 Seata.io Group. - * - * Licensed 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 io.seata.server.console.vo; - -import io.seata.core.constants.ServerTableColumnsName; - -import java.sql.Date; -import java.sql.ResultSet; -import java.sql.SQLException; -import java.util.Objects; - -/** - * BranchSessionVO - * @author zhongxiang.wang - */ -public class BranchSessionVO { - - private String xid; - - private String transactionId; - - private String branchId; - - private String resourceGroupId; - - private String resourceId; - - private String branchType; - - private Integer status; - - private String clientId; - - private String applicationData; - - private Long gmtCreate; - - private Long gmtModified; - - - public BranchSessionVO(){ - - } - - public BranchSessionVO(String xid, - Long transactionId, - Long branchId, - String resourceGroupId, - String resourceId, - String branchType, - Integer status, - String clientId, - String applicationData) { - this.xid = xid; - this.transactionId = String.valueOf(transactionId); - this.branchId = String.valueOf(branchId); - this.resourceGroupId = resourceGroupId; - this.resourceId = resourceId; - this.branchType = branchType; - this.status = status; - this.clientId = clientId; - this.applicationData = applicationData; - } - - public String getXid() { - return xid; - } - - public void setXid(String xid) { - this.xid = xid; - } - - public String getTransactionId() { - return transactionId; - } - - public void setTransactionId(Long transactionId) { - this.transactionId = String.valueOf(transactionId); - } - - public String getBranchId() { - return branchId; - } - - public void setBranchId(Long branchId) { - this.branchId = String.valueOf(branchId); - } - - public String getResourceGroupId() { - return resourceGroupId; - } - - public void setResourceGroupId(String resourceGroupId) { - this.resourceGroupId = resourceGroupId; - } - - public String getResourceId() { - return resourceId; - } - - public void setResourceId(String resourceId) { - this.resourceId = resourceId; - } - - public String getBranchType() { - return branchType; - } - - public void setBranchType(String branchType) { - this.branchType = branchType; - } - - public Integer getStatus() { - return status; - } - - public void setStatus(Integer status) { - this.status = status; - } - - public String getClientId() { - return clientId; - } - - public void setClientId(String clientId) { - this.clientId = clientId; - } - - public String getApplicationData() { - return applicationData; - } - - public void setApplicationData(String applicationData) { - this.applicationData = applicationData; - } - - public Long getGmtCreate() { - return gmtCreate; - } - - public void setGmtCreate(Long gmtCreate) { - this.gmtCreate = gmtCreate; - } - - public Long getGmtModified() { - return gmtModified; - } - - public void setGmtModified(Long gmtModified) { - this.gmtModified = gmtModified; - } - - public static BranchSessionVO convert(ResultSet rs) throws SQLException { - BranchSessionVO branchSessionVO = new BranchSessionVO(); - branchSessionVO.setXid(rs.getString(ServerTableColumnsName.BRANCH_TABLE_XID)); - branchSessionVO.setTransactionId(rs.getLong(ServerTableColumnsName.BRANCH_TABLE_TRANSACTION_ID)); - branchSessionVO.setBranchId(rs.getLong(ServerTableColumnsName.BRANCH_TABLE_BRANCH_ID)); - branchSessionVO.setResourceGroupId(rs.getString(ServerTableColumnsName.BRANCH_TABLE_RESOURCE_GROUP_ID)); - branchSessionVO.setResourceId(rs.getString(ServerTableColumnsName.BRANCH_TABLE_RESOURCE_ID)); - branchSessionVO.setBranchType(rs.getString(ServerTableColumnsName.BRANCH_TABLE_BRANCH_TYPE)); - branchSessionVO.setStatus(rs.getInt(ServerTableColumnsName.BRANCH_TABLE_STATUS)); - branchSessionVO.setClientId(rs.getString(ServerTableColumnsName.BRANCH_TABLE_CLIENT_ID)); - branchSessionVO.setApplicationData(rs.getString(ServerTableColumnsName.BRANCH_TABLE_APPLICATION_DATA)); - Date gmtCreateTimestamp = rs.getDate(ServerTableColumnsName.BRANCH_TABLE_GMT_CREATE); - if (gmtCreateTimestamp != null) { - branchSessionVO.setGmtCreate(gmtCreateTimestamp.getTime()); - } - Date gmtModifiedTimestamp = rs.getDate(ServerTableColumnsName.BRANCH_TABLE_GMT_MODIFIED); - if (gmtModifiedTimestamp != null) { - branchSessionVO.setGmtModified(gmtModifiedTimestamp.getTime()); - } - return branchSessionVO; - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - BranchSessionVO that = (BranchSessionVO) o; - return Objects.equals(xid, that.xid) - && Objects.equals(transactionId, that.transactionId) - && Objects.equals(branchId, that.branchId) - && Objects.equals(resourceGroupId, that.resourceGroupId) - && Objects.equals(resourceId, that.resourceId) - && Objects.equals(branchType, that.branchType) - && Objects.equals(status, that.status) - && Objects.equals(clientId, that.clientId) - && Objects.equals(applicationData, that.applicationData) - && Objects.equals(gmtCreate, that.gmtCreate) - && Objects.equals(gmtModified, that.gmtModified); - } - - @Override - public int hashCode() { - return Objects.hash(xid, - transactionId, - branchId, - resourceGroupId, - resourceId, - branchType, - status, - clientId, - applicationData, - gmtCreate, - gmtModified); - } - - @Override - public String toString() { - return "BranchSessionVO{" + - "xid='" + xid + '\'' + - ", transactionId=" + transactionId + - ", branchId=" + branchId + - ", resourceGroupId='" + resourceGroupId + '\'' + - ", resourceId='" + resourceId + '\'' + - ", branchType='" + branchType + '\'' + - ", status=" + status + - ", clientId='" + clientId + '\'' + - ", applicationData='" + applicationData + '\'' + - ", gmtCreate=" + gmtCreate + - ", gmtModified=" + gmtModified + - '}'; - } -} diff --git a/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/console/vo/GlobalLockVO.java b/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/console/vo/GlobalLockVO.java deleted file mode 100644 index 265cc77c..00000000 --- a/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/console/vo/GlobalLockVO.java +++ /dev/null @@ -1,196 +0,0 @@ -/* - * Copyright 1999-2019 Seata.io Group. - * - * Licensed 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 io.seata.server.console.vo; - -import io.seata.common.util.CollectionUtils; -import io.seata.core.constants.ServerTableColumnsName; -import io.seata.core.lock.RowLock; - -import java.sql.ResultSet; -import java.sql.SQLException; -import java.sql.Timestamp; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - -/** - * GlobalLockVO - * @author zhongxiang.wang - * @author miaoxueyu - */ -public class GlobalLockVO { - - private String xid; - - private String transactionId; - - private String branchId; - - private String resourceId; - - private String tableName; - - private String pk; - - private String rowKey; - - private Long gmtCreate; - - private Long gmtModified; - - /** - * convert RowLock list to GlobalLockVO list - * @param rowLocks the RowLock list - * @return the GlobalLockVO list - */ - public static List convert(List rowLocks) { - if (CollectionUtils.isEmpty(rowLocks)) { - return Collections.emptyList(); - } - final List result = new ArrayList<>(rowLocks.size()); - for (RowLock rowLock : rowLocks) { - result.add(convert(rowLock)); - } - - return result; - } - - - /** - * convert RowLock to GlobalLockVO - * @param rowLock the RowLock - * @return the GlobalLockVO - */ - public static GlobalLockVO convert(RowLock rowLock) { - final GlobalLockVO globalLockVO = new GlobalLockVO(); - globalLockVO.setXid(rowLock.getXid()); - globalLockVO.setTransactionId(rowLock.getTransactionId()); - globalLockVO.setBranchId(rowLock.getBranchId()); - globalLockVO.setResourceId(rowLock.getResourceId()); - globalLockVO.setTableName(rowLock.getTableName()); - globalLockVO.setPk(rowLock.getPk()); - globalLockVO.setRowKey(rowLock.getRowKey()); - return globalLockVO; - } - - - public String getXid() { - return xid; - } - - public void setXid(String xid) { - this.xid = xid; - } - - public String getTransactionId() { - return transactionId; - } - - public void setTransactionId(Long transactionId) { - this.transactionId = String.valueOf(transactionId); - } - - public String getBranchId() { - return branchId; - } - - public void setBranchId(Long branchId) { - this.branchId = String.valueOf(branchId); - } - - public String getResourceId() { - return resourceId; - } - - public void setResourceId(String resourceId) { - this.resourceId = resourceId; - } - - public String getTableName() { - return tableName; - } - - public void setTableName(String tableName) { - this.tableName = tableName; - } - - public String getPk() { - return pk; - } - - public void setPk(String pk) { - this.pk = pk; - } - - public String getRowKey() { - return rowKey; - } - - public void setRowKey(String rowKey) { - this.rowKey = rowKey; - } - - public Long getGmtCreate() { - return gmtCreate; - } - - public void setGmtCreate(Long gmtCreate) { - this.gmtCreate = gmtCreate; - } - - public Long getGmtModified() { - return gmtModified; - } - - public void setGmtModified(Long gmtModified) { - this.gmtModified = gmtModified; - } - - public static GlobalLockVO convert(ResultSet rs) throws SQLException { - GlobalLockVO globalLockVO = new GlobalLockVO(); - globalLockVO.setRowKey(rs.getString(ServerTableColumnsName.LOCK_TABLE_ROW_KEY)); - globalLockVO.setXid(rs.getString(ServerTableColumnsName.LOCK_TABLE_XID)); - globalLockVO.setTransactionId(rs.getLong(ServerTableColumnsName.LOCK_TABLE_TRANSACTION_ID)); - globalLockVO.setBranchId(rs.getLong(ServerTableColumnsName.LOCK_TABLE_BRANCH_ID)); - globalLockVO.setResourceId(rs.getString(ServerTableColumnsName.LOCK_TABLE_RESOURCE_ID)); - globalLockVO.setTableName(rs.getString(ServerTableColumnsName.LOCK_TABLE_TABLE_NAME)); - globalLockVO.setPk(rs.getString(ServerTableColumnsName.LOCK_TABLE_PK)); - Timestamp gmtCreateTimestamp = rs.getTimestamp(ServerTableColumnsName.LOCK_TABLE_GMT_CREATE); - if (gmtCreateTimestamp != null) { - globalLockVO.setGmtCreate(gmtCreateTimestamp.getTime()); - } - Timestamp gmtModifiedTimestamp = rs.getTimestamp(ServerTableColumnsName.LOCK_TABLE_GMT_MODIFIED); - if (gmtModifiedTimestamp != null) { - globalLockVO.setGmtModified(gmtModifiedTimestamp.getTime()); - } - return globalLockVO; - } - - @Override - public String toString() { - return "GlobalLockVO{" + - "xid='" + xid + '\'' + - ", transactionId=" + transactionId + - ", branchId=" + branchId + - ", resourceId='" + resourceId + '\'' + - ", tableName='" + tableName + '\'' + - ", pk='" + pk + '\'' + - ", rowKey='" + rowKey + '\'' + - ", gmtCreate=" + gmtCreate + - ", gmtModified=" + gmtModified + - '}'; - } -} diff --git a/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/console/vo/GlobalSessionVO.java b/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/console/vo/GlobalSessionVO.java deleted file mode 100644 index b040cb5f..00000000 --- a/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/console/vo/GlobalSessionVO.java +++ /dev/null @@ -1,217 +0,0 @@ -/* - * Copyright 1999-2019 Seata.io Group. - * - * Licensed 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 io.seata.server.console.vo; - -import io.seata.core.constants.ServerTableColumnsName; - -import java.sql.ResultSet; -import java.sql.SQLException; -import java.sql.Timestamp; -import java.util.Set; - -/** - * GlobalSessionVO - * @author zhongxiang.wang - */ -public class GlobalSessionVO { - - private String xid; - - private String transactionId; - - private Integer status; - - private String applicationId; - - private String transactionServiceGroup; - - private String transactionName; - - private Long timeout; - - private Long beginTime; - - private String applicationData; - - private Long gmtCreate; - - private Long gmtModified; - - private Set branchSessionVOs; - - - public GlobalSessionVO() { - - } - - public GlobalSessionVO(String xid, - Long transactionId, - Integer status, - String applicationId, - String transactionServiceGroup, - String transactionName, - Long timeout, - Long beginTime, - String applicationData, - Set branchSessionVOs) { - this.xid = xid; - this.transactionId = String.valueOf(transactionId); - this.status = status; - this.applicationId = applicationId; - this.transactionServiceGroup = transactionServiceGroup; - this.transactionName = transactionName; - this.timeout = timeout; - this.beginTime = beginTime; - this.applicationData = applicationData; - this.branchSessionVOs = branchSessionVOs; - } - - public String getXid() { - return xid; - } - - public void setXid(String xid) { - this.xid = xid; - } - - public String getTransactionId() { - return transactionId; - } - - public void setTransactionId(Long transactionId) { - this.transactionId = String.valueOf(transactionId); - } - - public Integer getStatus() { - return status; - } - - public void setStatus(Integer status) { - this.status = status; - } - - public String getApplicationId() { - return applicationId; - } - - public void setApplicationId(String applicationId) { - this.applicationId = applicationId; - } - - public String getTransactionServiceGroup() { - return transactionServiceGroup; - } - - public void setTransactionServiceGroup(String transactionServiceGroup) { - this.transactionServiceGroup = transactionServiceGroup; - } - - public String getTransactionName() { - return transactionName; - } - - public void setTransactionName(String transactionName) { - this.transactionName = transactionName; - } - - public Long getTimeout() { - return timeout; - } - - public void setTimeout(Long timeout) { - this.timeout = timeout; - } - - public Long getBeginTime() { - return beginTime; - } - - public void setBeginTime(Long beginTime) { - this.beginTime = beginTime; - } - - public String getApplicationData() { - return applicationData; - } - - public void setApplicationData(String applicationData) { - this.applicationData = applicationData; - } - - public Long getGmtCreate() { - return gmtCreate; - } - - public void setGmtCreate(Long gmtCreate) { - this.gmtCreate = gmtCreate; - } - - public Long getGmtModified() { - return gmtModified; - } - - public void setGmtModified(Long gmtModified) { - this.gmtModified = gmtModified; - } - - public Set getBranchSessionVOs() { - return branchSessionVOs; - } - - public void setBranchSessionVOs(Set branchSessionVOs) { - this.branchSessionVOs = branchSessionVOs; - } - - public static GlobalSessionVO convert(ResultSet rs) throws SQLException { - GlobalSessionVO globalSessionVO = new GlobalSessionVO(); - globalSessionVO.setXid(rs.getString(ServerTableColumnsName.GLOBAL_TABLE_XID)); - globalSessionVO.setTransactionId(rs.getLong(ServerTableColumnsName.GLOBAL_TABLE_TRANSACTION_ID)); - globalSessionVO.setStatus(rs.getInt(ServerTableColumnsName.GLOBAL_TABLE_STATUS)); - globalSessionVO.setApplicationId(rs.getString(ServerTableColumnsName.GLOBAL_TABLE_APPLICATION_ID)); - globalSessionVO.setTransactionServiceGroup(rs.getString(ServerTableColumnsName.GLOBAL_TABLE_TRANSACTION_SERVICE_GROUP)); - globalSessionVO.setTransactionName(rs.getString(ServerTableColumnsName.GLOBAL_TABLE_TRANSACTION_NAME)); - globalSessionVO.setTimeout(rs.getLong(ServerTableColumnsName.GLOBAL_TABLE_TIMEOUT)); - globalSessionVO.setBeginTime(rs.getLong(ServerTableColumnsName.GLOBAL_TABLE_BEGIN_TIME)); - globalSessionVO.setApplicationData(rs.getString(ServerTableColumnsName.GLOBAL_TABLE_APPLICATION_DATA)); - Timestamp gmtCreateTimestamp = rs.getTimestamp(ServerTableColumnsName.GLOBAL_TABLE_GMT_CREATE); - if (gmtCreateTimestamp != null) { - globalSessionVO.setGmtCreate(gmtCreateTimestamp.getTime()); - } - Timestamp gmtModifiedTimestamp = rs.getTimestamp(ServerTableColumnsName.GLOBAL_TABLE_GMT_MODIFIED); - if (gmtModifiedTimestamp != null) { - globalSessionVO.setGmtModified(gmtModifiedTimestamp.getTime()); - } - return globalSessionVO; - } - - @Override - public String toString() { - return "GlobalSessionVO{" + - "xid='" + xid + '\'' + - ", transactionId=" + transactionId + - ", status=" + status + - ", applicationId='" + applicationId + '\'' + - ", transactionServiceGroup='" + transactionServiceGroup + '\'' + - ", transactionName='" + transactionName + '\'' + - ", timeout=" + timeout + - ", beginTime=" + beginTime + - ", applicationData='" + applicationData + '\'' + - ", gmtCreate=" + gmtCreate + - ", gmtModified=" + gmtModified + - ", branchSessionVOs=" + branchSessionVOs + - '}'; - } -} diff --git a/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/controller/HealthController.java b/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/controller/HealthController.java deleted file mode 100644 index 155045af..00000000 --- a/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/controller/HealthController.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright 1999-2019 Seata.io Group. - * - * Licensed 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 io.seata.server.controller; - -import io.seata.server.ServerRunner; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Controller; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.ResponseBody; - -/** - * @author spilledyear@outlook.com - */ -@Controller -@RequestMapping -public class HealthController { - - private static final String OK = "ok"; - private static final String NOT_OK = "not_ok"; - - @Autowired - private ServerRunner serverRunner; - - - @RequestMapping("/health") - @ResponseBody - String healthCheck() { - return serverRunner.started() ? OK : NOT_OK; - } -} \ No newline at end of file diff --git a/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/coordinator/AbstractCore.java b/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/coordinator/AbstractCore.java deleted file mode 100644 index 70477c33..00000000 --- a/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/coordinator/AbstractCore.java +++ /dev/null @@ -1,241 +0,0 @@ -/* - * Copyright 1999-2019 Seata.io Group. - * - * Licensed 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 io.seata.server.coordinator; - -import io.seata.core.context.RootContext; -import io.seata.core.exception.BranchTransactionException; -import io.seata.core.exception.GlobalTransactionException; -import io.seata.core.exception.TransactionException; -import io.seata.core.exception.TransactionExceptionCode; -import io.seata.core.model.BranchStatus; -import io.seata.core.model.BranchType; -import io.seata.core.model.GlobalStatus; -import io.seata.core.protocol.transaction.BranchCommitRequest; -import io.seata.core.protocol.transaction.BranchCommitResponse; -import io.seata.core.protocol.transaction.BranchRollbackRequest; -import io.seata.core.protocol.transaction.BranchRollbackResponse; -import io.seata.core.rpc.RemotingServer; -import io.seata.server.lock.LockManager; -import io.seata.server.lock.LockerManagerFactory; -import io.seata.server.session.BranchSession; -import io.seata.server.session.GlobalSession; -import io.seata.server.session.SessionHelper; -import io.seata.server.session.SessionHolder; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.slf4j.MDC; - -import java.io.IOException; -import java.util.concurrent.TimeoutException; - -import static io.seata.core.exception.TransactionExceptionCode.*; - -/** - * The type abstract core. - * - * @author ph3636 - */ -public abstract class AbstractCore implements Core { - - protected static final Logger LOGGER = LoggerFactory.getLogger(AbstractCore.class); - - protected LockManager lockManager = LockerManagerFactory.getLockManager(); - - protected RemotingServer remotingServer; - - public AbstractCore(RemotingServer remotingServer) { - if (remotingServer == null) { - throw new IllegalArgumentException("remotingServer must be not null"); - } - this.remotingServer = remotingServer; - } - - public abstract BranchType getHandleBranchType(); - - @Override - public Long branchRegister(BranchType branchType, String resourceId, String clientId, String xid, - String applicationData, String lockKeys) throws TransactionException { - GlobalSession globalSession = assertGlobalSessionNotNull(xid, false); - return SessionHolder.lockAndExecute(globalSession, () -> { - globalSessionStatusCheck(globalSession); - globalSession.addSessionLifecycleListener(SessionHolder.getRootSessionManager()); - BranchSession branchSession = SessionHelper.newBranchByGlobal(globalSession, branchType, resourceId, - applicationData, lockKeys, clientId); - MDC.put(RootContext.MDC_KEY_BRANCH_ID, String.valueOf(branchSession.getBranchId())); - branchSessionLock(globalSession, branchSession); - try { - globalSession.addBranch(branchSession); - } catch (RuntimeException ex) { - branchSessionUnlock(branchSession); - throw new BranchTransactionException(FailedToAddBranch, String - .format("Failed to store branch xid = %s branchId = %s", globalSession.getXid(), - branchSession.getBranchId()), ex); - } - if (LOGGER.isInfoEnabled()) { - LOGGER.info("Register branch successfully, xid = {}, branchId = {}, resourceId = {} ,lockKeys = {}", - globalSession.getXid(), branchSession.getBranchId(), resourceId, lockKeys); - } - return branchSession.getBranchId(); - }); - } - - protected void globalSessionStatusCheck(GlobalSession globalSession) throws GlobalTransactionException { - if (!globalSession.isActive()) { - throw new GlobalTransactionException(GlobalTransactionNotActive, String.format( - "Could not register branch into global session xid = %s status = %s, cause by globalSession not active", - globalSession.getXid(), globalSession.getStatus())); - } - if (globalSession.getStatus() != GlobalStatus.Begin) { - throw new GlobalTransactionException(GlobalTransactionStatusInvalid, String - .format("Could not register branch into global session xid = %s status = %s while expecting %s", - globalSession.getXid(), globalSession.getStatus(), GlobalStatus.Begin)); - } - } - - protected void branchSessionLock(GlobalSession globalSession, BranchSession branchSession) throws TransactionException { - - } - - protected void branchSessionUnlock(BranchSession branchSession) throws TransactionException { - - } - - private GlobalSession assertGlobalSessionNotNull(String xid, boolean withBranchSessions) - throws TransactionException { - GlobalSession globalSession = SessionHolder.findGlobalSession(xid, withBranchSessions); - if (globalSession == null) { - throw new GlobalTransactionException(TransactionExceptionCode.GlobalTransactionNotExist, - String.format("Could not found global transaction xid = %s, may be has finished.", xid)); - } - return globalSession; - } - - @Override - public void branchReport(BranchType branchType, String xid, long branchId, BranchStatus status, - String applicationData) throws TransactionException { - GlobalSession globalSession = assertGlobalSessionNotNull(xid, true); - BranchSession branchSession = globalSession.getBranch(branchId); - if (branchSession == null) { - throw new BranchTransactionException(BranchTransactionNotExist, - String.format("Could not found branch session xid = %s branchId = %s", xid, branchId)); - } - branchSession.setApplicationData(applicationData); - globalSession.addSessionLifecycleListener(SessionHolder.getRootSessionManager()); - globalSession.changeBranchStatus(branchSession, status); - - if (LOGGER.isInfoEnabled()) { - LOGGER.info("Report branch status successfully, xid = {}, branchId = {}", globalSession.getXid(), - branchSession.getBranchId()); - } - } - - @Override - public boolean lockQuery(BranchType branchType, String resourceId, String xid, String lockKeys) - throws TransactionException { - return true; - } - - @Override - public BranchStatus branchCommit(GlobalSession globalSession, BranchSession branchSession) throws TransactionException { - try { - BranchCommitRequest request = new BranchCommitRequest(); - request.setXid(branchSession.getXid()); - request.setBranchId(branchSession.getBranchId()); - request.setResourceId(branchSession.getResourceId()); - request.setApplicationData(branchSession.getApplicationData()); - request.setBranchType(branchSession.getBranchType()); - return branchCommitSend(request, globalSession, branchSession); - } catch (IOException | TimeoutException e) { - throw new BranchTransactionException(FailedToSendBranchCommitRequest, - String.format("Send branch commit failed, xid = %s branchId = %s", branchSession.getXid(), - branchSession.getBranchId()), e); - } - } - - protected BranchStatus branchCommitSend(BranchCommitRequest request, GlobalSession globalSession, - BranchSession branchSession) throws IOException, TimeoutException { - - BranchCommitResponse response = (BranchCommitResponse) remotingServer.sendSyncRequest( - branchSession.getResourceId(), branchSession.getClientId(), request, branchSession.isAT()); - return response.getBranchStatus(); - } - - @Override - public BranchStatus branchRollback(GlobalSession globalSession, BranchSession branchSession) throws TransactionException { - try { - BranchRollbackRequest request = new BranchRollbackRequest(); - request.setXid(branchSession.getXid()); - request.setBranchId(branchSession.getBranchId()); - request.setResourceId(branchSession.getResourceId()); - request.setApplicationData(branchSession.getApplicationData()); - request.setBranchType(branchSession.getBranchType()); - return branchRollbackSend(request, globalSession, branchSession); - } catch (IOException | TimeoutException e) { - throw new BranchTransactionException(FailedToSendBranchRollbackRequest, - String.format("Send branch rollback failed, xid = %s branchId = %s", - branchSession.getXid(), branchSession.getBranchId()), e); - } - } - - protected BranchStatus branchRollbackSend(BranchRollbackRequest request, GlobalSession globalSession, - BranchSession branchSession) throws IOException, TimeoutException { - - BranchRollbackResponse response = (BranchRollbackResponse) remotingServer.sendSyncRequest( - branchSession.getResourceId(), branchSession.getClientId(), request, branchSession.isAT()); - return response.getBranchStatus(); - } - - @Override - public String begin(String applicationId, String transactionServiceGroup, String name, int timeout) - throws TransactionException { - return null; - } - - @Override - public GlobalStatus commit(String xid) throws TransactionException { - return null; - } - - @Override - public boolean doGlobalCommit(GlobalSession globalSession, boolean retrying) throws TransactionException { - return true; - } - - @Override - public GlobalStatus globalReport(String xid, GlobalStatus globalStatus) throws TransactionException { - return null; - } - - @Override - public GlobalStatus rollback(String xid) throws TransactionException { - return null; - } - - @Override - public boolean doGlobalRollback(GlobalSession globalSession, boolean retrying) throws TransactionException { - return true; - } - - @Override - public GlobalStatus getStatus(String xid) throws TransactionException { - return null; - } - - @Override - public void doGlobalReport(GlobalSession globalSession, String xid, GlobalStatus globalStatus) throws TransactionException { - - } -} diff --git a/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/coordinator/Core.java b/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/coordinator/Core.java deleted file mode 100644 index 8ad19cbd..00000000 --- a/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/coordinator/Core.java +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright 1999-2019 Seata.io Group. - * - * Licensed 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 io.seata.server.coordinator; - -import io.seata.core.exception.TransactionException; -import io.seata.core.model.GlobalStatus; -import io.seata.server.session.GlobalSession; - -/** - * The interface Core. - * - * @author sharajava - */ -public interface Core extends TransactionCoordinatorInbound, TransactionCoordinatorOutbound { - - /** - * Do global commit. - * - * @param globalSession the global session - * @param retrying the retrying - * @return is global commit. - * @throws TransactionException the transaction exception - */ - boolean doGlobalCommit(GlobalSession globalSession, boolean retrying) throws TransactionException; - - /** - * Do global rollback. - * - * @param globalSession the global session - * @param retrying the retrying - * @return is global rollback. - * @throws TransactionException the transaction exception - */ - boolean doGlobalRollback(GlobalSession globalSession, boolean retrying) throws TransactionException; - - /** - * Do global report. - * - * @param globalSession the global session - * @param xid Transaction id. - * @param param the global status - * @throws TransactionException the transaction exception - */ - void doGlobalReport(GlobalSession globalSession, String xid, GlobalStatus param) throws TransactionException; - -} diff --git a/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/coordinator/DefaultCoordinator.java b/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/coordinator/DefaultCoordinator.java deleted file mode 100644 index 910af84e..00000000 --- a/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/coordinator/DefaultCoordinator.java +++ /dev/null @@ -1,609 +0,0 @@ -/* - * Copyright 1999-2019 Seata.io Group. - * - * Licensed 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 io.seata.server.coordinator; - -import io.netty.channel.Channel; -import io.seata.common.thread.NamedThreadFactory; -import io.seata.common.util.CollectionUtils; -import io.seata.config.ConfigurationFactory; -import io.seata.core.constants.ConfigurationKeys; -import io.seata.core.context.RootContext; -import io.seata.core.exception.TransactionException; -import io.seata.core.model.GlobalStatus; -import io.seata.core.protocol.AbstractMessage; -import io.seata.core.protocol.AbstractResultMessage; -import io.seata.core.protocol.transaction.*; -import io.seata.core.rpc.Disposable; -import io.seata.core.rpc.RemotingServer; -import io.seata.core.rpc.RpcContext; -import io.seata.core.rpc.TransactionMessageHandler; -import io.seata.core.rpc.netty.ChannelManager; -import io.seata.core.rpc.netty.NettyRemotingServer; -import io.seata.server.AbstractTCInboundHandler; -import io.seata.server.metrics.MetricsPublisher; -import io.seata.server.session.*; -import io.seata.server.store.StoreConfig; -import org.apache.commons.lang.time.DateFormatUtils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.slf4j.MDC; - -import java.util.Collection; -import java.util.Map; -import java.util.concurrent.ArrayBlockingQueue; -import java.util.concurrent.ScheduledThreadPoolExecutor; -import java.util.concurrent.ThreadPoolExecutor; -import java.util.concurrent.TimeUnit; - -import static io.seata.common.Constants.*; -import static io.seata.common.DefaultValues.*; - -/** - * The type Default coordinator. - */ -public class DefaultCoordinator extends AbstractTCInboundHandler implements TransactionMessageHandler, Disposable { - - private static final Logger LOGGER = LoggerFactory.getLogger(DefaultCoordinator.class); - - private static final int TIMED_TASK_SHUTDOWN_MAX_WAIT_MILLS = 5000; - - /** - * The constant COMMITTING_RETRY_PERIOD. - */ - protected static final long COMMITTING_RETRY_PERIOD = CONFIG.getLong(ConfigurationKeys.COMMITING_RETRY_PERIOD, - DEFAULT_COMMITING_RETRY_PERIOD); - - /** - * The constant ASYNC_COMMITTING_RETRY_PERIOD. - */ - protected static final long ASYNC_COMMITTING_RETRY_PERIOD = CONFIG.getLong( - ConfigurationKeys.ASYNC_COMMITING_RETRY_PERIOD, DEFAULT_ASYNC_COMMITTING_RETRY_PERIOD); - - /** - * The constant ROLLBACKING_RETRY_PERIOD. - */ - protected static final long ROLLBACKING_RETRY_PERIOD = CONFIG.getLong(ConfigurationKeys.ROLLBACKING_RETRY_PERIOD, - DEFAULT_ROLLBACKING_RETRY_PERIOD); - - /** - * The constant TIMEOUT_RETRY_PERIOD. - */ - protected static final long TIMEOUT_RETRY_PERIOD = CONFIG.getLong(ConfigurationKeys.TIMEOUT_RETRY_PERIOD, - DEFAULT_TIMEOUT_RETRY_PERIOD); - - /** - * The Transaction undo log delete period. - */ - protected static final long UNDO_LOG_DELETE_PERIOD = CONFIG.getLong( - ConfigurationKeys.TRANSACTION_UNDO_LOG_DELETE_PERIOD, DEFAULT_UNDO_LOG_DELETE_PERIOD); - - /** - * The Transaction undo log delay delete period - */ - protected static final long UNDO_LOG_DELAY_DELETE_PERIOD = 3 * 60 * 1000; - - private static final int ALWAYS_RETRY_BOUNDARY = 0; - - /** - * default branch async queue size - */ - private static final int DEFAULT_BRANCH_ASYNC_QUEUE_SIZE = 5000; - - /** - * the pool size of branch asynchronous remove thread pool - */ - private static final int BRANCH_ASYNC_POOL_SIZE = Runtime.getRuntime().availableProcessors() * 2; - - private static final long MAX_COMMIT_RETRY_TIMEOUT = ConfigurationFactory.getInstance().getLong( - ConfigurationKeys.MAX_COMMIT_RETRY_TIMEOUT, DEFAULT_MAX_COMMIT_RETRY_TIMEOUT); - - private static final long MAX_ROLLBACK_RETRY_TIMEOUT = ConfigurationFactory.getInstance().getLong( - ConfigurationKeys.MAX_ROLLBACK_RETRY_TIMEOUT, DEFAULT_MAX_ROLLBACK_RETRY_TIMEOUT); - - private static final boolean ROLLBACK_RETRY_TIMEOUT_UNLOCK_ENABLE = ConfigurationFactory.getInstance().getBoolean( - ConfigurationKeys.ROLLBACK_RETRY_TIMEOUT_UNLOCK_ENABLE, DEFAULT_ROLLBACK_RETRY_TIMEOUT_UNLOCK_ENABLE); - - private final ScheduledThreadPoolExecutor retryRollbacking = - new ScheduledThreadPoolExecutor(1, new NamedThreadFactory(RETRY_ROLLBACKING, 1)); - - private final ScheduledThreadPoolExecutor retryCommitting = - new ScheduledThreadPoolExecutor(1, new NamedThreadFactory(RETRY_COMMITTING, 1)); - - private final ScheduledThreadPoolExecutor asyncCommitting = - new ScheduledThreadPoolExecutor(1, new NamedThreadFactory(ASYNC_COMMITTING, 1)); - - private final ScheduledThreadPoolExecutor timeoutCheck = - new ScheduledThreadPoolExecutor(1, new NamedThreadFactory(TX_TIMEOUT_CHECK, 1)); - - private final ScheduledThreadPoolExecutor undoLogDelete = - new ScheduledThreadPoolExecutor(1, new NamedThreadFactory(UNDOLOG_DELETE, 1)); - - private final GlobalStatus[] rollbackingStatuses = new GlobalStatus[] {GlobalStatus.TimeoutRollbacking, - GlobalStatus.TimeoutRollbackRetrying, GlobalStatus.RollbackRetrying, GlobalStatus.Rollbacking}; - - private final GlobalStatus[] retryCommittingStatuses = new GlobalStatus[] {GlobalStatus.Committing, GlobalStatus.CommitRetrying, GlobalStatus.Committed}; - - private final ThreadPoolExecutor branchRemoveExecutor; - - private RemotingServer remotingServer; - - private final DefaultCore core; - - private static volatile DefaultCoordinator instance; - - /** - * Instantiates a new Default coordinator. - * - * @param remotingServer the remoting server - */ - private DefaultCoordinator(RemotingServer remotingServer) { - if (remotingServer == null) { - throw new IllegalArgumentException("RemotingServer not allowed be null."); - } - this.remotingServer = remotingServer; - this.core = new DefaultCore(remotingServer); - boolean enableBranchAsyncRemove = CONFIG.getBoolean( - ConfigurationKeys.ENABLE_BRANCH_ASYNC_REMOVE, DEFAULT_ENABLE_BRANCH_ASYNC_REMOVE); - // create branchRemoveExecutor - if (enableBranchAsyncRemove && StoreConfig.getSessionMode() != StoreConfig.SessionMode.FILE) { - branchRemoveExecutor = new ThreadPoolExecutor(BRANCH_ASYNC_POOL_SIZE, BRANCH_ASYNC_POOL_SIZE, - Integer.MAX_VALUE, TimeUnit.MILLISECONDS, - new ArrayBlockingQueue<>( - CONFIG.getInt(ConfigurationKeys.SESSION_BRANCH_ASYNC_QUEUE_SIZE, DEFAULT_BRANCH_ASYNC_QUEUE_SIZE) - ), new NamedThreadFactory("branchSessionRemove", BRANCH_ASYNC_POOL_SIZE), - new ThreadPoolExecutor.CallerRunsPolicy()); - } else { - branchRemoveExecutor = null; - } - } - - public static DefaultCoordinator getInstance(RemotingServer remotingServer) { - if (null == instance) { - synchronized (DefaultCoordinator.class) { - if (null == instance) { - instance = new DefaultCoordinator(remotingServer); - } - } - } - return instance; - } - - public static DefaultCoordinator getInstance() { - if (null == instance) { - throw new IllegalArgumentException("The instance has not been created."); - } - return instance; - } - - /** - * Asynchronous remove branch - * - * @param globalSession the globalSession - * @param branchSession the branchSession - */ - public void doBranchRemoveAsync(GlobalSession globalSession, BranchSession branchSession) { - if (globalSession == null) { - return; - } - branchRemoveExecutor.execute(new BranchRemoveTask(globalSession, branchSession)); - } - - /** - * Asynchronous remove all branch - * - * @param globalSession the globalSession - */ - public void doBranchRemoveAllAsync(GlobalSession globalSession) { - if (globalSession == null) { - return; - } - branchRemoveExecutor.execute(new BranchRemoveTask(globalSession)); - } - - @Override - protected void doGlobalBegin(GlobalBeginRequest request, GlobalBeginResponse response, RpcContext rpcContext) - throws TransactionException { - response.setXid(core.begin(rpcContext.getApplicationId(), rpcContext.getTransactionServiceGroup(), - request.getTransactionName(), request.getTimeout())); - if (LOGGER.isInfoEnabled()) { - LOGGER.info("Begin new global transaction applicationId: {},transactionServiceGroup: {}, transactionName: {},timeout:{},xid:{}", - rpcContext.getApplicationId(), rpcContext.getTransactionServiceGroup(), request.getTransactionName(), request.getTimeout(), response.getXid()); - } - } - - @Override - protected void doGlobalCommit(GlobalCommitRequest request, GlobalCommitResponse response, RpcContext rpcContext) - throws TransactionException { - MDC.put(RootContext.MDC_KEY_XID, request.getXid()); - response.setGlobalStatus(core.commit(request.getXid())); - } - - @Override - protected void doGlobalRollback(GlobalRollbackRequest request, GlobalRollbackResponse response, - RpcContext rpcContext) throws TransactionException { - MDC.put(RootContext.MDC_KEY_XID, request.getXid()); - response.setGlobalStatus(core.rollback(request.getXid())); - } - - @Override - protected void doGlobalStatus(GlobalStatusRequest request, GlobalStatusResponse response, RpcContext rpcContext) - throws TransactionException { - MDC.put(RootContext.MDC_KEY_XID, request.getXid()); - response.setGlobalStatus(core.getStatus(request.getXid())); - } - - @Override - protected void doGlobalReport(GlobalReportRequest request, GlobalReportResponse response, RpcContext rpcContext) - throws TransactionException { - MDC.put(RootContext.MDC_KEY_XID, request.getXid()); - response.setGlobalStatus(core.globalReport(request.getXid(), request.getGlobalStatus())); - } - - @Override - protected void doBranchRegister(BranchRegisterRequest request, BranchRegisterResponse response, - RpcContext rpcContext) throws TransactionException { - MDC.put(RootContext.MDC_KEY_XID, request.getXid()); - response.setBranchId( - core.branchRegister(request.getBranchType(), request.getResourceId(), rpcContext.getClientId(), - request.getXid(), request.getApplicationData(), request.getLockKey())); - } - - @Override - protected void doBranchReport(BranchReportRequest request, BranchReportResponse response, RpcContext rpcContext) - throws TransactionException { - MDC.put(RootContext.MDC_KEY_XID, request.getXid()); - MDC.put(RootContext.MDC_KEY_BRANCH_ID, String.valueOf(request.getBranchId())); - core.branchReport(request.getBranchType(), request.getXid(), request.getBranchId(), request.getStatus(), - request.getApplicationData()); - } - - @Override - protected void doLockCheck(GlobalLockQueryRequest request, GlobalLockQueryResponse response, RpcContext rpcContext) - throws TransactionException { - MDC.put(RootContext.MDC_KEY_XID, request.getXid()); - response.setLockable( - core.lockQuery(request.getBranchType(), request.getResourceId(), request.getXid(), request.getLockKey())); - } - - /** - * Timeout check. - */ - protected void timeoutCheck() { - SessionCondition sessionCondition = new SessionCondition(GlobalStatus.Begin); - sessionCondition.setLazyLoadBranch(true); - Collection beginGlobalsessions = - SessionHolder.getRootSessionManager().findGlobalSessions(sessionCondition); - if (CollectionUtils.isEmpty(beginGlobalsessions)) { - return; - } - if (!beginGlobalsessions.isEmpty() && LOGGER.isDebugEnabled()) { - LOGGER.debug("Global transaction timeout check begin, size: {}", beginGlobalsessions.size()); - } - SessionHelper.forEach(beginGlobalsessions, globalSession -> { - if (LOGGER.isDebugEnabled()) { - LOGGER.debug( - globalSession.getXid() + " " + globalSession.getStatus() + " " + globalSession.getBeginTime() + " " - + globalSession.getTimeout()); - } - SessionHolder.lockAndExecute(globalSession, () -> { - if (globalSession.getStatus() != GlobalStatus.Begin || !globalSession.isTimeout()) { - return false; - } - - LOGGER.warn("Global transaction[{}] is timeout and will be rollback,transaction begin time:{} and now:{}", globalSession.getXid(), - DateFormatUtils.ISO_DATE_FORMAT.format(globalSession.getBeginTime()), DateFormatUtils.ISO_DATE_FORMAT.format(System.currentTimeMillis())); - - globalSession.addSessionLifecycleListener(SessionHolder.getRootSessionManager()); - globalSession.close(); - globalSession.setStatus(GlobalStatus.TimeoutRollbacking); - - globalSession.addSessionLifecycleListener(SessionHolder.getRetryRollbackingSessionManager()); - SessionHolder.getRetryRollbackingSessionManager().addGlobalSession(globalSession); - - // transaction timeout and start rollbacking event - MetricsPublisher.postSessionDoingEvent(globalSession, GlobalStatus.TimeoutRollbacking.name(), false, false); - - return true; - }); - }); - if (!beginGlobalsessions.isEmpty() && LOGGER.isDebugEnabled()) { - LOGGER.debug("Global transaction timeout check end. "); - } - - } - - - /** - * Handle retry rollbacking. - */ - protected void handleRetryRollbacking() { - SessionCondition sessionCondition = new SessionCondition(rollbackingStatuses); - sessionCondition.setLazyLoadBranch(true); - Collection rollbackingSessions = - SessionHolder.getRetryRollbackingSessionManager().findGlobalSessions(sessionCondition); - if (CollectionUtils.isEmpty(rollbackingSessions)) { - return; - } - long now = System.currentTimeMillis(); - SessionHelper.forEach(rollbackingSessions, rollbackingSession -> { - try { - // prevent repeated rollback - if (rollbackingSession.getStatus() == GlobalStatus.Rollbacking - && !rollbackingSession.isDeadSession()) { - // The function of this 'return' is 'continue'. - return; - } - if (isRetryTimeout(now, MAX_ROLLBACK_RETRY_TIMEOUT, rollbackingSession.getBeginTime())) { - if (ROLLBACK_RETRY_TIMEOUT_UNLOCK_ENABLE) { - rollbackingSession.clean(); - } - - SessionHelper.endRollbackFailed(rollbackingSession, true, true); - - //The function of this 'return' is 'continue'. - return; - } - rollbackingSession.addSessionLifecycleListener(SessionHolder.getRootSessionManager()); - core.doGlobalRollback(rollbackingSession, true); - } catch (TransactionException ex) { - LOGGER.error("Failed to retry rollbacking [{}] {} {}", rollbackingSession.getXid(), ex.getCode(), ex.getMessage()); - } - }); - } - - /** - * Handle retry committing. - */ - protected void handleRetryCommitting() { - SessionCondition retryCommittingSessionCondition = new SessionCondition(retryCommittingStatuses); - retryCommittingSessionCondition.setLazyLoadBranch(true); - Collection committingSessions = - SessionHolder.getRetryCommittingSessionManager().findGlobalSessions(retryCommittingSessionCondition); - if (CollectionUtils.isEmpty(committingSessions)) { - return; - } - long now = System.currentTimeMillis(); - SessionHelper.forEach(committingSessions, committingSession -> { - try { - // prevent repeated commit - if (GlobalStatus.Committing.equals(committingSession.getStatus()) && !committingSession.isDeadSession()) { - // The function of this 'return' is 'continue'. - return; - } - if (isRetryTimeout(now, MAX_COMMIT_RETRY_TIMEOUT, committingSession.getBeginTime())) { - - // commit retry timeout event - SessionHelper.endCommitFailed(committingSession, true, true); - - //The function of this 'return' is 'continue'. - return; - } - if (GlobalStatus.Committed.equals(committingSession.getStatus()) - && committingSession.getBranchSessions().isEmpty()) { - SessionHelper.endCommitted(committingSession,true); - } - committingSession.addSessionLifecycleListener(SessionHolder.getRootSessionManager()); - core.doGlobalCommit(committingSession, true); - } catch (TransactionException ex) { - LOGGER.error("Failed to retry committing [{}] {} {}", committingSession.getXid(), ex.getCode(), ex.getMessage()); - } - }); - } - - /** - * Handle async committing. - */ - protected void handleAsyncCommitting() { - SessionCondition sessionCondition = new SessionCondition(GlobalStatus.AsyncCommitting); - Collection asyncCommittingSessions = - SessionHolder.getAsyncCommittingSessionManager().findGlobalSessions(sessionCondition); - if (CollectionUtils.isEmpty(asyncCommittingSessions)) { - return; - } - SessionHelper.forEach(asyncCommittingSessions, asyncCommittingSession -> { - try { - asyncCommittingSession.addSessionLifecycleListener(SessionHolder.getRootSessionManager()); - core.doGlobalCommit(asyncCommittingSession, true); - } catch (TransactionException ex) { - LOGGER.error("Failed to async committing [{}] {} {}", asyncCommittingSession.getXid(), ex.getCode(), ex.getMessage(), ex); - } - }); - } - - /** - * Undo log delete. - */ - protected void undoLogDelete() { - Map rmChannels = ChannelManager.getRmChannels(); - if (rmChannels == null || rmChannels.isEmpty()) { - if (LOGGER.isDebugEnabled()) { - LOGGER.debug("no active rm channels to delete undo log"); - } - return; - } - short saveDays = CONFIG.getShort(ConfigurationKeys.TRANSACTION_UNDO_LOG_SAVE_DAYS, - UndoLogDeleteRequest.DEFAULT_SAVE_DAYS); - for (Map.Entry channelEntry : rmChannels.entrySet()) { - String resourceId = channelEntry.getKey(); - UndoLogDeleteRequest deleteRequest = new UndoLogDeleteRequest(); - deleteRequest.setResourceId(resourceId); - deleteRequest.setSaveDays(saveDays > 0 ? saveDays : UndoLogDeleteRequest.DEFAULT_SAVE_DAYS); - try { - remotingServer.sendAsyncRequest(channelEntry.getValue(), deleteRequest); - } catch (Exception e) { - LOGGER.error("Failed to async delete undo log resourceId = {}, exception: {}", resourceId, e.getMessage()); - } - } - } - - private boolean isRetryTimeout(long now, long timeout, long beginTime) { - return timeout >= ALWAYS_RETRY_BOUNDARY && now - beginTime > timeout; - } - - /** - * Init. - */ - public void init() { - retryRollbacking.scheduleAtFixedRate( - () -> SessionHolder.distributedLockAndExecute(RETRY_ROLLBACKING, this::handleRetryRollbacking), 0, - ROLLBACKING_RETRY_PERIOD, TimeUnit.MILLISECONDS); - - retryCommitting.scheduleAtFixedRate( - () -> SessionHolder.distributedLockAndExecute(RETRY_COMMITTING, this::handleRetryCommitting), 0, - COMMITTING_RETRY_PERIOD, TimeUnit.MILLISECONDS); - - asyncCommitting.scheduleAtFixedRate( - () -> SessionHolder.distributedLockAndExecute(ASYNC_COMMITTING, this::handleAsyncCommitting), 0, - ASYNC_COMMITTING_RETRY_PERIOD, TimeUnit.MILLISECONDS); - - timeoutCheck.scheduleAtFixedRate( - () -> SessionHolder.distributedLockAndExecute(TX_TIMEOUT_CHECK, this::timeoutCheck), 0, - TIMEOUT_RETRY_PERIOD, TimeUnit.MILLISECONDS); - - undoLogDelete.scheduleAtFixedRate( - () -> SessionHolder.distributedLockAndExecute(UNDOLOG_DELETE, this::undoLogDelete), - UNDO_LOG_DELAY_DELETE_PERIOD, UNDO_LOG_DELETE_PERIOD, TimeUnit.MILLISECONDS); - } - - @Override - public AbstractResultMessage onRequest(AbstractMessage request, RpcContext context) { - if (!(request instanceof AbstractTransactionRequestToTC)) { - throw new IllegalArgumentException(); - } - AbstractTransactionRequestToTC transactionRequest = (AbstractTransactionRequestToTC) request; - transactionRequest.setTCInboundHandler(this); - - return transactionRequest.handle(context); - } - - @Override - public void onResponse(AbstractResultMessage response, RpcContext context) { - if (!(response instanceof AbstractTransactionResponse)) { - throw new IllegalArgumentException(); - } - - } - - @Override - public void destroy() { - // 1. first shutdown timed task - retryRollbacking.shutdown(); - retryCommitting.shutdown(); - asyncCommitting.shutdown(); - timeoutCheck.shutdown(); - undoLogDelete.shutdown(); - if (branchRemoveExecutor != null) { - branchRemoveExecutor.shutdown(); - } - try { - retryRollbacking.awaitTermination(TIMED_TASK_SHUTDOWN_MAX_WAIT_MILLS, TimeUnit.MILLISECONDS); - retryCommitting.awaitTermination(TIMED_TASK_SHUTDOWN_MAX_WAIT_MILLS, TimeUnit.MILLISECONDS); - asyncCommitting.awaitTermination(TIMED_TASK_SHUTDOWN_MAX_WAIT_MILLS, TimeUnit.MILLISECONDS); - timeoutCheck.awaitTermination(TIMED_TASK_SHUTDOWN_MAX_WAIT_MILLS, TimeUnit.MILLISECONDS); - undoLogDelete.awaitTermination(TIMED_TASK_SHUTDOWN_MAX_WAIT_MILLS, TimeUnit.MILLISECONDS); - if (branchRemoveExecutor != null) { - branchRemoveExecutor.awaitTermination(TIMED_TASK_SHUTDOWN_MAX_WAIT_MILLS, TimeUnit.MILLISECONDS); - } - } catch (InterruptedException ignore) { - - } - // 2. second close netty flow - if (remotingServer instanceof NettyRemotingServer) { - ((NettyRemotingServer) remotingServer).destroy(); - } - // 3. third destroy SessionHolder - SessionHolder.destroy(); - instance = null; - } - - /** - * only used for mock test - * @param remotingServer - */ - public void setRemotingServer(RemotingServer remotingServer) { - this.remotingServer = remotingServer; - } - - /** - * the task to remove branchSession - */ - static class BranchRemoveTask implements Runnable { - - /** - * the globalSession - */ - private final GlobalSession globalSession; - - /** - * the branchSession - */ - private final BranchSession branchSession; - - /** - * If you use this construct, the task will remove the branchSession provided by the parameter - * @param globalSession the globalSession - */ - public BranchRemoveTask(GlobalSession globalSession, BranchSession branchSession) { - this.globalSession = globalSession; - if (branchSession == null) { - throw new IllegalArgumentException("BranchSession can`t be null!"); - } - this.branchSession = branchSession; - } - - /** - * If you use this construct, the task will remove all branchSession - * @param globalSession the globalSession - */ - public BranchRemoveTask(GlobalSession globalSession) { - this.globalSession = globalSession; - this.branchSession = null; - } - - @Override - public void run() { - if (globalSession == null) { - return; - } - try { - MDC.put(RootContext.MDC_KEY_XID, globalSession.getXid()); - if (branchSession != null) { - doRemove(branchSession); - } else { - globalSession.getSortedBranches().forEach(this::doRemove); - } - } catch (Exception unKnowException) { - LOGGER.error("Asynchronous delete branchSession error, xid = {}", globalSession.getXid(), unKnowException); - } finally { - MDC.remove(RootContext.MDC_KEY_XID); - } - } - - private void doRemove(BranchSession bt) { - try { - MDC.put(RootContext.MDC_KEY_BRANCH_ID, String.valueOf(bt.getBranchId())); - globalSession.removeBranch(bt); - LOGGER.info("Asynchronous delete branchSession successfully, xid = {}, branchId = {}", - globalSession.getXid(), bt.getBranchId()); - } catch (TransactionException transactionException) { - LOGGER.error("Asynchronous delete branchSession error, xid = {}, branchId = {}", - globalSession.getXid(), bt.getBranchId(), transactionException); - } finally { - MDC.remove(RootContext.MDC_KEY_BRANCH_ID); - } - } - } -} diff --git a/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/coordinator/DefaultCore.java b/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/coordinator/DefaultCore.java deleted file mode 100644 index bfd52711..00000000 --- a/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/coordinator/DefaultCore.java +++ /dev/null @@ -1,399 +0,0 @@ -/* - * Copyright 1999-2019 Seata.io Group. - * - * Licensed 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 io.seata.server.coordinator; - -import io.seata.common.DefaultValues; -import io.seata.common.exception.NotSupportYetException; -import io.seata.common.loader.EnhancedServiceLoader; -import io.seata.common.util.CollectionUtils; -import io.seata.config.ConfigurationFactory; -import io.seata.core.context.RootContext; -import io.seata.core.exception.TransactionException; -import io.seata.core.logger.StackTraceLogger; -import io.seata.core.model.BranchStatus; -import io.seata.core.model.BranchType; -import io.seata.core.model.GlobalStatus; -import io.seata.core.rpc.RemotingServer; -import io.seata.server.metrics.MetricsPublisher; -import io.seata.server.session.BranchSession; -import io.seata.server.session.GlobalSession; -import io.seata.server.session.SessionHelper; -import io.seata.server.session.SessionHolder; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.slf4j.MDC; - -import java.util.List; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; - -import static io.seata.core.constants.ConfigurationKeys.XAER_NOTA_RETRY_TIMEOUT; -import static io.seata.server.session.BranchSessionHandler.CONTINUE; - -/** - * The type Default core. - * - * @author sharajava - */ -public class DefaultCore implements Core { - - private static final Logger LOGGER = LoggerFactory.getLogger(DefaultCore.class); - - private static final int RETRY_XAER_NOTA_TIMEOUT = ConfigurationFactory.getInstance().getInt(XAER_NOTA_RETRY_TIMEOUT, - DefaultValues.DEFAULT_XAER_NOTA_RETRY_TIMEOUT); - - private static Map coreMap = new ConcurrentHashMap<>(); - - /** - * get the Default core. - * - * @param remotingServer the remoting server - */ - public DefaultCore(RemotingServer remotingServer) { - List allCore = EnhancedServiceLoader.loadAll(AbstractCore.class, - new Class[] {RemotingServer.class}, new Object[] {remotingServer}); - if (CollectionUtils.isNotEmpty(allCore)) { - for (AbstractCore core : allCore) { - coreMap.put(core.getHandleBranchType(), core); - } - } - } - - /** - * get core - * - * @param branchType the branchType - * @return the core - */ - public AbstractCore getCore(BranchType branchType) { - AbstractCore core = coreMap.get(branchType); - if (core == null) { - throw new NotSupportYetException("unsupported type:" + branchType.name()); - } - return core; - } - - /** - * only for mock - * - * @param branchType the branchType - * @param core the core - */ - public void mockCore(BranchType branchType, AbstractCore core) { - coreMap.put(branchType, core); - } - - @Override - public Long branchRegister(BranchType branchType, String resourceId, String clientId, String xid, - String applicationData, String lockKeys) throws TransactionException { - return getCore(branchType).branchRegister(branchType, resourceId, clientId, xid, - applicationData, lockKeys); - } - - @Override - public void branchReport(BranchType branchType, String xid, long branchId, BranchStatus status, - String applicationData) throws TransactionException { - getCore(branchType).branchReport(branchType, xid, branchId, status, applicationData); - } - - @Override - public boolean lockQuery(BranchType branchType, String resourceId, String xid, String lockKeys) - throws TransactionException { - return getCore(branchType).lockQuery(branchType, resourceId, xid, lockKeys); - } - - @Override - public BranchStatus branchCommit(GlobalSession globalSession, BranchSession branchSession) throws TransactionException { - return getCore(branchSession.getBranchType()).branchCommit(globalSession, branchSession); - } - - @Override - public BranchStatus branchRollback(GlobalSession globalSession, BranchSession branchSession) throws TransactionException { - return getCore(branchSession.getBranchType()).branchRollback(globalSession, branchSession); - } - - @Override - public String begin(String applicationId, String transactionServiceGroup, String name, int timeout) - throws TransactionException { - GlobalSession session = GlobalSession.createGlobalSession(applicationId, transactionServiceGroup, name, timeout); - MDC.put(RootContext.MDC_KEY_XID, session.getXid()); - session.addSessionLifecycleListener(SessionHolder.getRootSessionManager()); - - session.begin(); - - // transaction start event - MetricsPublisher.postSessionDoingEvent(session, false); - - return session.getXid(); - } - - - - @Override - public GlobalStatus commit(String xid) throws TransactionException { - GlobalSession globalSession = SessionHolder.findGlobalSession(xid); - if (globalSession == null) { - return GlobalStatus.Finished; - } - - if (globalSession.isTimeout()) { - LOGGER.info("TC detected timeout, xid = {}", globalSession.getXid()); - return GlobalStatus.TimeoutRollbacking; - } - - globalSession.addSessionLifecycleListener(SessionHolder.getRootSessionManager()); - // just lock changeStatus - - boolean shouldCommit = SessionHolder.lockAndExecute(globalSession, () -> { - if (globalSession.getStatus() == GlobalStatus.Begin) { - // Highlight: Firstly, close the session, then no more branch can be registered. - globalSession.closeAndClean(); - if (globalSession.canBeCommittedAsync()) { - globalSession.asyncCommit(); - MetricsPublisher.postSessionDoneEvent(globalSession, GlobalStatus.Committed, false, false); - return false; - } else { - globalSession.changeGlobalStatus(GlobalStatus.Committing); - return true; - } - } - return false; - }); - - if (shouldCommit) { - boolean success = doGlobalCommit(globalSession, false); - //If successful and all remaining branches can be committed asynchronously, do async commit. - if (success && globalSession.hasBranch() && globalSession.canBeCommittedAsync()) { - globalSession.asyncCommit(); - return GlobalStatus.Committed; - } else { - return globalSession.getStatus(); - } - } else { - return globalSession.getStatus() == GlobalStatus.AsyncCommitting ? GlobalStatus.Committed : globalSession.getStatus(); - } - } - - @Override - public boolean doGlobalCommit(GlobalSession globalSession, boolean retrying) throws TransactionException { - boolean success = true; - // start committing event - MetricsPublisher.postSessionDoingEvent(globalSession, retrying); - - if (globalSession.isSaga()) { - success = getCore(BranchType.SAGA).doGlobalCommit(globalSession, retrying); - } else { - Boolean result = SessionHelper.forEach(globalSession.getSortedBranches(), branchSession -> { - // if not retrying, skip the canBeCommittedAsync branches - if (!retrying && branchSession.canBeCommittedAsync()) { - return CONTINUE; - } - - BranchStatus currentStatus = branchSession.getStatus(); - if (currentStatus == BranchStatus.PhaseOne_Failed) { - SessionHelper.removeBranch(globalSession, branchSession, !retrying); - return CONTINUE; - } - try { - BranchStatus branchStatus = getCore(branchSession.getBranchType()).branchCommit(globalSession, branchSession); - if (isXaerNotaTimeout(globalSession,branchStatus)) { - LOGGER.info("Commit branch XAER_NOTA retry timeout, xid = {} branchId = {}", globalSession.getXid(), branchSession.getBranchId()); - branchStatus = BranchStatus.PhaseTwo_Committed; - } - switch (branchStatus) { - case PhaseTwo_Committed: - SessionHelper.removeBranch(globalSession, branchSession, !retrying); - LOGGER.info("Commit branch transaction successfully, xid = {} branchId = {}", globalSession.getXid(), branchSession.getBranchId()); - return CONTINUE; - case PhaseTwo_CommitFailed_Unretryable: - //not at branch - SessionHelper.endCommitFailed(globalSession, retrying); - LOGGER.error("Committing global transaction[{}] finally failed, caused by branch transaction[{}] commit failed.", globalSession.getXid(), branchSession.getBranchId()); - return false; - - default: - if (!retrying) { - globalSession.queueToRetryCommit(); - return false; - } - if (globalSession.canBeCommittedAsync()) { - LOGGER.error("Committing branch transaction[{}], status:{} and will retry later", - branchSession.getBranchId(), branchStatus); - return CONTINUE; - } else { - LOGGER.error( - "Committing global transaction[{}] failed, caused by branch transaction[{}] commit failed, will retry later.", globalSession.getXid(), branchSession.getBranchId()); - return false; - } - } - } catch (Exception ex) { - StackTraceLogger.error(LOGGER, ex, "Committing branch transaction exception: {}", - new String[] {branchSession.toString()}); - if (!retrying) { - globalSession.queueToRetryCommit(); - throw new TransactionException(ex); - } - } - return CONTINUE; - }); - // Return if the result is not null - if (result != null) { - return result; - } - //If has branch and not all remaining branches can be committed asynchronously, - //do print log and return false - if (globalSession.hasBranch() && !globalSession.canBeCommittedAsync()) { - LOGGER.info("Committing global transaction is NOT done, xid = {}.", globalSession.getXid()); - return false; - } - } - // if it succeeds and there is no branch, retrying=true is the asynchronous state when retrying. EndCommitted is - // executed to improve concurrency performance, and the global transaction ends.. - if (success && globalSession.getBranchSessions().isEmpty()) { - if (!retrying) { - //contains not AT branch - globalSession.setStatus(GlobalStatus.Committed); - } - SessionHelper.endCommitted(globalSession, retrying); - LOGGER.info("Committing global transaction is successfully done, xid = {}.", globalSession.getXid()); - } - return success; - } - - @Override - public GlobalStatus rollback(String xid) throws TransactionException { - GlobalSession globalSession = SessionHolder.findGlobalSession(xid); - if (globalSession == null) { - return GlobalStatus.Finished; - } - globalSession.addSessionLifecycleListener(SessionHolder.getRootSessionManager()); - // just lock changeStatus - boolean shouldRollBack = SessionHolder.lockAndExecute(globalSession, () -> { - globalSession.close(); // Highlight: Firstly, close the session, then no more branch can be registered. - if (globalSession.getStatus() == GlobalStatus.Begin) { - globalSession.changeGlobalStatus(GlobalStatus.Rollbacking); - return true; - } - return false; - }); - if (!shouldRollBack) { - return globalSession.getStatus(); - } - - boolean rollbackSuccess = doGlobalRollback(globalSession, false); - return rollbackSuccess ? GlobalStatus.Rollbacked : globalSession.getStatus(); - } - - @Override - public boolean doGlobalRollback(GlobalSession globalSession, boolean retrying) throws TransactionException { - boolean success = true; - // start rollback event - MetricsPublisher.postSessionDoingEvent(globalSession, retrying); - - if (globalSession.isSaga()) { - success = getCore(BranchType.SAGA).doGlobalRollback(globalSession, retrying); - } else { - Boolean result = SessionHelper.forEach(globalSession.getReverseSortedBranches(), branchSession -> { - BranchStatus currentBranchStatus = branchSession.getStatus(); - if (currentBranchStatus == BranchStatus.PhaseOne_Failed) { - SessionHelper.removeBranch(globalSession, branchSession, !retrying); - return CONTINUE; - } - try { - BranchStatus branchStatus = branchRollback(globalSession, branchSession); - if (isXaerNotaTimeout(globalSession, branchStatus)) { - LOGGER.info("Rollback branch XAER_NOTA retry timeout, xid = {} branchId = {}", globalSession.getXid(), branchSession.getBranchId()); - branchStatus = BranchStatus.PhaseTwo_Rollbacked; - } - switch (branchStatus) { - case PhaseTwo_Rollbacked: - SessionHelper.removeBranch(globalSession, branchSession, !retrying); - LOGGER.info("Rollback branch transaction successfully, xid = {} branchId = {}", globalSession.getXid(), branchSession.getBranchId()); - return CONTINUE; - case PhaseTwo_RollbackFailed_Unretryable: - SessionHelper.endRollbackFailed(globalSession, retrying); - LOGGER.error("Rollback branch transaction fail and stop retry, xid = {} branchId = {}", globalSession.getXid(), branchSession.getBranchId()); - return false; - default: - LOGGER.error("Rollback branch transaction fail and will retry, xid = {} branchId = {}", globalSession.getXid(), branchSession.getBranchId()); - if (!retrying) { - globalSession.queueToRetryRollback(); - } - return false; - } - } catch (Exception ex) { - StackTraceLogger.error(LOGGER, ex, - "Rollback branch transaction exception, xid = {} branchId = {} exception = {}", - new String[] {globalSession.getXid(), String.valueOf(branchSession.getBranchId()), ex.getMessage()}); - if (!retrying) { - globalSession.queueToRetryRollback(); - } - throw new TransactionException(ex); - } - }); - // Return if the result is not null - if (result != null) { - return result; - } - } - - // In db mode, lock and branch data residual problems may occur. - // Therefore, execution needs to be delayed here and cannot be executed synchronously. - if (success) { - SessionHelper.endRollbacked(globalSession, retrying); - LOGGER.info("Rollback global transaction successfully, xid = {}.", globalSession.getXid()); - } - return success; - } - - @Override - public GlobalStatus getStatus(String xid) throws TransactionException { - GlobalSession globalSession = SessionHolder.findGlobalSession(xid, false); - if (globalSession == null) { - return GlobalStatus.Finished; - } else { - return globalSession.getStatus(); - } - } - - @Override - public GlobalStatus globalReport(String xid, GlobalStatus globalStatus) throws TransactionException { - GlobalSession globalSession = SessionHolder.findGlobalSession(xid); - if (globalSession == null) { - return globalStatus; - } - globalSession.addSessionLifecycleListener(SessionHolder.getRootSessionManager()); - doGlobalReport(globalSession, xid, globalStatus); - return globalSession.getStatus(); - } - - @Override - public void doGlobalReport(GlobalSession globalSession, String xid, GlobalStatus globalStatus) throws TransactionException { - if (globalSession.isSaga()) { - getCore(BranchType.SAGA).doGlobalReport(globalSession, xid, globalStatus); - } - } - - private boolean isXaerNotaTimeout(GlobalSession globalSession, BranchStatus branchStatus) { - if (BranchStatus.PhaseTwo_CommitFailed_XAER_NOTA_Retryable.equals(branchStatus) || - BranchStatus.PhaseTwo_RollbackFailed_XAER_NOTA_Retryable.equals(branchStatus)) { - return System.currentTimeMillis() > globalSession.getBeginTime() + globalSession.getTimeout() + - Math.max(RETRY_XAER_NOTA_TIMEOUT, globalSession.getTimeout()); - } else { - return false; - } - } -} diff --git a/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/coordinator/TransactionCoordinatorInbound.java b/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/coordinator/TransactionCoordinatorInbound.java deleted file mode 100644 index d8c9932b..00000000 --- a/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/coordinator/TransactionCoordinatorInbound.java +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright 1999-2019 Seata.io Group. - * - * Licensed 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 io.seata.server.coordinator; - -import io.seata.core.model.ResourceManagerOutbound; -import io.seata.core.model.TransactionManager; - -/** - * receive inbound request from RM or TM. - * - * @author zhangchenghui.dev@gmail.com - * @since 1.1.0 - */ -public interface TransactionCoordinatorInbound extends ResourceManagerOutbound, TransactionManager { - -} diff --git a/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/coordinator/TransactionCoordinatorOutbound.java b/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/coordinator/TransactionCoordinatorOutbound.java deleted file mode 100644 index a213bd40..00000000 --- a/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/coordinator/TransactionCoordinatorOutbound.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright 1999-2019 Seata.io Group. - * - * Licensed 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 io.seata.server.coordinator; - -import io.seata.core.exception.TransactionException; -import io.seata.core.model.BranchStatus; -import io.seata.server.session.BranchSession; -import io.seata.server.session.GlobalSession; - -/** - * send outbound request to RM. - * - * @author zhangchenghui.dev@gmail.com - * @since 1.1.0 - */ -public interface TransactionCoordinatorOutbound { - - /** - * Commit a branch transaction. - * - * @param globalSession the global session - * @param branchSession the branch session - * @return Status of the branch after committing. - * @throws TransactionException Any exception that fails this will be wrapped with TransactionException and thrown - * out. - */ - BranchStatus branchCommit(GlobalSession globalSession, BranchSession branchSession) throws TransactionException; - - /** - * Rollback a branch transaction. - * - * @param globalSession the global session - * @param branchSession the branch session - * @return Status of the branch after rollbacking. - * @throws TransactionException Any exception that fails this will be wrapped with TransactionException and thrown - * out. - */ - BranchStatus branchRollback(GlobalSession globalSession, BranchSession branchSession) throws TransactionException; - - -} diff --git a/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/env/ContainerHelper.java b/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/env/ContainerHelper.java deleted file mode 100644 index a95242da..00000000 --- a/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/env/ContainerHelper.java +++ /dev/null @@ -1,103 +0,0 @@ -/* - * Copyright 1999-2019 Seata.io Group. - * - * Licensed 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 io.seata.server.env; - -import io.seata.common.util.NumberUtils; -import io.seata.common.util.StringUtils; - -import static io.seata.core.constants.ConfigurationKeys.ENV_SEATA_PORT_KEY; - -/** - * @author xingfudeshi@gmail.com - * @author wang.liang - */ -public class ContainerHelper { - - private static final String C_GROUP_PATH = "/proc/1/cgroup"; - private static final String DOCKER_PATH = "/docker"; - private static final String KUBEPODS_PATH = "/kubepods"; - - private static final String ENV_SYSTEM_KEY = "SEATA_ENV"; - private static final String ENV_SEATA_IP_KEY = "SEATA_IP"; - private static final String ENV_SERVER_NODE_KEY = "SERVER_NODE"; - private static final String ENV_STORE_MODE_KEY = "STORE_MODE"; - private static final String ENV_LOCK_STORE_MODE_KEY = "LOCK_STORE_MODE"; - private static final String ENV_SESSION_STORE_MODE_KEY = "SESSION_STORE_MODE"; - - /** - * Gets env from container. - * - * @return the env - */ - public static String getEnv() { - return StringUtils.trimToNull(System.getenv(ENV_SYSTEM_KEY)); - } - - /** - * Gets host from container. - * - * @return the env - */ - public static String getHost() { - return StringUtils.trimToNull(System.getenv(ENV_SEATA_IP_KEY)); - } - - /** - * Gets port from container. - * - * @return the env - */ - public static int getPort() { - return NumberUtils.toInt(System.getenv(ENV_SEATA_PORT_KEY), 0); - } - - /** - * Gets server node from container. - * - * @return the env - */ - public static Long getServerNode() { - return NumberUtils.toLong(System.getenv(ENV_SERVER_NODE_KEY)); - } - - /** - * Gets store mode from container. - * - * @return the env - */ - public static String getStoreMode() { - return StringUtils.trimToNull(System.getenv(ENV_STORE_MODE_KEY)); - } - - /** - * Gets session store mode from container. - * - * @return the env - */ - public static String getSessionStoreMode() { - return StringUtils.trimToNull(System.getenv(ENV_SESSION_STORE_MODE_KEY)); - } - - /** - * Gets lock store mode from container. - * - * @return the env - */ - public static String getLockStoreMode() { - return StringUtils.trimToNull(System.getenv(ENV_LOCK_STORE_MODE_KEY)); - } - -} diff --git a/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/env/PortHelper.java b/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/env/PortHelper.java deleted file mode 100644 index e3c24733..00000000 --- a/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/env/PortHelper.java +++ /dev/null @@ -1,130 +0,0 @@ -/* - * Copyright 1999-2019 Seata.io Group. - * - * Licensed 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 io.seata.server.env; - -import io.seata.common.util.CollectionUtils; -import io.seata.common.util.MapUtil; -import io.seata.common.util.NumberUtils; -import io.seata.common.util.StringUtils; -import org.springframework.util.ResourceUtils; -import org.yaml.snakeyaml.Yaml; - -import java.io.*; -import java.util.Map; -import java.util.Properties; - -/** - * @author wang.liang - */ -public class PortHelper { - - public static int getPortFromEnvOrStartup(String[] args) { - int port = 0; - if (args != null && args.length >= 2) { - for (int i = 0; i < args.length; ++i) { - if ("-p".equalsIgnoreCase(args[i]) && i < args.length - 1) { - port = NumberUtils.toInt(args[i + 1], 0); - } - } - } - if (port == 0) { - port = ContainerHelper.getPort(); - } - return port; - } - - /** - * get config from configFile - * -Dspring.config.location > classpath:application.properties > classpath:application.yml - * - * @return the port - * @throws IOException the io exception - */ - public static int getPortFromConfigFile() throws IOException { - - int port = 8080; - File configFile = null; - File startupConfigFile = getConfigFromStartup(); - if (null != startupConfigFile) { - configFile = startupConfigFile; - } else { - try { - File propertiesFile = ResourceUtils.getFile("classpath:application.properties"); - configFile = propertiesFile; - } catch (FileNotFoundException exx) { - File ymlFile = ResourceUtils.getFile("classpath:application.yml"); - configFile = ymlFile; - } - } - InputStream inputStream = null; - try { - inputStream = new FileInputStream(configFile); - String fileName = configFile.getName(); - String portNum = null; - if (fileName.endsWith("yml")) { - Map yamlMap = new Yaml().load(inputStream); - Map configMap = MapUtil.getFlattenedMap(yamlMap); - if (CollectionUtils.isNotEmpty(configMap)) { - Object serverPort = configMap.get("server.port"); - if (null != serverPort) { - portNum = serverPort.toString(); - } - } - } else { - Properties properties = new Properties(); - properties.load(inputStream); - portNum = properties.getProperty("server.port"); - } - if (null != portNum) { - try { - port = Integer.parseInt(portNum); - } catch (NumberFormatException exx) { - //ignore - } - } - } finally { - if (null != inputStream) { - inputStream.close(); - } - } - return port; - - } - private static File getConfigFromStartup() { - - String configLocation = System.getProperty("spring.config.location"); - if (StringUtils.isNotBlank(configLocation)) { - try { - File configFile = ResourceUtils.getFile(configLocation); - if (!configFile.isFile()) { - return null; - } - String fileName = configFile.getName(); - if (!(fileName.endsWith("yml") || fileName.endsWith("properties"))) { - return null; - } - return configFile; - } catch (FileNotFoundException e) { - return null; - } - } - return null; - - } - - -} - diff --git a/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/event/EventBusManager.java b/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/event/EventBusManager.java deleted file mode 100644 index 5500bc75..00000000 --- a/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/event/EventBusManager.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright 1999-2019 Seata.io Group. - * - * Licensed 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 io.seata.server.event; - -import io.seata.core.event.EventBus; -import io.seata.core.event.GuavaEventBus; - -/** - * Manager hold the singleton event bus instance. - * - * @author zhengyangyong - */ -public class EventBusManager { - private static class SingletonHolder { - private static EventBus INSTANCE = new GuavaEventBus("tc",true); - } - - public static EventBus get() { - return SingletonHolder.INSTANCE; - } -} diff --git a/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/lock/AbstractLockManager.java b/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/lock/AbstractLockManager.java deleted file mode 100644 index 91bb7b6e..00000000 --- a/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/lock/AbstractLockManager.java +++ /dev/null @@ -1,198 +0,0 @@ -/* - * Copyright 1999-2019 Seata.io Group. - * - * Licensed 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 io.seata.server.lock; - -import io.seata.common.XID; -import io.seata.common.util.CollectionUtils; -import io.seata.common.util.StringUtils; -import io.seata.core.exception.TransactionException; -import io.seata.core.lock.Locker; -import io.seata.core.lock.RowLock; -import io.seata.core.model.LockStatus; -import io.seata.server.session.BranchSession; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - -/** - * The type Abstract lock manager. - * - * @author zhangsen - */ -public abstract class AbstractLockManager implements LockManager { - - /** - * The constant LOGGER. - */ - protected static final Logger LOGGER = LoggerFactory.getLogger(AbstractLockManager.class); - - @Override - public boolean acquireLock(BranchSession branchSession) throws TransactionException { - return acquireLock(branchSession, true, false); - } - - @Override - public boolean acquireLock(BranchSession branchSession, boolean autoCommit, boolean skipCheckLock) throws TransactionException { - if (branchSession == null) { - throw new IllegalArgumentException("branchSession can't be null for memory/file locker."); - } - String lockKey = branchSession.getLockKey(); - if (StringUtils.isNullOrEmpty(lockKey)) { - // no lock - return true; - } - // get locks of branch - List locks = collectRowLocks(branchSession); - if (CollectionUtils.isEmpty(locks)) { - // no lock - return true; - } - return getLocker(branchSession).acquireLock(locks, autoCommit, skipCheckLock); - } - - @Override - public boolean releaseLock(BranchSession branchSession) throws TransactionException { - if (branchSession == null) { - throw new IllegalArgumentException("branchSession can't be null for memory/file locker."); - } - List locks = collectRowLocks(branchSession); - try { - return getLocker(branchSession).releaseLock(locks); - } catch (Exception t) { - LOGGER.error("unLock error, branchSession:{}", branchSession, t); - return false; - } - } - - @Override - public boolean isLockable(String xid, String resourceId, String lockKey) throws TransactionException { - if (StringUtils.isBlank(lockKey)) { - // no lock - return true; - } - List locks = collectRowLocks(lockKey, resourceId, xid); - try { - return getLocker().isLockable(locks); - } catch (Exception t) { - LOGGER.error("isLockable error, xid:{} resourceId:{}, lockKey:{}", xid, resourceId, lockKey, t); - return false; - } - } - - - @Override - public void cleanAllLocks() throws TransactionException { - getLocker().cleanAllLocks(); - } - - /** - * Gets locker. - * - * @return the locker - */ - protected Locker getLocker() { - return getLocker(null); - } - - /** - * Gets locker. - * - * @param branchSession the branch session - * @return the locker - */ - protected abstract Locker getLocker(BranchSession branchSession); - - @Override - public List collectRowLocks(BranchSession branchSession) { - if (branchSession == null || StringUtils.isBlank(branchSession.getLockKey())) { - return Collections.emptyList(); - } - - String lockKey = branchSession.getLockKey(); - String resourceId = branchSession.getResourceId(); - String xid = branchSession.getXid(); - long transactionId = branchSession.getTransactionId(); - long branchId = branchSession.getBranchId(); - - return collectRowLocks(lockKey, resourceId, xid, transactionId, branchId); - } - - /** - * Collect row locks list. - * - * @param lockKey the lock key - * @param resourceId the resource id - * @param xid the xid - * @return the list - */ - protected List collectRowLocks(String lockKey, String resourceId, String xid) { - return collectRowLocks(lockKey, resourceId, xid, XID.getTransactionId(xid), null); - } - - /** - * Collect row locks list. - * - * @param lockKey the lock key - * @param resourceId the resource id - * @param xid the xid - * @param transactionId the transaction id - * @param branchID the branch id - * @return the list - */ - protected List collectRowLocks(String lockKey, String resourceId, String xid, Long transactionId, - Long branchID) { - List locks = new ArrayList<>(); - - String[] tableGroupedLockKeys = lockKey.split(";"); - for (String tableGroupedLockKey : tableGroupedLockKeys) { - int idx = tableGroupedLockKey.indexOf(":"); - if (idx < 0) { - return locks; - } - String tableName = tableGroupedLockKey.substring(0, idx); - String mergedPKs = tableGroupedLockKey.substring(idx + 1); - if (StringUtils.isBlank(mergedPKs)) { - return locks; - } - String[] pks = mergedPKs.split(","); - if (pks == null || pks.length == 0) { - return locks; - } - for (String pk : pks) { - if (StringUtils.isNotBlank(pk)) { - RowLock rowLock = new RowLock(); - rowLock.setXid(xid); - rowLock.setTransactionId(transactionId); - rowLock.setBranchId(branchID); - rowLock.setTableName(tableName); - rowLock.setPk(pk); - rowLock.setResourceId(resourceId); - locks.add(rowLock); - } - } - } - return locks; - } - - @Override - public void updateLockStatus(String xid, LockStatus lockStatus) { - this.getLocker().updateLockStatus(xid, lockStatus); - } - -} diff --git a/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/lock/LockManager.java b/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/lock/LockManager.java deleted file mode 100644 index a655d93f..00000000 --- a/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/lock/LockManager.java +++ /dev/null @@ -1,106 +0,0 @@ -/* - * Copyright 1999-2019 Seata.io Group. - * - * Licensed 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 io.seata.server.lock; - -import io.seata.core.exception.TransactionException; -import io.seata.core.lock.RowLock; -import io.seata.core.model.LockStatus; -import io.seata.server.session.BranchSession; -import io.seata.server.session.GlobalSession; - -import java.util.List; - -/** - * The interface Lock manager. - * - * @author sharajava - */ -public interface LockManager { - - /** - * Acquire lock boolean. - * - * @param branchSession the branch session - * @return the boolean - * @throws TransactionException the transaction exception - */ - boolean acquireLock(BranchSession branchSession) throws TransactionException; - - /** - * Acquire lock boolean. - * - * @param branchSession the branch session - * @param autoCommit the auto commit - * @param skipCheckLock whether skip check lock or not - * @return the boolean - * @throws TransactionException the transaction exception - */ - boolean acquireLock(BranchSession branchSession, boolean autoCommit, boolean skipCheckLock) throws TransactionException; - - /** - * Un lock boolean. - * - * @param branchSession the branch session - * @return the boolean - * @throws TransactionException the transaction exception - */ - boolean releaseLock(BranchSession branchSession) throws TransactionException; - - /** - * Un lock boolean. - * - * @param globalSession the global session - * @return the boolean - * @throws TransactionException the transaction exception - */ - boolean releaseGlobalSessionLock(GlobalSession globalSession) throws TransactionException; - - /** - * Is lockable boolean. - * - * @param xid the xid - * @param resourceId the resource id - * @param lockKey the lock key - * @return the boolean - * @throws TransactionException the transaction exception - */ - boolean isLockable(String xid, String resourceId, String lockKey) throws TransactionException; - - /** - * Clean all locks. - * - * @throws TransactionException the transaction exception - */ - void cleanAllLocks() throws TransactionException; - - /** - * Collect row locks list.` - * - * @param branchSession the branch session - * @return the list - */ - List collectRowLocks(BranchSession branchSession); - - /** - * update lock status. - * @param xid the xid - * @param lockStatus the lock status - * @throws TransactionException the transaction exception - * - */ - void updateLockStatus(String xid, LockStatus lockStatus) throws TransactionException; - -} diff --git a/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/lock/LockerManagerFactory.java b/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/lock/LockerManagerFactory.java deleted file mode 100644 index b4aef847..00000000 --- a/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/lock/LockerManagerFactory.java +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Copyright 1999-2019 Seata.io Group. - * - * Licensed 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 io.seata.server.lock; - -import io.seata.common.loader.EnhancedServiceLoader; -import io.seata.config.Configuration; -import io.seata.config.ConfigurationFactory; -import io.seata.server.store.StoreConfig; -import io.seata.server.store.StoreConfig.LockMode; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * The type Lock manager factory. - * - * @author sharajava - */ -public class LockerManagerFactory { - - private static final Logger LOGGER = LoggerFactory.getLogger(LockerManagerFactory.class); - private static final Configuration CONFIG = ConfigurationFactory.getInstance(); - - /** - * the lock manager - */ - private static volatile LockManager LOCK_MANAGER; - - /** - * Get lock manager. - * - * @return the lock manager - */ - public static LockManager getLockManager() { - if (LOCK_MANAGER == null) { - init(); - } - return LOCK_MANAGER; - } - - public static void init() { - init(null); - } - - public static void init(LockMode lockMode) { - if (LOCK_MANAGER == null) { - synchronized (LockerManagerFactory.class) { - if (LOCK_MANAGER == null) { - if (null == lockMode) { - lockMode = StoreConfig.getLockMode(); - } - LOGGER.info("use lock store mode: {}", lockMode.getName()); - //if not exist the lock mode, throw exception - if (null != StoreConfig.StoreMode.get(lockMode.name())) { - LOCK_MANAGER = EnhancedServiceLoader.load(LockManager.class, lockMode.getName()); - } - } - } - } - } - -} diff --git a/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/lock/distributed/DistributedLockerFactory.java b/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/lock/distributed/DistributedLockerFactory.java deleted file mode 100644 index 362d2132..00000000 --- a/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/lock/distributed/DistributedLockerFactory.java +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Copyright 1999-2019 Seata.io Group. - * - * Licensed 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 io.seata.server.lock.distributed; - -import io.seata.common.loader.EnhancedServiceLoader; -import io.seata.common.loader.EnhancedServiceNotFoundException; -import io.seata.core.store.DefaultDistributedLocker; -import io.seata.core.store.DistributedLocker; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Distributed locker factory - * @author zhongxiang.wang - */ -public class DistributedLockerFactory { - - /** - * The constant LOGGER. - */ - private static final Logger LOGGER = LoggerFactory.getLogger(DistributedLockerFactory.class); - - private static volatile DistributedLocker DISTRIBUTED_LOCKER = null; - - /** - * Get the distributed locker by lockerType - * - * @param lockerType the locker type - * @return the distributed locker - */ - public static DistributedLocker getDistributedLocker(String lockerType) { - if (DISTRIBUTED_LOCKER == null) { - synchronized (DistributedLocker.class) { - if (DISTRIBUTED_LOCKER == null) { - DistributedLocker distributedLocker = null; - try { - if (!"file".equals(lockerType)) { - distributedLocker = EnhancedServiceLoader.load(DistributedLocker.class, lockerType); - } - } catch (EnhancedServiceNotFoundException ex) { - LOGGER.error("Get distributed locker failed: {}", ex.getMessage(), ex); - } - if (distributedLocker == null) { - distributedLocker = new DefaultDistributedLocker(); - } - DISTRIBUTED_LOCKER = distributedLocker; - } - } - } - return DISTRIBUTED_LOCKER; - } - - public static void cleanLocker() { - DISTRIBUTED_LOCKER = null; - } -} diff --git a/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/logging/listener/SystemPropertyLoggerContextListener.java b/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/logging/listener/SystemPropertyLoggerContextListener.java deleted file mode 100644 index c0c96598..00000000 --- a/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/logging/listener/SystemPropertyLoggerContextListener.java +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Copyright 1999-2019 Seata.io Group. - * - * Licensed 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 io.seata.server.logging.listener; - -import ch.qos.logback.classic.Level; -import ch.qos.logback.classic.Logger; -import ch.qos.logback.classic.LoggerContext; -import ch.qos.logback.classic.spi.LoggerContextListener; -import ch.qos.logback.core.Context; -import ch.qos.logback.core.spi.ContextAwareBase; -import ch.qos.logback.core.spi.LifeCycle; -import io.seata.core.constants.ConfigurationKeys; - -/** - * @author wang.liang - */ -public class SystemPropertyLoggerContextListener extends ContextAwareBase implements LoggerContextListener, LifeCycle { - - private boolean started = false; - - @Override - public void start() { - if (started) { - return; - } - - Context context = getContext(); - context.putProperty("RPC_PORT", System.getProperty(ConfigurationKeys.SERVER_SERVICE_PORT_CAMEL)); - - started = true; - } - - @Override - public void stop() { - } - - @Override - public boolean isStarted() { - return started; - } - - @Override - public boolean isResetResistant() { - return true; - } - - @Override - public void onStart(LoggerContext context) { - } - - @Override - public void onReset(LoggerContext context) { - } - - @Override - public void onStop(LoggerContext context) { - } - - @Override - public void onLevelChange(Logger logger, Level level) { - } -} \ No newline at end of file diff --git a/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/logging/logback/ExtendedWhitespaceThrowableProxyConverter.java b/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/logging/logback/ExtendedWhitespaceThrowableProxyConverter.java deleted file mode 100644 index c6bb4a10..00000000 --- a/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/logging/logback/ExtendedWhitespaceThrowableProxyConverter.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright 1999-2019 Seata.io Group. - * - * Licensed 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 io.seata.server.logging.logback; - -import ch.qos.logback.classic.pattern.ExtendedThrowableProxyConverter; -import ch.qos.logback.classic.spi.IThrowableProxy; -import ch.qos.logback.core.CoreConstants; - -/** - * {@link ExtendedThrowableProxyConverter} that adds some additional whitespace around the - * stack trace. - * Copied from spring-boot-xxx.jar by wang.liang - * @author Phillip Webb - */ -public class ExtendedWhitespaceThrowableProxyConverter extends ExtendedThrowableProxyConverter { - - @Override - protected String throwableProxyToString(IThrowableProxy tp) { - return "==>" + CoreConstants.LINE_SEPARATOR + super.throwableProxyToString(tp) - + "<==" + CoreConstants.LINE_SEPARATOR + CoreConstants.LINE_SEPARATOR; - } -} diff --git a/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/logging/logback/appender/EnhancedLogstashEncoder.java b/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/logging/logback/appender/EnhancedLogstashEncoder.java deleted file mode 100644 index 0b7689c1..00000000 --- a/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/logging/logback/appender/EnhancedLogstashEncoder.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright 1999-2019 Seata.io Group. - * - * Licensed 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 io.seata.server.logging.logback.appender; - -import net.logstash.logback.composite.JsonProvider; -import net.logstash.logback.composite.JsonProviders; -import net.logstash.logback.encoder.LogstashEncoder; - -import java.util.ArrayList; - -/** - * The type Enhanced logstash encoder - * - * @author wang.liang - * @since 1.5.0 - */ -public class EnhancedLogstashEncoder extends LogstashEncoder { - - /** - * set exclude provider - * - * @param excludedProviderClassName the excluded provider class name - */ - public void setExcludeProvider(String excludedProviderClassName) { - JsonProviders providers = getFormatter().getProviders(); - for (JsonProvider provider : new ArrayList<>(providers.getProviders())) { - if (provider.getClass().getName().equals(excludedProviderClassName)) { - providers.removeProvider((JsonProvider) provider); - } - } - } -} diff --git a/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/metrics/MeterIdConstants.java b/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/metrics/MeterIdConstants.java deleted file mode 100644 index 96f6ac5f..00000000 --- a/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/metrics/MeterIdConstants.java +++ /dev/null @@ -1,108 +0,0 @@ -/* - * Copyright 1999-2019 Seata.io Group. - * - * Licensed 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 io.seata.server.metrics; - -import io.seata.metrics.Id; -import io.seata.metrics.IdConstants; - -/** - * Constants for meter id in tc - * - * @author zhengyangyong - */ -public interface MeterIdConstants { - Id COUNTER_ACTIVE = new Id(IdConstants.SEATA_TRANSACTION) - .withTag(IdConstants.ROLE_KEY, IdConstants.ROLE_VALUE_TC) - .withTag(IdConstants.METER_KEY, IdConstants.METER_VALUE_COUNTER) - .withTag(IdConstants.STATUS_KEY, IdConstants.STATUS_VALUE_ACTIVE); - - Id COUNTER_COMMITTED = new Id(IdConstants.SEATA_TRANSACTION) - .withTag(IdConstants.ROLE_KEY, IdConstants.ROLE_VALUE_TC) - .withTag(IdConstants.METER_KEY, IdConstants.METER_VALUE_COUNTER) - .withTag(IdConstants.STATUS_KEY, IdConstants.STATUS_VALUE_COMMITTED); - - Id COUNTER_ROLLBACKED = new Id(IdConstants.SEATA_TRANSACTION) - .withTag(IdConstants.ROLE_KEY, IdConstants.ROLE_VALUE_TC) - .withTag(IdConstants.METER_KEY, IdConstants.METER_VALUE_COUNTER) - .withTag(IdConstants.STATUS_KEY, IdConstants.STATUS_VALUE_ROLLBACKED); - - Id COUNTER_AFTER_ROLLBACKED = new Id(IdConstants.SEATA_TRANSACTION) - .withTag(IdConstants.ROLE_KEY, IdConstants.ROLE_VALUE_TC) - .withTag(IdConstants.METER_KEY, IdConstants.METER_VALUE_COUNTER) - .withTag(IdConstants.STATUS_KEY, IdConstants.STATUS_VALUE_AFTER_ROLLBACKED_KEY); - - Id COUNTER_AFTER_COMMITTED = new Id(IdConstants.SEATA_TRANSACTION) - .withTag(IdConstants.ROLE_KEY, IdConstants.ROLE_VALUE_TC) - .withTag(IdConstants.METER_KEY, IdConstants.METER_VALUE_COUNTER) - .withTag(IdConstants.STATUS_KEY, IdConstants.STATUS_VALUE_AFTER_COMMITTED_KEY); - - - Id SUMMARY_COMMITTED = new Id(IdConstants.SEATA_TRANSACTION) - .withTag(IdConstants.ROLE_KEY, IdConstants.ROLE_VALUE_TC) - .withTag(IdConstants.METER_KEY, IdConstants.METER_VALUE_SUMMARY) - .withTag(IdConstants.STATUS_KEY, IdConstants.STATUS_VALUE_COMMITTED); - - Id SUMMARY_ROLLBACKED = new Id(IdConstants.SEATA_TRANSACTION) - .withTag(IdConstants.ROLE_KEY, IdConstants.ROLE_VALUE_TC) - .withTag(IdConstants.METER_KEY, IdConstants.METER_VALUE_SUMMARY) - .withTag(IdConstants.STATUS_KEY, IdConstants.STATUS_VALUE_ROLLBACKED); - - Id SUMMARY_FAILED = new Id(IdConstants.SEATA_TRANSACTION) - .withTag(IdConstants.ROLE_KEY, IdConstants.ROLE_VALUE_TC) - .withTag(IdConstants.METER_KEY, IdConstants.METER_VALUE_SUMMARY) - .withTag(IdConstants.STATUS_KEY, IdConstants.STATUS_VALUE_FAILED); - - Id SUMMARY_TWO_PHASE_TIMEOUT = new Id(IdConstants.SEATA_TRANSACTION) - .withTag(IdConstants.ROLE_KEY, IdConstants.ROLE_VALUE_TC) - .withTag(IdConstants.METER_KEY, IdConstants.METER_VALUE_SUMMARY) - .withTag(IdConstants.STATUS_KEY, IdConstants.STATUS_VALUE_TWO_PHASE_TIMEOUT); - - Id SUMMARY_AFTER_ROLLBACKED = new Id(IdConstants.SEATA_TRANSACTION) - .withTag(IdConstants.ROLE_KEY, IdConstants.ROLE_VALUE_TC) - .withTag(IdConstants.METER_KEY, IdConstants.METER_VALUE_SUMMARY) - .withTag(IdConstants.STATUS_KEY, IdConstants.STATUS_VALUE_AFTER_ROLLBACKED_KEY); - - Id SUMMARY_AFTER_COMMITTED = new Id(IdConstants.SEATA_TRANSACTION) - .withTag(IdConstants.ROLE_KEY, IdConstants.ROLE_VALUE_TC) - .withTag(IdConstants.METER_KEY, IdConstants.METER_VALUE_SUMMARY) - .withTag(IdConstants.STATUS_KEY, IdConstants.STATUS_VALUE_AFTER_COMMITTED_KEY); - - Id TIMER_COMMITTED = new Id(IdConstants.SEATA_TRANSACTION) - .withTag(IdConstants.ROLE_KEY, IdConstants.ROLE_VALUE_TC) - .withTag(IdConstants.METER_KEY, IdConstants.METER_VALUE_TIMER) - .withTag(IdConstants.STATUS_KEY, IdConstants.STATUS_VALUE_COMMITTED); - - Id TIMER_ROLLBACK = new Id(IdConstants.SEATA_TRANSACTION) - .withTag(IdConstants.ROLE_KEY, IdConstants.ROLE_VALUE_TC) - .withTag(IdConstants.METER_KEY, IdConstants.METER_VALUE_TIMER) - .withTag(IdConstants.STATUS_KEY, IdConstants.STATUS_VALUE_ROLLBACKED); - - Id TIMER_FAILED = new Id(IdConstants.SEATA_TRANSACTION) - .withTag(IdConstants.ROLE_KEY, IdConstants.ROLE_VALUE_TC) - .withTag(IdConstants.METER_KEY, IdConstants.METER_VALUE_TIMER) - .withTag(IdConstants.STATUS_KEY, IdConstants.STATUS_VALUE_FAILED); - - Id TIMER_AFTER_ROLLBACKED = new Id(IdConstants.SEATA_TRANSACTION) - .withTag(IdConstants.ROLE_KEY, IdConstants.ROLE_VALUE_TC) - .withTag(IdConstants.METER_KEY, IdConstants.METER_VALUE_TIMER) - .withTag(IdConstants.STATUS_KEY, IdConstants.STATUS_VALUE_AFTER_ROLLBACKED_KEY); - - Id TIMER_AFTER_COMMITTED = new Id(IdConstants.SEATA_TRANSACTION) - .withTag(IdConstants.ROLE_KEY, IdConstants.ROLE_VALUE_TC) - .withTag(IdConstants.METER_KEY, IdConstants.METER_VALUE_TIMER) - .withTag(IdConstants.STATUS_KEY, IdConstants.STATUS_VALUE_AFTER_COMMITTED_KEY); - -} diff --git a/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/metrics/MetricsManager.java b/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/metrics/MetricsManager.java deleted file mode 100644 index bad1c27c..00000000 --- a/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/metrics/MetricsManager.java +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright 1999-2019 Seata.io Group. - * - * Licensed 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 io.seata.server.metrics; - -import io.seata.config.ConfigurationFactory; -import io.seata.core.constants.ConfigurationKeys; -import io.seata.metrics.exporter.Exporter; -import io.seata.metrics.exporter.ExporterFactory; -import io.seata.metrics.registry.Registry; -import io.seata.metrics.registry.RegistryFactory; -import io.seata.server.event.EventBusManager; - -import java.util.List; - -import static io.seata.common.DefaultValues.DEFAULT_METRICS_ENABLED; - -/** - * Metrics manager for init - * - * @author zhengyangyong - */ -public class MetricsManager { - private static class SingletonHolder { - private static MetricsManager INSTANCE = new MetricsManager(); - } - - public static final MetricsManager get() { - return SingletonHolder.INSTANCE; - } - - private Registry registry; - - public Registry getRegistry() { - return registry; - } - - public void init() { - boolean enabled = ConfigurationFactory.getInstance().getBoolean( - ConfigurationKeys.METRICS_PREFIX + ConfigurationKeys.METRICS_ENABLED, DEFAULT_METRICS_ENABLED); - if (enabled) { - registry = RegistryFactory.getInstance(); - if (registry != null) { - List exporters = ExporterFactory.getInstanceList(); - //only at least one metrics exporter implement had imported in pom then need register MetricsSubscriber - if (exporters.size() != 0) { - exporters.forEach(exporter -> exporter.setRegistry(registry)); - EventBusManager.get().register(new MetricsSubscriber(registry)); - } - } - } - } -} diff --git a/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/metrics/MetricsPublisher.java b/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/metrics/MetricsPublisher.java deleted file mode 100644 index f0db1e52..00000000 --- a/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/metrics/MetricsPublisher.java +++ /dev/null @@ -1,97 +0,0 @@ -/* - * Copyright 1999-2019 Seata.io Group. - * - * Licensed 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 io.seata.server.metrics; - -import io.seata.core.event.EventBus; -import io.seata.core.event.GlobalTransactionEvent; -import io.seata.core.model.GlobalStatus; -import io.seata.server.event.EventBusManager; -import io.seata.server.session.GlobalSession; - -/** - * The type Metrics publisher. - * - * @author slievrly - */ -public class MetricsPublisher { - - private static final EventBus EVENT_BUS = EventBusManager.get(); - - /** - * post end event - * - * @param globalSession the global session - * @param retryGlobal the retry global - * @param retryBranch the retry branch - */ - public static void postSessionDoneEvent(final GlobalSession globalSession, boolean retryGlobal, - boolean retryBranch) { - postSessionDoneEvent(globalSession, globalSession.getStatus(), retryGlobal, retryBranch); - } - - /** - * post end event (force specified state) - * - * @param globalSession the global session - * @param status the global status - * @param retryGlobal the retry global - * @param retryBranch the retry branch - */ - public static void postSessionDoneEvent(final GlobalSession globalSession, GlobalStatus status, boolean retryGlobal, - boolean retryBranch) { - postSessionDoneEvent(globalSession, status.name(), retryGlobal, globalSession.getBeginTime(), retryBranch); - } - - /** - * Post session done event. - * - * @param globalSession the global session - * @param status the status - * @param retryGlobal the retry global - * @param beginTime the begin time - * @param retryBranch the retry branch - */ - public static void postSessionDoneEvent(final GlobalSession globalSession, String status, boolean retryGlobal, long beginTime, boolean retryBranch) { - EVENT_BUS.post(new GlobalTransactionEvent(globalSession.getTransactionId(), GlobalTransactionEvent.ROLE_TC, - globalSession.getTransactionName(), globalSession.getApplicationId(), - globalSession.getTransactionServiceGroup(), beginTime, System.currentTimeMillis(), status, retryGlobal, retryBranch)); - } - - /** - * Post session doing event. - * - * @param globalSession the global session - * @param retryGlobal the retry global - */ - public static void postSessionDoingEvent(final GlobalSession globalSession, boolean retryGlobal) { - postSessionDoingEvent(globalSession, globalSession.getStatus().name(), retryGlobal, false); - } - - /** - * Post session doing event. - * - * @param globalSession the global session - * @param status the status - * @param retryGlobal the retry global - * @param retryBranch the retry branch - */ - public static void postSessionDoingEvent(final GlobalSession globalSession, String status, boolean retryGlobal, - boolean retryBranch) { - EVENT_BUS.post(new GlobalTransactionEvent(globalSession.getTransactionId(), GlobalTransactionEvent.ROLE_TC, - globalSession.getTransactionName(), globalSession.getApplicationId(), - globalSession.getTransactionServiceGroup(), globalSession.getBeginTime(), null, status, retryGlobal, retryBranch)); - } -} diff --git a/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/metrics/MetricsSubscriber.java b/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/metrics/MetricsSubscriber.java deleted file mode 100644 index 277cee08..00000000 --- a/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/metrics/MetricsSubscriber.java +++ /dev/null @@ -1,214 +0,0 @@ -/* - * Copyright 1999-2019 Seata.io Group. - * - * Licensed 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 io.seata.server.metrics; - -import com.google.common.eventbus.Subscribe; -import io.seata.core.event.GlobalTransactionEvent; -import io.seata.core.model.GlobalStatus; -import io.seata.metrics.registry.Registry; -import io.seata.server.event.EventBusManager; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.util.HashMap; -import java.util.Map; -import java.util.concurrent.TimeUnit; -import java.util.function.Consumer; - -import static io.seata.metrics.IdConstants.*; - -/** - * Event subscriber for metrics - * - * @author zhengyangyong - */ -public class MetricsSubscriber { - - private static final Logger LOGGER = LoggerFactory.getLogger(MetricsSubscriber.class); - private final Registry registry; - - private final Map> consumers; - - public MetricsSubscriber(Registry registry) { - this.registry = registry; - consumers = new HashMap<>(); - consumers.put(GlobalStatus.Begin.name(), this::processGlobalStatusBegin); - consumers.put(GlobalStatus.Committed.name(), this::processGlobalStatusCommitted); - consumers.put(GlobalStatus.Rollbacked.name(), this::processGlobalStatusRollbacked); - - consumers.put(GlobalStatus.CommitFailed.name(), this::processGlobalStatusCommitFailed); - consumers.put(GlobalStatus.RollbackFailed.name(), this::processGlobalStatusRollbackFailed); - consumers.put(GlobalStatus.TimeoutRollbacked.name(), this::processGlobalStatusTimeoutRollbacked); - consumers.put(GlobalStatus.TimeoutRollbackFailed.name(), this::processGlobalStatusTimeoutRollbackFailed); - - consumers.put(GlobalStatus.CommitRetryTimeout.name(), this::processGlobalStatusCommitRetryTimeout); - consumers.put(GlobalStatus.RollbackRetryTimeout.name(), this::processGlobalStatusTimeoutRollbackRetryTimeout); - - consumers.put(STATUS_VALUE_AFTER_COMMITTED_KEY, this::processAfterGlobalCommitted); - consumers.put(STATUS_VALUE_AFTER_ROLLBACKED_KEY, this::processAfterGlobalRollbacked); - } - - private void processGlobalStatusBegin(GlobalTransactionEvent event) { - if (LOGGER.isDebugEnabled()) { - LOGGER.debug("accept new event,xid:{},event:{}", event.getId(), event); - for (Object object : EventBusManager.get().getSubscribers()) { - LOGGER.debug("subscribe:{},threadName:{}", object.toString(), Thread.currentThread().getName()); - } - } - registry.getCounter(MeterIdConstants.COUNTER_ACTIVE.withTag(APP_ID_KEY, event.getApplicationId()) - .withTag(GROUP_KEY, event.getGroup())).increase(1); - } - - private void processGlobalStatusCommitted(GlobalTransactionEvent event) { - if (event.isRetryGlobal()) { - return; - } - decreaseActive(event); - registry.getCounter(MeterIdConstants.COUNTER_COMMITTED - .withTag(APP_ID_KEY, event.getApplicationId()) - .withTag(GROUP_KEY, event.getGroup())).increase(1); - registry.getSummary(MeterIdConstants.SUMMARY_COMMITTED - .withTag(APP_ID_KEY, event.getApplicationId()) - .withTag(GROUP_KEY, event.getGroup())).increase(1); - registry.getTimer(MeterIdConstants.TIMER_COMMITTED - .withTag(APP_ID_KEY, event.getApplicationId()) - .withTag(GROUP_KEY, event.getGroup())) - .record(event.getEndTime() - event.getBeginTime(), TimeUnit.MILLISECONDS); - } - - private void processGlobalStatusRollbacked(GlobalTransactionEvent event) { - if (event.isRetryGlobal()) { - return; - } - decreaseActive(event); - registry.getCounter(MeterIdConstants.COUNTER_ROLLBACKED - .withTag(APP_ID_KEY, event.getApplicationId()) - .withTag(GROUP_KEY, event.getGroup())).increase(1); - registry.getSummary(MeterIdConstants.SUMMARY_ROLLBACKED - .withTag(APP_ID_KEY, event.getApplicationId()) - .withTag(GROUP_KEY, event.getGroup())).increase(1); - registry.getTimer(MeterIdConstants.TIMER_ROLLBACK - .withTag(APP_ID_KEY, event.getApplicationId()) - .withTag(GROUP_KEY, event.getGroup())) - .record(event.getEndTime() - event.getBeginTime(), TimeUnit.MILLISECONDS); - } - - private void processAfterGlobalRollbacked(GlobalTransactionEvent event) { - if (event.isRetryGlobal() && event.isRetryBranch()) { - decreaseActive(event); - } - registry.getCounter(MeterIdConstants.COUNTER_AFTER_ROLLBACKED - .withTag(APP_ID_KEY, event.getApplicationId()) - .withTag(GROUP_KEY, event.getGroup())).increase(1); - registry.getSummary(MeterIdConstants.SUMMARY_AFTER_ROLLBACKED - .withTag(APP_ID_KEY, event.getApplicationId()) - .withTag(GROUP_KEY, event.getGroup())).increase(1); - registry.getTimer(MeterIdConstants.TIMER_AFTER_ROLLBACKED - .withTag(APP_ID_KEY, event.getApplicationId()) - .withTag(GROUP_KEY, event.getGroup())) - .record(event.getEndTime() - event.getBeginTime(), TimeUnit.MILLISECONDS); - } - - private void processAfterGlobalCommitted(GlobalTransactionEvent event) { - if (event.isRetryGlobal() && event.isRetryBranch()) { - decreaseActive(event); - } - registry.getCounter(MeterIdConstants.COUNTER_AFTER_COMMITTED - .withTag(APP_ID_KEY, event.getApplicationId()) - .withTag(GROUP_KEY, event.getGroup())).increase(1); - registry.getSummary(MeterIdConstants.SUMMARY_AFTER_COMMITTED - .withTag(APP_ID_KEY, event.getApplicationId()) - .withTag(GROUP_KEY, event.getGroup())).increase(1); - registry.getTimer(MeterIdConstants.TIMER_AFTER_COMMITTED - .withTag(APP_ID_KEY, event.getApplicationId()) - .withTag(GROUP_KEY, event.getGroup())) - .record(event.getEndTime() - event.getBeginTime(), TimeUnit.MILLISECONDS); - } - - private void processGlobalStatusCommitFailed(GlobalTransactionEvent event) { - decreaseActive(event); - reportFailed(event); - } - - private void processGlobalStatusRollbackFailed(GlobalTransactionEvent event) { - decreaseActive(event); - reportFailed(event); - } - - private void processGlobalStatusTimeoutRollbacked(GlobalTransactionEvent event) { - decreaseActive(event); - } - - private void processGlobalStatusTimeoutRollbackFailed(GlobalTransactionEvent event) { - decreaseActive(event); - reportTwoPhaseTimeout(event); - } - - private void processGlobalStatusCommitRetryTimeout(GlobalTransactionEvent event) { - decreaseActive(event); - reportTwoPhaseTimeout(event); - } - - private void processGlobalStatusTimeoutRollbackRetryTimeout(GlobalTransactionEvent event) { - decreaseActive(event); - } - - private void decreaseActive(GlobalTransactionEvent event) { - registry.getCounter(MeterIdConstants.COUNTER_ACTIVE - .withTag(APP_ID_KEY, event.getApplicationId()) - .withTag(GROUP_KEY, event.getGroup())).decrease(1); - } - - private void reportFailed(GlobalTransactionEvent event) { - registry.getSummary(MeterIdConstants.SUMMARY_FAILED - .withTag(APP_ID_KEY, event.getApplicationId()) - .withTag(GROUP_KEY, event.getGroup())).increase(1); - registry.getTimer(MeterIdConstants.TIMER_FAILED - .withTag(APP_ID_KEY, event.getApplicationId()) - .withTag(GROUP_KEY, event.getGroup())) - .record(event.getEndTime() - event.getBeginTime(), TimeUnit.MILLISECONDS); - } - - private void reportTwoPhaseTimeout(GlobalTransactionEvent event) { - registry.getSummary(MeterIdConstants.SUMMARY_TWO_PHASE_TIMEOUT - .withTag(APP_ID_KEY, event.getApplicationId()) - .withTag(GROUP_KEY, event.getGroup())).increase(1); - } - - - - @Subscribe - public void recordGlobalTransactionEventForMetrics(GlobalTransactionEvent event) { - if (registry != null && consumers.containsKey(event.getStatus())) { - consumers.get(event.getStatus()).accept(event); - } - } - - @Override - public boolean equals(Object obj) { - return this.getClass().getName().equals(obj.getClass().getName()); - } - - /** - * PMD check - * SuppressWarnings("checkstyle:EqualsHashCode") - * @return the hash code - */ - @Override - public int hashCode() { - return super.hashCode(); - } -} diff --git a/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/session/AbstractSessionManager.java b/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/session/AbstractSessionManager.java deleted file mode 100644 index 2668c2c5..00000000 --- a/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/session/AbstractSessionManager.java +++ /dev/null @@ -1,199 +0,0 @@ -/* - * Copyright 1999-2019 Seata.io Group. - * - * Licensed 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 io.seata.server.session; - -import io.seata.core.exception.BranchTransactionException; -import io.seata.core.exception.GlobalTransactionException; -import io.seata.core.exception.TransactionException; -import io.seata.core.exception.TransactionExceptionCode; -import io.seata.core.model.BranchStatus; -import io.seata.core.model.GlobalStatus; -import io.seata.core.model.LockStatus; -import io.seata.server.store.SessionStorable; -import io.seata.server.store.TransactionStoreManager; -import io.seata.server.store.TransactionStoreManager.LogOperation; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * The type Abstract session manager. - */ -public abstract class AbstractSessionManager implements SessionManager, SessionLifecycleListener { - - /** - * The constant LOGGER. - */ - protected static final Logger LOGGER = LoggerFactory.getLogger(AbstractSessionManager.class); - - /** - * The Transaction store manager. - */ - protected TransactionStoreManager transactionStoreManager; - - /** - * The Name. - */ - protected String name; - - /** - * Instantiates a new Abstract session manager. - */ - public AbstractSessionManager() { - } - - /** - * Instantiates a new Abstract session manager. - * - * @param name the name - */ - public AbstractSessionManager(String name) { - this.name = name; - } - - @Override - public void addGlobalSession(GlobalSession session) throws TransactionException { - if (LOGGER.isDebugEnabled()) { - LOGGER.debug("MANAGER[{}] SESSION[{}] {}", name, session, LogOperation.GLOBAL_ADD); - } - writeSession(LogOperation.GLOBAL_ADD, session); - } - - @Override - public void updateGlobalSessionStatus(GlobalSession session, GlobalStatus status) throws TransactionException { - if (LOGGER.isDebugEnabled()) { - LOGGER.debug("MANAGER[{}] SESSION[{}] {}", name, session, LogOperation.GLOBAL_UPDATE); - } - if (GlobalStatus.Rollbacking == status) { - session.getBranchSessions().forEach(i -> i.setLockStatus(LockStatus.Rollbacking)); - } - writeSession(LogOperation.GLOBAL_UPDATE, session); - } - - @Override - public void removeGlobalSession(GlobalSession session) throws TransactionException { - if (LOGGER.isDebugEnabled()) { - LOGGER.debug("MANAGER[{}] SESSION[{}] {}", name, session, LogOperation.GLOBAL_REMOVE); - } - writeSession(LogOperation.GLOBAL_REMOVE, session); - } - - @Override - public void addBranchSession(GlobalSession session, BranchSession branchSession) throws TransactionException { - if (LOGGER.isDebugEnabled()) { - LOGGER.debug("MANAGER[{}] SESSION[{}] {}", name, branchSession, LogOperation.BRANCH_ADD); - } - writeSession(LogOperation.BRANCH_ADD, branchSession); - } - - @Override - public void updateBranchSessionStatus(BranchSession branchSession, BranchStatus status) - throws TransactionException { - if (LOGGER.isDebugEnabled()) { - LOGGER.debug("MANAGER[{}] SESSION[{}] {}", name, branchSession, LogOperation.BRANCH_UPDATE); - } - writeSession(LogOperation.BRANCH_UPDATE, branchSession); - } - - @Override - public void removeBranchSession(GlobalSession globalSession, BranchSession branchSession) - throws TransactionException { - if (LOGGER.isDebugEnabled()) { - LOGGER.debug("MANAGER[{}] SESSION[{}] {}", name, branchSession, LogOperation.BRANCH_REMOVE); - } - writeSession(LogOperation.BRANCH_REMOVE, branchSession); - } - - @Override - public void onBegin(GlobalSession globalSession) throws TransactionException { - addGlobalSession(globalSession); - } - - @Override - public void onStatusChange(GlobalSession globalSession, GlobalStatus status) throws TransactionException { - updateGlobalSessionStatus(globalSession, status); - } - - @Override - public void onBranchStatusChange(GlobalSession globalSession, BranchSession branchSession, BranchStatus status) - throws TransactionException { - updateBranchSessionStatus(branchSession, status); - } - - @Override - public void onAddBranch(GlobalSession globalSession, BranchSession branchSession) throws TransactionException { - addBranchSession(globalSession, branchSession); - } - - @Override - public void onRemoveBranch(GlobalSession globalSession, BranchSession branchSession) throws TransactionException { - removeBranchSession(globalSession, branchSession); - } - - @Override - public void onClose(GlobalSession globalSession) throws TransactionException { - globalSession.setActive(false); - } - - @Override - public void onSuccessEnd(GlobalSession globalSession) throws TransactionException { - removeGlobalSession(globalSession); - } - - @Override - public void onFailEnd(GlobalSession globalSession) throws TransactionException { - LOGGER.info("xid:{} fail end, transaction:{}",globalSession.getXid(),globalSession.toString()); - } - - private void writeSession(LogOperation logOperation, SessionStorable sessionStorable) throws TransactionException { - if (!transactionStoreManager.writeSession(logOperation, sessionStorable)) { - if (LogOperation.GLOBAL_ADD.equals(logOperation)) { - throw new GlobalTransactionException(TransactionExceptionCode.FailedWriteSession, - "Fail to store global session"); - } else if (LogOperation.GLOBAL_UPDATE.equals(logOperation)) { - throw new GlobalTransactionException(TransactionExceptionCode.FailedWriteSession, - "Fail to update global session"); - } else if (LogOperation.GLOBAL_REMOVE.equals(logOperation)) { - throw new GlobalTransactionException(TransactionExceptionCode.FailedWriteSession, - "Fail to remove global session"); - } else if (LogOperation.BRANCH_ADD.equals(logOperation)) { - throw new BranchTransactionException(TransactionExceptionCode.FailedWriteSession, - "Fail to store branch session"); - } else if (LogOperation.BRANCH_UPDATE.equals(logOperation)) { - throw new BranchTransactionException(TransactionExceptionCode.FailedWriteSession, - "Fail to update branch session"); - } else if (LogOperation.BRANCH_REMOVE.equals(logOperation)) { - throw new BranchTransactionException(TransactionExceptionCode.FailedWriteSession, - "Fail to remove branch session"); - } else { - throw new BranchTransactionException(TransactionExceptionCode.FailedWriteSession, - "Unknown LogOperation:" + logOperation.name()); - } - } - } - - @Override - public void destroy() { - } - - /** - * Sets transaction store manager. - * - * @param transactionStoreManager the transaction store manager - */ - public void setTransactionStoreManager(TransactionStoreManager transactionStoreManager) { - this.transactionStoreManager = transactionStoreManager; - } -} diff --git a/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/session/BranchSession.java b/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/session/BranchSession.java deleted file mode 100644 index daaf2304..00000000 --- a/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/session/BranchSession.java +++ /dev/null @@ -1,473 +0,0 @@ -/* - * Copyright 1999-2019 Seata.io Group. - * - * Licensed 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 io.seata.server.session; - -import io.seata.common.util.CompressUtil; -import io.seata.core.exception.TransactionException; -import io.seata.core.model.BranchStatus; -import io.seata.core.model.BranchType; -import io.seata.core.model.LockStatus; -import io.seata.server.lock.LockerManagerFactory; -import io.seata.server.storage.file.lock.FileLocker; -import io.seata.server.store.SessionStorable; -import io.seata.server.store.StoreConfig; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.io.IOException; -import java.nio.ByteBuffer; -import java.util.Set; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentMap; - -import static io.seata.core.model.LockStatus.Locked; - -/** - * The type Branch session. - * - * @author sharajava - */ -public class BranchSession implements Lockable, Comparable, SessionStorable { - - private static final Logger LOGGER = LoggerFactory.getLogger(BranchSession.class); - - private static final int MAX_BRANCH_SESSION_SIZE = StoreConfig.getMaxBranchSessionSize(); - - private static ThreadLocal byteBufferThreadLocal = ThreadLocal.withInitial(() -> ByteBuffer.allocate( - MAX_BRANCH_SESSION_SIZE)); - - private String xid; - - private long transactionId; - - private long branchId; - - private String resourceGroupId; - - private String resourceId; - - private String lockKey; - - private BranchType branchType; - - private BranchStatus status = BranchStatus.Unknown; - - private String clientId; - - private String applicationData; - - private LockStatus lockStatus = Locked; - - private ConcurrentMap> lockHolder - = new ConcurrentHashMap<>(); - - /** - * Gets application data. - * - * @return the application data - */ - public String getApplicationData() { - return applicationData; - } - - /** - * Sets application data. - * - * @param applicationData the application data - */ - public void setApplicationData(String applicationData) { - this.applicationData = applicationData; - } - - /** - * Gets resource group id. - * - * @return the resource group id - */ - public String getResourceGroupId() { - return resourceGroupId; - } - - /** - * Sets resource group id. - * - * @param resourceGroupId the resource group id - */ - public void setResourceGroupId(String resourceGroupId) { - this.resourceGroupId = resourceGroupId; - } - - /** - * Gets client id. - * - * @return the client id - */ - public String getClientId() { - return clientId; - } - - /** - * Sets client id. - * - * @param clientId the client id - */ - public void setClientId(String clientId) { - this.clientId = clientId; - } - - /** - * Gets resource id. - * - * @return the resource id - */ - public String getResourceId() { - return resourceId; - } - - /** - * Sets resource id. - * - * @param resourceId the resource id - */ - public void setResourceId(String resourceId) { - this.resourceId = resourceId; - } - - /** - * Gets lock key. - * - * @return the lock key - */ - public String getLockKey() { - return lockKey; - } - - /** - * Sets lock key. - * - * @param lockKey the lock key - */ - public void setLockKey(String lockKey) { - this.lockKey = lockKey; - } - - /** - * Gets branch type. - * - * @return the branch type - */ - public BranchType getBranchType() { - return branchType; - } - - /** - * Sets branch type. - * - * @param branchType the branch type - */ - public void setBranchType(BranchType branchType) { - this.branchType = branchType; - } - - /** - * Gets status. - * - * @return the status - */ - public BranchStatus getStatus() { - return status; - } - - /** - * Sets status. - * - * @param status the status - */ - public void setStatus(BranchStatus status) { - this.status = status; - } - - /** - * Gets transaction id. - * - * @return the transaction id - */ - public long getTransactionId() { - return transactionId; - } - - /** - * Sets transaction id. - * - * @param transactionId the transaction id - */ - public void setTransactionId(long transactionId) { - this.transactionId = transactionId; - } - - /** - * Gets branch id. - * - * @return the branch id - */ - public long getBranchId() { - return branchId; - } - - /** - * Sets branch id. - * - * @param branchId the branch id - */ - public void setBranchId(long branchId) { - this.branchId = branchId; - } - - /** - * Gets xid. - * - * @return the xid - */ - public String getXid() { - return xid; - } - - /** - * Sets xid. - * - * @param xid the xid - */ - public void setXid(String xid) { - this.xid = xid; - } - - @Override - public String toString() { - return "BR:" + branchId + "/" + transactionId; - } - - @Override - public int compareTo(BranchSession o) { - return Long.compare(this.branchId, o.branchId); - } - - public boolean canBeCommittedAsync() { - return branchType == BranchType.AT || status == BranchStatus.PhaseOne_Failed; - } - - /** - * Gets lock holder. - * - * @return the lock holder - */ - public ConcurrentMap> getLockHolder() { - return lockHolder; - } - - @Override - public boolean lock() throws TransactionException { - return this.lock(true, false); - } - - public boolean lock(boolean autoCommit, boolean skipCheckLock) throws TransactionException { - if (this.getBranchType().equals(BranchType.AT)) { - return LockerManagerFactory.getLockManager().acquireLock(this, autoCommit, skipCheckLock); - } - return true; - } - - @Override - public boolean unlock() throws TransactionException { - if (this.getBranchType() == BranchType.AT) { - return LockerManagerFactory.getLockManager().releaseLock(this); - } - return true; - } - - public boolean isAT() { - return this.getBranchType() == BranchType.AT; - } - - public LockStatus getLockStatus() { - return lockStatus; - } - - public void setLockStatus(LockStatus lockStatus) { - this.lockStatus = lockStatus; - } - - @Override - public byte[] encode() { - - byte[] resourceIdBytes = resourceId != null ? resourceId.getBytes() : null; - - byte[] lockKeyBytes = lockKey != null ? lockKey.getBytes() : null; - - byte[] clientIdBytes = clientId != null ? clientId.getBytes() : null; - - byte[] applicationDataBytes = applicationData != null ? applicationData.getBytes() : null; - - byte[] xidBytes = xid != null ? xid.getBytes() : null; - - byte branchTypeByte = branchType != null ? (byte) branchType.ordinal() : -1; - - int size = calBranchSessionSize(resourceIdBytes, lockKeyBytes, clientIdBytes, applicationDataBytes, xidBytes); - - if (size > MAX_BRANCH_SESSION_SIZE) { - if (lockKeyBytes == null) { - throw new RuntimeException("branch session size exceeded, size : " + size + " maxBranchSessionSize : " - + MAX_BRANCH_SESSION_SIZE); - } - // try compress lockkey - try { - size -= lockKeyBytes.length; - lockKeyBytes = CompressUtil.compress(lockKeyBytes); - } catch (IOException e) { - LOGGER.error("compress lockKey error", e); - } finally { - size += lockKeyBytes.length; - } - - if (size > MAX_BRANCH_SESSION_SIZE) { - throw new RuntimeException( - "compress branch session size exceeded, compressSize : " + size + " maxBranchSessionSize : " - + MAX_BRANCH_SESSION_SIZE); - } - } - - ByteBuffer byteBuffer = byteBufferThreadLocal.get(); - //recycle - byteBuffer.clear(); - - byteBuffer.putLong(transactionId); - byteBuffer.putLong(branchId); - - if (resourceIdBytes != null) { - byteBuffer.putInt(resourceIdBytes.length); - byteBuffer.put(resourceIdBytes); - } else { - byteBuffer.putInt(0); - } - - if (lockKeyBytes != null) { - byteBuffer.putInt(lockKeyBytes.length); - byteBuffer.put(lockKeyBytes); - } else { - byteBuffer.putInt(0); - } - - if (clientIdBytes != null) { - byteBuffer.putShort((short)clientIdBytes.length); - byteBuffer.put(clientIdBytes); - } else { - byteBuffer.putShort((short)0); - } - - if (applicationDataBytes != null) { - byteBuffer.putInt(applicationDataBytes.length); - byteBuffer.put(applicationDataBytes); - } else { - byteBuffer.putInt(0); - } - - if (xidBytes != null) { - byteBuffer.putInt(xidBytes.length); - byteBuffer.put(xidBytes); - } else { - byteBuffer.putInt(0); - } - - byteBuffer.put(branchTypeByte); - - byteBuffer.put((byte)status.getCode()); - byteBuffer.put((byte)lockStatus.getCode()); - byteBuffer.flip(); - byte[] result = new byte[byteBuffer.limit()]; - byteBuffer.get(result); - return result; - } - - private int calBranchSessionSize(byte[] resourceIdBytes, byte[] lockKeyBytes, byte[] clientIdBytes, - byte[] applicationDataBytes, byte[] xidBytes) { - final int size = 8 // trascationId - + 8 // branchId - + 4 // resourceIdBytes.length - + 4 // lockKeyBytes.length - + 2 // clientIdBytes.length - + 4 // applicationDataBytes.length - + 4 // xidBytes.size - + 1 // statusCode - + (resourceIdBytes == null ? 0 : resourceIdBytes.length) - + (lockKeyBytes == null ? 0 : lockKeyBytes.length) - + (clientIdBytes == null ? 0 : clientIdBytes.length) - + (applicationDataBytes == null ? 0 : applicationDataBytes.length) - + (xidBytes == null ? 0 : xidBytes.length) - + 1; //branchType - return size; - } - - @Override - public void decode(byte[] a) { - ByteBuffer byteBuffer = ByteBuffer.wrap(a); - this.transactionId = byteBuffer.getLong(); - this.branchId = byteBuffer.getLong(); - int resourceLen = byteBuffer.getInt(); - if (resourceLen > 0) { - byte[] byResource = new byte[resourceLen]; - byteBuffer.get(byResource); - this.resourceId = new String(byResource); - } - int lockKeyLen = byteBuffer.getInt(); - if (lockKeyLen > 0) { - byte[] byLockKey = new byte[lockKeyLen]; - byteBuffer.get(byLockKey); - if (CompressUtil.isCompressData(byLockKey)) { - try { - this.lockKey = new String(CompressUtil.uncompress(byLockKey)); - } catch (IOException e) { - throw new RuntimeException("decompress lockKey error", e); - } - } else { - this.lockKey = new String(byLockKey); - } - - } - short clientIdLen = byteBuffer.getShort(); - if (clientIdLen > 0) { - byte[] byClientId = new byte[clientIdLen]; - byteBuffer.get(byClientId); - this.clientId = new String(byClientId); - } - int applicationDataLen = byteBuffer.getInt(); - if (applicationDataLen > 0) { - byte[] byApplicationData = new byte[applicationDataLen]; - byteBuffer.get(byApplicationData); - this.applicationData = new String(byApplicationData); - } - int xidLen = byteBuffer.getInt(); - if (xidLen > 0) { - byte[] xidBytes = new byte[xidLen]; - byteBuffer.get(xidBytes); - this.xid = new String(xidBytes); - } - int branchTypeId = byteBuffer.get(); - if (branchTypeId >= 0) { - this.branchType = BranchType.values()[branchTypeId]; - } - this.status = BranchStatus.get(byteBuffer.get()); - } - -} diff --git a/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/session/BranchSessionHandler.java b/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/session/BranchSessionHandler.java deleted file mode 100644 index 3523018b..00000000 --- a/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/session/BranchSessionHandler.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright 1999-2019 Seata.io Group. - * - * Licensed 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 io.seata.server.session; - -import io.seata.core.exception.TransactionException; - -/** - * The Functional Interface Branch session handler - * - * @author wang.liang - * @since 1.5.0 - */ -@FunctionalInterface -public interface BranchSessionHandler { - - Boolean CONTINUE = null; - - /** - * Handle branch session. - * - * @param branchSession the branch session - * @return the handle result - * @throws TransactionException the transaction exception - */ - Boolean handle(BranchSession branchSession) throws TransactionException; -} diff --git a/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/session/GlobalSession.java b/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/session/GlobalSession.java deleted file mode 100644 index 8f6c39ce..00000000 --- a/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/session/GlobalSession.java +++ /dev/null @@ -1,771 +0,0 @@ -/* - * Copyright 1999-2019 Seata.io Group. - * - * Licensed 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 io.seata.server.session; - -import io.seata.common.Constants; -import io.seata.common.DefaultValues; -import io.seata.common.XID; -import io.seata.common.util.StringUtils; -import io.seata.config.ConfigurationFactory; -import io.seata.core.constants.ConfigurationKeys; -import io.seata.core.exception.GlobalTransactionException; -import io.seata.core.exception.TransactionException; -import io.seata.core.exception.TransactionExceptionCode; -import io.seata.core.model.BranchStatus; -import io.seata.core.model.BranchType; -import io.seata.core.model.GlobalStatus; -import io.seata.core.model.LockStatus; -import io.seata.server.UUIDGenerator; -import io.seata.server.lock.LockerManagerFactory; -import io.seata.server.store.SessionStorable; -import io.seata.server.store.StoreConfig; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.nio.ByteBuffer; -import java.util.*; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.locks.Lock; -import java.util.concurrent.locks.ReentrantLock; - -import static io.seata.core.model.GlobalStatus.*; - -/** - * The type Global session. - * - * @author sharajava - */ -public class GlobalSession implements SessionLifecycle, SessionStorable { - - private static final Logger LOGGER = LoggerFactory.getLogger(GlobalSession.class); - - private static final int MAX_GLOBAL_SESSION_SIZE = StoreConfig.getMaxGlobalSessionSize(); - - private static ThreadLocal byteBufferThreadLocal = ThreadLocal.withInitial(() -> ByteBuffer.allocate( - MAX_GLOBAL_SESSION_SIZE)); - - /** - * If the global session's status is (Rollbacking or Committing) and currentTime - createTime >= RETRY_DEAD_THRESHOLD - * then the tx will be remand as need to retry rollback - */ - private static final int RETRY_DEAD_THRESHOLD = ConfigurationFactory.getInstance() - .getInt(ConfigurationKeys.RETRY_DEAD_THRESHOLD, DefaultValues.DEFAULT_RETRY_DEAD_THRESHOLD); - - private String xid; - - private long transactionId; - - private volatile GlobalStatus status; - - private String applicationId; - - private String transactionServiceGroup; - - private String transactionName; - - private int timeout; - - private long beginTime; - - private String applicationData; - - private final boolean lazyLoadBranch; - - private volatile boolean active = true; - - private List branchSessions; - - private GlobalSessionLock globalSessionLock = new GlobalSessionLock(); - - - /** - * Add boolean. - * - * @param branchSession the branch session - * @return the boolean - */ - public boolean add(BranchSession branchSession) { - if (null != branchSessions) { - return branchSessions.add(branchSession); - } else { - // db and redis no need to deal with - return true; - } - } - - /** - * Remove boolean. - * - * @param branchSession the branch session - * @return the boolean - */ - public boolean remove(BranchSession branchSession) { - return branchSessions.remove(branchSession); - } - - private Set lifecycleListeners = new HashSet<>(); - - /** - * Can be committed async boolean. - * - * @return the boolean - */ - public boolean canBeCommittedAsync() { - List branchSessions = getBranchSessions(); - for (BranchSession branchSession : branchSessions) { - if (!branchSession.canBeCommittedAsync()) { - return false; - } - } - return true; - } - - /** - * Has AT branch - * - * @return the boolean - */ - public boolean hasATBranch() { - List branchSessions = getBranchSessions(); - for (BranchSession branchSession : branchSessions) { - if (branchSession.getBranchType() == BranchType.AT) { - return true; - } - } - return false; - } - - /** - * Is saga type transaction - * - * @return is saga - */ - public boolean isSaga() { - List branchSessions = getBranchSessions(); - if (branchSessions.size() > 0) { - return BranchType.SAGA == branchSessions.get(0).getBranchType(); - } else { - return StringUtils.isNotBlank(transactionName) - && transactionName.startsWith(Constants.SAGA_TRANS_NAME_PREFIX); - } - } - - /** - * Is timeout boolean. - * - * @return the boolean - */ - public boolean isTimeout() { - return (System.currentTimeMillis() - beginTime) > timeout; - } - - /** - * prevent could not handle committing and rollbacking transaction - * @return if true retry commit or roll back - */ - public boolean isDeadSession() { - return (System.currentTimeMillis() - beginTime) > RETRY_DEAD_THRESHOLD; - } - - @Override - public void begin() throws TransactionException { - this.status = GlobalStatus.Begin; - this.beginTime = System.currentTimeMillis(); - this.active = true; - for (SessionLifecycleListener lifecycleListener : lifecycleListeners) { - lifecycleListener.onBegin(this); - } - } - - @Override - public void changeGlobalStatus(GlobalStatus status) throws TransactionException { - if (GlobalStatus.Rollbacking == status) { - LockerManagerFactory.getLockManager().updateLockStatus(xid, LockStatus.Rollbacking); - } - this.status = status; - for (SessionLifecycleListener lifecycleListener : lifecycleListeners) { - lifecycleListener.onStatusChange(this, status); - } - } - - @Override - public void changeBranchStatus(BranchSession branchSession, BranchStatus status) - throws TransactionException { - branchSession.setStatus(status); - for (SessionLifecycleListener lifecycleListener : lifecycleListeners) { - lifecycleListener.onBranchStatusChange(this, branchSession, status); - } - } - - @Override - public boolean isActive() { - return active; - } - - @Override - public void close() throws TransactionException { - if (active) { - for (SessionLifecycleListener lifecycleListener : lifecycleListeners) { - lifecycleListener.onClose(this); - } - } - } - - @Override - public void end() throws TransactionException { - if (GlobalStatus.isTwoPhaseSuccess(status)) { - // Clean locks first - clean(); - for (SessionLifecycleListener lifecycleListener : lifecycleListeners) { - lifecycleListener.onSuccessEnd(this); - } - } else { - for (SessionLifecycleListener lifecycleListener : lifecycleListeners) { - lifecycleListener.onFailEnd(this); - } - } - } - - public void clean() throws TransactionException { - if (!LockerManagerFactory.getLockManager().releaseGlobalSessionLock(this)) { - throw new TransactionException("UnLock globalSession error, xid = " + this.xid); - } - } - - /** - * Close and clean. - * - * @throws TransactionException the transaction exception - */ - public void closeAndClean() throws TransactionException { - close(); - if (this.hasATBranch()) { - clean(); - } - } - - /** - * Add session lifecycle listener. - * - * @param sessionLifecycleListener the session lifecycle listener - */ - public void addSessionLifecycleListener(SessionLifecycleListener sessionLifecycleListener) { - lifecycleListeners.add(sessionLifecycleListener); - } - - /** - * Remove session lifecycle listener. - * - * @param sessionLifecycleListener the session lifecycle listener - */ - public void removeSessionLifecycleListener(SessionLifecycleListener sessionLifecycleListener) { - lifecycleListeners.remove(sessionLifecycleListener); - } - - @Override - public void addBranch(BranchSession branchSession) throws TransactionException { - for (SessionLifecycleListener lifecycleListener : lifecycleListeners) { - lifecycleListener.onAddBranch(this, branchSession); - } - branchSession.setStatus(BranchStatus.Registered); - add(branchSession); - } - - public void loadBranchs() { - if (branchSessions == null && isLazyLoadBranch()) { - synchronized (this) { - if (branchSessions == null && isLazyLoadBranch()) { - branchSessions = new ArrayList<>(); - Optional.ofNullable(SessionHolder.getRootSessionManager().findGlobalSession(xid, true)) - .ifPresent(globalSession -> branchSessions.addAll(globalSession.getBranchSessions())); - } - } - } - } - - @Override - public void unlockBranch(BranchSession branchSession) throws TransactionException { - // do not unlock if global status in (Committing, CommitRetrying, AsyncCommitting), - // because it's already unlocked in 'DefaultCore.commit()' - if (status != Committing && status != CommitRetrying && status != AsyncCommitting) { - if (!branchSession.unlock()) { - throw new TransactionException("Unlock branch lock failed, xid = " + this.xid + ", branchId = " + branchSession.getBranchId()); - } - } - } - - @Override - public void removeBranch(BranchSession branchSession) throws TransactionException { - for (SessionLifecycleListener lifecycleListener : lifecycleListeners) { - lifecycleListener.onRemoveBranch(this, branchSession); - } - remove(branchSession); - } - - @Override - public void removeAndUnlockBranch(BranchSession branchSession) throws TransactionException { - unlockBranch(branchSession); - removeBranch(branchSession); - } - - /** - * Gets branch. - * - * @param branchId the branch id - * @return the branch - */ - public BranchSession getBranch(long branchId) { - synchronized (this) { - List branchSessions = getBranchSessions(); - for (BranchSession branchSession : branchSessions) { - if (branchSession.getBranchId() == branchId) { - return branchSession; - } - } - - return null; - } - } - - /** - * Gets sorted branches. - * - * @return the sorted branches - */ - public List getSortedBranches() { - return new ArrayList<>(getBranchSessions()); - } - - /** - * Gets reverse sorted branches. - * - * @return the reverse sorted branches - */ - public List getReverseSortedBranches() { - List reversed = new ArrayList<>(getBranchSessions()); - Collections.reverse(reversed); - return reversed; - } - - /** - * Instantiates a new Global session. - */ - public GlobalSession() { - this.lazyLoadBranch = false; - } - - /** - * Instantiates a new Global session. - * - * @param applicationId the application id - * @param transactionServiceGroup the transaction service group - * @param transactionName the transaction name - * @param timeout the timeout - * @param lazyLoadBranch the lazy load branch - */ - public GlobalSession(String applicationId, String transactionServiceGroup, String transactionName, int timeout, boolean lazyLoadBranch) { - this.transactionId = UUIDGenerator.generateUUID(); - this.status = GlobalStatus.Begin; - this.lazyLoadBranch = lazyLoadBranch; - if (!lazyLoadBranch) { - this.branchSessions = new ArrayList<>(); - } - this.applicationId = applicationId; - this.transactionServiceGroup = transactionServiceGroup; - this.transactionName = transactionName; - this.timeout = timeout; - this.xid = XID.generateXID(transactionId); - } - - /** - * Instantiates a new Global session. - * - * @param applicationId the application id - * @param transactionServiceGroup the transaction service group - * @param transactionName the transaction name - * @param timeout the timeout - */ - public GlobalSession(String applicationId, String transactionServiceGroup, String transactionName, int timeout) { - this(applicationId, transactionServiceGroup, transactionName, timeout, false); - } - - /** - * Gets transaction id. - * - * @return the transaction id - */ - public long getTransactionId() { - return transactionId; - } - - /** - * Sets transaction id. - * - * @param transactionId the transaction id - */ - public void setTransactionId(long transactionId) { - this.transactionId = transactionId; - } - - /** - * Gets status. - * - * @return the status - */ - public GlobalStatus getStatus() { - return status; - } - - /** - * Sets status. - * - * @param status the status - */ - public void setStatus(GlobalStatus status) { - this.status = status; - } - - /** - * Gets xid. - * - * @return the xid - */ - public String getXid() { - return xid; - } - - /** - * Sets xid. - * - * @param xid the xid - */ - public void setXid(String xid) { - this.xid = xid; - } - - /** - * Gets application id. - * - * @return the application id - */ - public String getApplicationId() { - return applicationId; - } - - /** - * Gets transaction service group. - * - * @return the transaction service group - */ - public String getTransactionServiceGroup() { - return transactionServiceGroup; - } - - /** - * Gets transaction name. - * - * @return the transaction name - */ - public String getTransactionName() { - return transactionName; - } - - /** - * Gets timeout. - * - * @return the timeout - */ - public int getTimeout() { - return timeout; - } - - /** - * Gets begin time. - * - * @return the begin time - */ - public long getBeginTime() { - return beginTime; - } - - /** - * Sets begin time. - * - * @param beginTime the begin time - */ - public void setBeginTime(long beginTime) { - this.beginTime = beginTime; - } - - /** - * Gets application data. - * - * @return the application data - */ - public String getApplicationData() { - return applicationData; - } - - /** - * Sets application data. - * - * @param applicationData the application data - */ - public void setApplicationData(String applicationData) { - this.applicationData = applicationData; - } - - public boolean isLazyLoadBranch() { - return lazyLoadBranch; - } - - /** - * Create global session global session. - * - * @param applicationId the application id - * @param txServiceGroup the tx service group - * @param txName the tx name - * @param timeout the timeout - * @return the global session - */ - public static GlobalSession createGlobalSession(String applicationId, String txServiceGroup, String txName, - int timeout) { - GlobalSession session = new GlobalSession(applicationId, txServiceGroup, txName, timeout, false); - return session; - } - - /** - * Sets active. - * - * @param active the active - */ - public void setActive(boolean active) { - this.active = active; - } - - @Override - public byte[] encode() { - byte[] byApplicationIdBytes = applicationId != null ? applicationId.getBytes() : null; - - byte[] byServiceGroupBytes = transactionServiceGroup != null ? transactionServiceGroup.getBytes() : null; - - byte[] byTxNameBytes = transactionName != null ? transactionName.getBytes() : null; - - byte[] xidBytes = xid != null ? xid.getBytes() : null; - - byte[] applicationDataBytes = applicationData != null ? applicationData.getBytes() : null; - - int size = calGlobalSessionSize(byApplicationIdBytes, byServiceGroupBytes, byTxNameBytes, xidBytes, - applicationDataBytes); - - if (size > MAX_GLOBAL_SESSION_SIZE) { - throw new RuntimeException("global session size exceeded, size : " + size + " maxBranchSessionSize : " + - MAX_GLOBAL_SESSION_SIZE); - } - ByteBuffer byteBuffer = byteBufferThreadLocal.get(); - //recycle - byteBuffer.clear(); - - byteBuffer.putLong(transactionId); - byteBuffer.putInt(timeout); - if (byApplicationIdBytes != null) { - byteBuffer.putShort((short)byApplicationIdBytes.length); - byteBuffer.put(byApplicationIdBytes); - } else { - byteBuffer.putShort((short)0); - } - if (byServiceGroupBytes != null) { - byteBuffer.putShort((short)byServiceGroupBytes.length); - byteBuffer.put(byServiceGroupBytes); - } else { - byteBuffer.putShort((short)0); - } - if (byTxNameBytes != null) { - byteBuffer.putShort((short)byTxNameBytes.length); - byteBuffer.put(byTxNameBytes); - } else { - byteBuffer.putShort((short)0); - } - if (xidBytes != null) { - byteBuffer.putInt(xidBytes.length); - byteBuffer.put(xidBytes); - } else { - byteBuffer.putInt(0); - } - if (applicationDataBytes != null) { - byteBuffer.putInt(applicationDataBytes.length); - byteBuffer.put(applicationDataBytes); - } else { - byteBuffer.putInt(0); - } - - byteBuffer.putLong(beginTime); - byteBuffer.put((byte)status.getCode()); - byteBuffer.flip(); - byte[] result = new byte[byteBuffer.limit()]; - byteBuffer.get(result); - return result; - } - - private int calGlobalSessionSize(byte[] byApplicationIdBytes, byte[] byServiceGroupBytes, byte[] byTxNameBytes, - byte[] xidBytes, byte[] applicationDataBytes) { - final int size = 8 // transactionId - + 4 // timeout - + 2 // byApplicationIdBytes.length - + 2 // byServiceGroupBytes.length - + 2 // byTxNameBytes.length - + 4 // xidBytes.length - + 4 // applicationDataBytes.length - + 8 // beginTime - + 1 // statusCode - + (byApplicationIdBytes == null ? 0 : byApplicationIdBytes.length) - + (byServiceGroupBytes == null ? 0 : byServiceGroupBytes.length) - + (byTxNameBytes == null ? 0 : byTxNameBytes.length) - + (xidBytes == null ? 0 : xidBytes.length) - + (applicationDataBytes == null ? 0 : applicationDataBytes.length); - return size; - } - - @Override - public void decode(byte[] a) { - this.branchSessions = new ArrayList<>(); - ByteBuffer byteBuffer = ByteBuffer.wrap(a); - this.transactionId = byteBuffer.getLong(); - this.timeout = byteBuffer.getInt(); - short applicationIdLen = byteBuffer.getShort(); - if (applicationIdLen > 0) { - byte[] byApplicationId = new byte[applicationIdLen]; - byteBuffer.get(byApplicationId); - this.applicationId = new String(byApplicationId); - } - short serviceGroupLen = byteBuffer.getShort(); - if (serviceGroupLen > 0) { - byte[] byServiceGroup = new byte[serviceGroupLen]; - byteBuffer.get(byServiceGroup); - this.transactionServiceGroup = new String(byServiceGroup); - } - short txNameLen = byteBuffer.getShort(); - if (txNameLen > 0) { - byte[] byTxName = new byte[txNameLen]; - byteBuffer.get(byTxName); - this.transactionName = new String(byTxName); - } - int xidLen = byteBuffer.getInt(); - if (xidLen > 0) { - byte[] xidBytes = new byte[xidLen]; - byteBuffer.get(xidBytes); - this.xid = new String(xidBytes); - } - int applicationDataLen = byteBuffer.getInt(); - if (applicationDataLen > 0) { - byte[] applicationDataLenBytes = new byte[applicationDataLen]; - byteBuffer.get(applicationDataLenBytes); - this.applicationData = new String(applicationDataLenBytes); - } - - this.beginTime = byteBuffer.getLong(); - this.status = GlobalStatus.get(byteBuffer.get()); - } - - /** - * Has branch boolean. - * - * @return the boolean - */ - public boolean hasBranch() { - return getBranchSessions().size() > 0; - } - - public void lock() throws TransactionException { - globalSessionLock.lock(); - } - - public void unlock() { - globalSessionLock.unlock(); - } - - private static class GlobalSessionLock { - - private Lock globalSessionLock = new ReentrantLock(); - - private static final int GLOBAL_SESSION_LOCK_TIME_OUT_MILLS = 2 * 1000; - - public void lock() throws TransactionException { - try { - if (globalSessionLock.tryLock(GLOBAL_SESSION_LOCK_TIME_OUT_MILLS, TimeUnit.MILLISECONDS)) { - return; - } - } catch (InterruptedException e) { - LOGGER.error("Interrupted error", e); - } - throw new GlobalTransactionException(TransactionExceptionCode.FailedLockGlobalTranscation, "Lock global session failed"); - } - - public void unlock() { - globalSessionLock.unlock(); - } - } - - @FunctionalInterface - public interface LockRunnable { - - void run() throws TransactionException; - } - - @FunctionalInterface - public interface LockCallable { - - V call() throws TransactionException; - } - - public List getBranchSessions() { - loadBranchs(); - return branchSessions; - } - - public void asyncCommit() throws TransactionException { - this.addSessionLifecycleListener(SessionHolder.getAsyncCommittingSessionManager()); - this.setStatus(GlobalStatus.AsyncCommitting); - SessionHolder.getAsyncCommittingSessionManager().addGlobalSession(this); - } - - public void queueToRetryCommit() throws TransactionException { - this.addSessionLifecycleListener(SessionHolder.getRetryCommittingSessionManager()); - this.setStatus(GlobalStatus.CommitRetrying); - SessionHolder.getRetryCommittingSessionManager().addGlobalSession(this); - } - - public void queueToRetryRollback() throws TransactionException { - this.addSessionLifecycleListener(SessionHolder.getRetryRollbackingSessionManager()); - GlobalStatus currentStatus = this.getStatus(); - if (SessionStatusValidator.isTimeoutGlobalStatus(currentStatus)) { - this.setStatus(GlobalStatus.TimeoutRollbackRetrying); - } else { - this.setStatus(GlobalStatus.RollbackRetrying); - } - SessionHolder.getRetryRollbackingSessionManager().addGlobalSession(this); - } - - @Override - public String toString() { - return "GlobalSession{" + "xid='" + xid + '\'' + ", transactionId=" + transactionId + ", status=" + status - + ", applicationId='" + applicationId + '\'' + ", transactionServiceGroup='" + transactionServiceGroup - + '\'' + ", transactionName='" + transactionName + '\'' + ", timeout=" + timeout + ", beginTime=" - + beginTime + ", applicationData='" + applicationData + '\'' + ", lazyLoadBranch=" + lazyLoadBranch - + ", active=" + active + ", branchSessions=" + branchSessions + ", globalSessionLock=" + globalSessionLock - + ", lifecycleListeners=" + lifecycleListeners + '}'; - } -} diff --git a/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/session/GlobalSessionHandler.java b/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/session/GlobalSessionHandler.java deleted file mode 100644 index 515b155b..00000000 --- a/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/session/GlobalSessionHandler.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright 1999-2019 Seata.io Group. - * - * Licensed 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 io.seata.server.session; - -import io.seata.core.exception.TransactionException; - -/** - * The Functional Interface Global session handler - * - * @author wang.liang - * @since 1.5.0 - */ -@FunctionalInterface -public interface GlobalSessionHandler { - - /** - * Handle global session. - * - * @param globalSession the global session - * @throws TransactionException the transaction exception - */ - void handle(GlobalSession globalSession) throws TransactionException; -} \ No newline at end of file diff --git a/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/session/Lockable.java b/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/session/Lockable.java deleted file mode 100644 index d023e632..00000000 --- a/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/session/Lockable.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright 1999-2019 Seata.io Group. - * - * Licensed 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 io.seata.server.session; - -import io.seata.core.exception.TransactionException; - -/** - * The interface Lockable. - * - * @author sharajava - */ -public interface Lockable { - - /** - * Lock boolean. - * - * @return the boolean - * @throws TransactionException the transaction exception - */ - boolean lock() throws TransactionException; - - /** - * Unlock boolean. - * - * @return the boolean - * @throws TransactionException the transaction exception - */ - boolean unlock() throws TransactionException; -} diff --git a/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/session/Reloadable.java b/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/session/Reloadable.java deleted file mode 100644 index 5701c69d..00000000 --- a/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/session/Reloadable.java +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright 1999-2019 Seata.io Group. - * - * Licensed 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 io.seata.server.session; - -/** - * Service contains states which can be reloaded. - * - * @author sharajava - */ -public interface Reloadable { - - /** - * Reload states. - */ - void reload(); -} diff --git a/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/session/SessionCondition.java b/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/session/SessionCondition.java deleted file mode 100644 index 6542a72c..00000000 --- a/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/session/SessionCondition.java +++ /dev/null @@ -1,145 +0,0 @@ -/* - * Copyright 1999-2019 Seata.io Group. - * - * Licensed 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 io.seata.server.session; - -import io.seata.core.model.GlobalStatus; - -/** - * The type Session condition. - * - * @author slievrly - */ -public class SessionCondition { - private Long transactionId; - private String xid; - private GlobalStatus status; - private GlobalStatus[] statuses; - private Long overTimeAliveMills; - private boolean lazyLoadBranch; - - /** - * Instantiates a new Session condition. - */ - public SessionCondition() { - } - - /** - * Instantiates a new Session condition. - * - * @param xid the xid - */ - public SessionCondition(String xid) { - this.xid = xid; - } - - /** - * Instantiates a new Session condition. - * - * @param status the status - */ - public SessionCondition(GlobalStatus status) { - this.status = status; - this.statuses = new GlobalStatus[] {status}; - } - - /** - * Instantiates a new Session condition. - * - * @param statuses the statuses - */ - public SessionCondition(GlobalStatus... statuses) { - this.statuses = statuses; - } - - /** - * Instantiates a new Session condition. - * - * @param overTimeAliveMills the over time alive mills - */ - public SessionCondition(long overTimeAliveMills) { - this.overTimeAliveMills = overTimeAliveMills; - } - - /** - * Gets status. - * - * @return the status - */ - public GlobalStatus getStatus() { - return status; - } - - /** - * Sets status. - * - * @param status the status - */ - public void setStatus(GlobalStatus status) { - this.status = status; - this.statuses = new GlobalStatus[] {status}; - } - - /** - * Gets over time alive mills. - * - * @return the over time alive mills - */ - public Long getOverTimeAliveMills() { - return overTimeAliveMills; - } - - /** - * Sets over time alive mills. - * - * @param overTimeAliveMills the over time alive mills - */ - public void setOverTimeAliveMills(Long overTimeAliveMills) { - this.overTimeAliveMills = overTimeAliveMills; - } - - public Long getTransactionId() { - return transactionId; - } - - public void setTransactionId(Long transactionId) { - this.transactionId = transactionId; - } - - public String getXid() { - return xid; - } - - public void setXid(String xid) { - this.xid = xid; - } - - public GlobalStatus[] getStatuses() { - return statuses; - } - - public void setStatuses(GlobalStatus... statuses) { - this.statuses = statuses; - } - - public boolean isLazyLoadBranch() { - return lazyLoadBranch; - } - - public void setLazyLoadBranch(boolean lazyLoadBranch) { - this.lazyLoadBranch = lazyLoadBranch; - } - -} diff --git a/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/session/SessionHelper.java b/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/session/SessionHelper.java deleted file mode 100644 index 12e5f25e..00000000 --- a/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/session/SessionHelper.java +++ /dev/null @@ -1,346 +0,0 @@ -/* - * Copyright 1999-2019 Seata.io Group. - * - * Licensed 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 io.seata.server.session; - -import io.seata.common.util.CollectionUtils; -import io.seata.config.Configuration; -import io.seata.config.ConfigurationFactory; -import io.seata.core.constants.ConfigurationKeys; -import io.seata.core.context.RootContext; -import io.seata.core.exception.TransactionException; -import io.seata.core.model.BranchType; -import io.seata.core.model.GlobalStatus; -import io.seata.metrics.IdConstants; -import io.seata.server.UUIDGenerator; -import io.seata.server.coordinator.DefaultCoordinator; -import io.seata.server.metrics.MetricsPublisher; -import io.seata.server.store.StoreConfig; -import io.seata.server.store.StoreConfig.SessionMode; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.slf4j.MDC; - -import java.util.Collection; -import java.util.List; -import java.util.Objects; - -import static io.seata.common.DefaultValues.DEFAULT_ENABLE_BRANCH_ASYNC_REMOVE; - -/** - * The type Session helper. - * - * @author sharajava - */ -public class SessionHelper { - private static final Logger LOGGER = LoggerFactory.getLogger(SessionHelper.class); - - /** - * The constant CONFIG. - */ - private static final Configuration CONFIG = ConfigurationFactory.getInstance(); - - private static final Boolean ENABLE_BRANCH_ASYNC_REMOVE = CONFIG.getBoolean( - ConfigurationKeys.ENABLE_BRANCH_ASYNC_REMOVE, DEFAULT_ENABLE_BRANCH_ASYNC_REMOVE); - - /** - * The instance of DefaultCoordinator - */ - private static final DefaultCoordinator COORDINATOR = DefaultCoordinator.getInstance(); - - private static final boolean DELAY_HANDLE_SESSION = StoreConfig.getSessionMode() != SessionMode.FILE; - - private SessionHelper() { - } - - public static BranchSession newBranchByGlobal(GlobalSession globalSession, BranchType branchType, String resourceId, String lockKeys, String clientId) { - return newBranchByGlobal(globalSession, branchType, resourceId, null, lockKeys, clientId); - } - - /** - * New branch by global branch session. - * - * @param globalSession the global session - * @param branchType the branch type - * @param resourceId the resource id - * @param lockKeys the lock keys - * @param clientId the client id - * @return the branch session - */ - public static BranchSession newBranchByGlobal(GlobalSession globalSession, BranchType branchType, String resourceId, - String applicationData, String lockKeys, String clientId) { - BranchSession branchSession = new BranchSession(); - - branchSession.setXid(globalSession.getXid()); - branchSession.setTransactionId(globalSession.getTransactionId()); - branchSession.setBranchId(UUIDGenerator.generateUUID()); - branchSession.setBranchType(branchType); - branchSession.setResourceId(resourceId); - branchSession.setLockKey(lockKeys); - branchSession.setClientId(clientId); - branchSession.setApplicationData(applicationData); - - return branchSession; - } - - /** - * New branch - * - * @param branchType the branch type - * @param xid Transaction id. - * @param branchId Branch id. - * @param resourceId Resource id. - * @param applicationData Application data bind with this branch. - * @return the branch session - */ - public static BranchSession newBranch(BranchType branchType, String xid, long branchId, String resourceId, String applicationData) { - BranchSession branchSession = new BranchSession(); - branchSession.setXid(xid); - branchSession.setBranchId(branchId); - branchSession.setBranchType(branchType); - branchSession.setResourceId(resourceId); - branchSession.setApplicationData(applicationData); - return branchSession; - } - - /** - * End committed. - * - * @param globalSession the global session - * @param retryGlobal the retry global - * @throws TransactionException the transaction exception - */ - public static void endCommitted(GlobalSession globalSession, boolean retryGlobal) throws TransactionException { - if (retryGlobal || !DELAY_HANDLE_SESSION) { - long beginTime = System.currentTimeMillis(); - boolean retryBranch = globalSession.getStatus() == GlobalStatus.CommitRetrying; - globalSession.changeGlobalStatus(GlobalStatus.Committed); - globalSession.end(); - if (!DELAY_HANDLE_SESSION) { - MetricsPublisher.postSessionDoneEvent(globalSession, false, false); - } - MetricsPublisher.postSessionDoneEvent(globalSession, IdConstants.STATUS_VALUE_AFTER_COMMITTED_KEY, true, - beginTime, retryBranch); - } else { - if (globalSession.isSaga()) { - globalSession.setStatus(GlobalStatus.Committed); - globalSession.end(); - } - MetricsPublisher.postSessionDoneEvent(globalSession, false, false); - } - } - - /** - * End commit failed. - * - * @param globalSession the global session - * @param retryGlobal the retry global - * @throws TransactionException the transaction exception - */ - public static void endCommitFailed(GlobalSession globalSession, boolean retryGlobal) throws TransactionException { - endCommitFailed(globalSession, retryGlobal, false); - } - - /** - * End commit failed. - * - * @param globalSession the global session - * @param retryGlobal the retry global - * @param isRetryTimeout is retry timeout - * @throws TransactionException the transaction exception - */ - public static void endCommitFailed(GlobalSession globalSession, boolean retryGlobal, boolean isRetryTimeout) - throws TransactionException { - if (isRetryTimeout) { - globalSession.changeGlobalStatus(GlobalStatus.CommitRetryTimeout); - } else { - globalSession.changeGlobalStatus(GlobalStatus.CommitFailed); - } - LOGGER.error("The Global session {} has changed the status to {}, need to be handled it manually.", - globalSession.getXid(), globalSession.getStatus()); - - globalSession.end(); - MetricsPublisher.postSessionDoneEvent(globalSession, retryGlobal, false); - } - - /** - * End rollbacked. - * - * @param globalSession the global session - * @param retryGlobal the retry global - * @throws TransactionException the transaction exception - */ - public static void endRollbacked(GlobalSession globalSession, boolean retryGlobal) throws TransactionException { - if (retryGlobal || !DELAY_HANDLE_SESSION) { - long beginTime = System.currentTimeMillis(); - boolean timeoutDone = false; - GlobalStatus currentStatus = globalSession.getStatus(); - if (currentStatus == GlobalStatus.TimeoutRollbacking) { - MetricsPublisher.postSessionDoneEvent(globalSession, GlobalStatus.TimeoutRollbacked, false, false); - timeoutDone = true; - } - boolean retryBranch = - currentStatus == GlobalStatus.TimeoutRollbackRetrying || currentStatus == GlobalStatus.RollbackRetrying; - if (SessionStatusValidator.isTimeoutGlobalStatus(currentStatus)) { - globalSession.changeGlobalStatus(GlobalStatus.TimeoutRollbacked); - } else { - globalSession.changeGlobalStatus(GlobalStatus.Rollbacked); - } - globalSession.end(); - if (!DELAY_HANDLE_SESSION && !timeoutDone) { - MetricsPublisher.postSessionDoneEvent(globalSession, false, false); - } - MetricsPublisher.postSessionDoneEvent(globalSession, IdConstants.STATUS_VALUE_AFTER_ROLLBACKED_KEY, true, - beginTime, retryBranch); - } else { - if (globalSession.isSaga()) { - globalSession.setStatus(GlobalStatus.Rollbacked); - globalSession.end(); - } - MetricsPublisher.postSessionDoneEvent(globalSession, GlobalStatus.Rollbacked, false, false); - } - } - - /** - * End rollback failed. - * - * @param globalSession the global session - * @param retryGlobal the retry global - * @throws TransactionException the transaction exception - */ - public static void endRollbackFailed(GlobalSession globalSession, boolean retryGlobal) throws TransactionException { - endRollbackFailed(globalSession, retryGlobal, false); - } - - /** - * End rollback failed. - * - * @param globalSession the global session - * @param retryGlobal the retry global - * @param isRetryTimeout is retry timeout - * @throws TransactionException the transaction exception - */ - public static void endRollbackFailed(GlobalSession globalSession, boolean retryGlobal, boolean isRetryTimeout) throws TransactionException { - GlobalStatus currentStatus = globalSession.getStatus(); - if (isRetryTimeout) { - globalSession.changeGlobalStatus(GlobalStatus.RollbackRetryTimeout); - } else if (SessionStatusValidator.isTimeoutGlobalStatus(currentStatus)) { - globalSession.changeGlobalStatus(GlobalStatus.TimeoutRollbackFailed); - } else { - globalSession.changeGlobalStatus(GlobalStatus.RollbackFailed); - } - LOGGER.error("The Global session {} has changed the status to {}, need to be handled it manually.", globalSession.getXid(), globalSession.getStatus()); - globalSession.end(); - MetricsPublisher.postSessionDoneEvent(globalSession, retryGlobal, false); - } - - /** - * Foreach global sessions. - * - * @param sessions the global sessions - * @param handler the handler - * @since 1.5.0 - */ - public static void forEach(Collection sessions, GlobalSessionHandler handler) { - if (CollectionUtils.isEmpty(sessions)) { - return; - } - sessions.parallelStream().forEach(globalSession -> { - try { - MDC.put(RootContext.MDC_KEY_XID, globalSession.getXid()); - handler.handle(globalSession); - } catch (Throwable th) { - LOGGER.error("handle global session failed: {}", globalSession.getXid(), th); - } finally { - MDC.remove(RootContext.MDC_KEY_XID); - } - }); - } - - /** - * Foreach branch sessions. - * - * @param sessions the branch session - * @param handler the handler - * @since 1.5.0 - */ - public static Boolean forEach(Collection sessions, BranchSessionHandler handler) throws TransactionException { - Boolean result; - for (BranchSession branchSession : sessions) { - try { - MDC.put(RootContext.MDC_KEY_BRANCH_ID, String.valueOf(branchSession.getBranchId())); - result = handler.handle(branchSession); - if (result == null) { - continue; - } - return result; - } finally { - MDC.remove(RootContext.MDC_KEY_BRANCH_ID); - } - } - return null; - } - - - /** - * remove branchSession from globalSession - * @param globalSession the globalSession - * @param branchSession the branchSession - * @param isAsync if asynchronous remove - */ - public static void removeBranch(GlobalSession globalSession, BranchSession branchSession, boolean isAsync) - throws TransactionException { - globalSession.unlockBranch(branchSession); - if (isEnableBranchRemoveAsync() && isAsync) { - COORDINATOR.doBranchRemoveAsync(globalSession, branchSession); - } else { - globalSession.removeBranch(branchSession); - } - } - - /** - * remove branchSession from globalSession - * @param globalSession the globalSession - * @param isAsync if asynchronous remove - */ - public static void removeAllBranch(GlobalSession globalSession, boolean isAsync) - throws TransactionException { - List branchSessions = globalSession.getSortedBranches(); - if (branchSessions == null || branchSessions.isEmpty()) { - return; - } - boolean isAsyncRemove = isEnableBranchRemoveAsync() && isAsync; - for (BranchSession branchSession : branchSessions) { - if (isAsyncRemove) { - globalSession.unlockBranch(branchSession); - } else { - globalSession.removeAndUnlockBranch(branchSession); - } - } - if (isAsyncRemove) { - COORDINATOR.doBranchRemoveAllAsync(globalSession); - } - } - - /** - * if true, enable delete the branch asynchronously - * - * @return the boolean - */ - private static boolean isEnableBranchRemoveAsync() { - return Objects.equals(Boolean.TRUE, DELAY_HANDLE_SESSION) - && Objects.equals(Boolean.TRUE, ENABLE_BRANCH_ASYNC_REMOVE); - } -} diff --git a/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/session/SessionHolder.java b/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/session/SessionHolder.java deleted file mode 100644 index a05bda43..00000000 --- a/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/session/SessionHolder.java +++ /dev/null @@ -1,426 +0,0 @@ -/* - * Copyright 1999-2019 Seata.io Group. - * - * Licensed 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 io.seata.server.session; - -import io.seata.common.ConfigurationKeys; -import io.seata.common.XID; -import io.seata.common.exception.ShouldNeverHappenException; -import io.seata.common.exception.StoreException; -import io.seata.common.loader.EnhancedServiceLoader; -import io.seata.common.util.CollectionUtils; -import io.seata.common.util.StringUtils; -import io.seata.config.Configuration; -import io.seata.config.ConfigurationFactory; -import io.seata.core.exception.TransactionException; -import io.seata.core.model.GlobalStatus; -import io.seata.core.model.LockStatus; -import io.seata.core.store.DistributedLockDO; -import io.seata.core.store.DistributedLocker; -import io.seata.server.lock.distributed.DistributedLockerFactory; -import io.seata.server.store.StoreConfig; -import io.seata.server.store.StoreConfig.SessionMode; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.io.IOException; -import java.util.Collection; -import java.util.List; -import java.util.concurrent.CompletableFuture; - -import static io.seata.common.DefaultValues.DEFAULT_DISTRIBUTED_LOCK_EXPIRE_TIME; - -/** - * The type Session holder. - * - * @author sharajava - */ -public class SessionHolder { - - private static final Logger LOGGER = LoggerFactory.getLogger(SessionHolder.class); - - /** - * The constant CONFIG. - */ - protected static final Configuration CONFIG = ConfigurationFactory.getInstance(); - /** - * The constant ROOT_SESSION_MANAGER_NAME. - */ - public static final String ROOT_SESSION_MANAGER_NAME = "root.data"; - /** - * The constant ASYNC_COMMITTING_SESSION_MANAGER_NAME. - */ - public static final String ASYNC_COMMITTING_SESSION_MANAGER_NAME = "async.commit.data"; - /** - * The constant RETRY_COMMITTING_SESSION_MANAGER_NAME. - */ - public static final String RETRY_COMMITTING_SESSION_MANAGER_NAME = "retry.commit.data"; - /** - * The constant RETRY_ROLLBACKING_SESSION_MANAGER_NAME. - */ - public static final String RETRY_ROLLBACKING_SESSION_MANAGER_NAME = "retry.rollback.data"; - - /** - * The default session store dir - */ - public static final String DEFAULT_SESSION_STORE_FILE_DIR = "sessionStore"; - - /** - * The redis distributed lock expire time - */ - private static long DISTRIBUTED_LOCK_EXPIRE_TIME = CONFIG.getLong(ConfigurationKeys.DISTRIBUTED_LOCK_EXPIRE_TIME, DEFAULT_DISTRIBUTED_LOCK_EXPIRE_TIME); - - private static SessionManager ROOT_SESSION_MANAGER; - private static SessionManager ASYNC_COMMITTING_SESSION_MANAGER; - private static SessionManager RETRY_COMMITTING_SESSION_MANAGER; - private static SessionManager RETRY_ROLLBACKING_SESSION_MANAGER; - - private static DistributedLocker DISTRIBUTED_LOCKER; - - public static void init() { - init(null); - } - /** - * Init. - * - * @param sessionMode the store mode: file, db, redis - * @throws IOException the io exception - */ - public static void init(SessionMode sessionMode) { - if (null == sessionMode) { - sessionMode = StoreConfig.getSessionMode(); - } - LOGGER.info("use session store mode: {}", sessionMode.getName()); - if (SessionMode.DB.equals(sessionMode)) { - ROOT_SESSION_MANAGER = EnhancedServiceLoader.load(SessionManager.class, SessionMode.DB.getName()); - ASYNC_COMMITTING_SESSION_MANAGER = EnhancedServiceLoader.load(SessionManager.class, SessionMode.DB.getName(), - new Object[]{ASYNC_COMMITTING_SESSION_MANAGER_NAME}); - RETRY_COMMITTING_SESSION_MANAGER = EnhancedServiceLoader.load(SessionManager.class, SessionMode.DB.getName(), - new Object[]{RETRY_COMMITTING_SESSION_MANAGER_NAME}); - RETRY_ROLLBACKING_SESSION_MANAGER = EnhancedServiceLoader.load(SessionManager.class, SessionMode.DB.getName(), - new Object[]{RETRY_ROLLBACKING_SESSION_MANAGER_NAME}); - - DISTRIBUTED_LOCKER = DistributedLockerFactory.getDistributedLocker(SessionMode.DB.getName()); - } else if (SessionMode.FILE.equals(sessionMode)) { - String sessionStorePath = CONFIG.getConfig(ConfigurationKeys.STORE_FILE_DIR, - DEFAULT_SESSION_STORE_FILE_DIR); - if (StringUtils.isBlank(sessionStorePath)) { - throw new StoreException("the {store.file.dir} is empty."); - } - ROOT_SESSION_MANAGER = EnhancedServiceLoader.load(SessionManager.class, SessionMode.FILE.getName(), - new Object[]{ROOT_SESSION_MANAGER_NAME, sessionStorePath}); - ASYNC_COMMITTING_SESSION_MANAGER = ROOT_SESSION_MANAGER; - RETRY_COMMITTING_SESSION_MANAGER = ROOT_SESSION_MANAGER; - RETRY_ROLLBACKING_SESSION_MANAGER = ROOT_SESSION_MANAGER; - - DISTRIBUTED_LOCKER = DistributedLockerFactory.getDistributedLocker(SessionMode.FILE.getName()); - } else if (SessionMode.REDIS.equals(sessionMode)) { - ROOT_SESSION_MANAGER = EnhancedServiceLoader.load(SessionManager.class, SessionMode.REDIS.getName()); - ASYNC_COMMITTING_SESSION_MANAGER = EnhancedServiceLoader.load(SessionManager.class, - SessionMode.REDIS.getName(), new Object[]{ASYNC_COMMITTING_SESSION_MANAGER_NAME}); - RETRY_COMMITTING_SESSION_MANAGER = EnhancedServiceLoader.load(SessionManager.class, - SessionMode.REDIS.getName(), new Object[]{RETRY_COMMITTING_SESSION_MANAGER_NAME}); - RETRY_ROLLBACKING_SESSION_MANAGER = EnhancedServiceLoader.load(SessionManager.class, - SessionMode.REDIS.getName(), new Object[]{RETRY_ROLLBACKING_SESSION_MANAGER_NAME}); - - DISTRIBUTED_LOCKER = DistributedLockerFactory.getDistributedLocker(SessionMode.REDIS.getName()); - } else { - // unknown store - throw new IllegalArgumentException("unknown store mode:" + sessionMode.getName()); - } - reload(sessionMode); - } - - //region reload - - /** - * Reload. - * - * @param sessionMode the mode of store - */ - protected static void reload(SessionMode sessionMode) { - - if (ROOT_SESSION_MANAGER instanceof Reloadable) { - ((Reloadable) ROOT_SESSION_MANAGER).reload(); - } - - if (SessionMode.FILE.equals(sessionMode)) { - Collection allSessions = ROOT_SESSION_MANAGER.allSessions(); - if (CollectionUtils.isNotEmpty(allSessions)) { - for (GlobalSession globalSession : allSessions) { - GlobalStatus globalStatus = globalSession.getStatus(); - switch (globalStatus) { - case UnKnown: - case Committed: - case CommitFailed: - case Rollbacked: - case RollbackFailed: - case TimeoutRollbacked: - case TimeoutRollbackFailed: - case Finished: - removeInErrorState(globalSession); - break; - case AsyncCommitting: - queueToAsyncCommitting(globalSession); - break; - case Committing: - case CommitRetrying: - queueToRetryCommit(globalSession); - break; - default: { - lockBranchSessions(globalSession.getSortedBranches()); - switch (globalStatus) { - case Rollbacking: - case RollbackRetrying: - case TimeoutRollbacking: - case TimeoutRollbackRetrying: - globalSession.getBranchSessions().parallelStream() - .forEach(branchSession -> branchSession.setLockStatus(LockStatus.Rollbacking)); - queueToRetryRollback(globalSession); - break; - case Begin: - globalSession.setActive(true); - break; - default: - LOGGER.error("Could not handle the global session, xid: {}", globalSession.getXid()); - throw new ShouldNeverHappenException("NOT properly handled " + globalStatus); - } - break; - } - } - } - } - } else { - // Redis, db and so on - CompletableFuture.runAsync(() -> { - SessionCondition searchCondition = new SessionCondition(GlobalStatus.UnKnown, GlobalStatus.Committed, - GlobalStatus.Rollbacked, GlobalStatus.TimeoutRollbacked, GlobalStatus.Finished); - searchCondition.setLazyLoadBranch(true); - - long now = System.currentTimeMillis(); - List errorStatusGlobalSessions = ROOT_SESSION_MANAGER.findGlobalSessions(searchCondition); - while (!CollectionUtils.isEmpty(errorStatusGlobalSessions)) { - for (GlobalSession errorStatusGlobalSession : errorStatusGlobalSessions) { - if (errorStatusGlobalSession.getBeginTime() >= now) { - // Exit when the global transaction begin after the instance started - return; - } - - removeInErrorState(errorStatusGlobalSession); - } - - // Load the next part - errorStatusGlobalSessions = ROOT_SESSION_MANAGER.findGlobalSessions(searchCondition); - } - }); - } - } - - private static void removeInErrorState(GlobalSession globalSession) { - try { - LOGGER.warn("The global session should NOT be {}, remove it. xid = {}", globalSession.getStatus(), globalSession.getXid()); - ROOT_SESSION_MANAGER.removeGlobalSession(globalSession); - if (LOGGER.isInfoEnabled()) { - LOGGER.info("Remove global session succeed, xid = {}, status = {}", globalSession.getXid(), globalSession.getStatus()); - } - } catch (Exception e) { - LOGGER.error("Remove global session failed, xid = {}, status = {}", globalSession.getXid(), globalSession.getStatus(), e); - } - } - - private static void queueToAsyncCommitting(GlobalSession globalSession) { - try { - globalSession.addSessionLifecycleListener(getAsyncCommittingSessionManager()); - getAsyncCommittingSessionManager().addGlobalSession(globalSession); - } catch (TransactionException e) { - throw new ShouldNeverHappenException(e); - } - } - - private static void lockBranchSessions(List branchSessions) { - branchSessions.forEach(branchSession -> { - try { - branchSession.lock(); - } catch (TransactionException e) { - throw new ShouldNeverHappenException(e); - } - }); - } - - private static void queueToRetryCommit(GlobalSession globalSession) { - try { - globalSession.addSessionLifecycleListener(getRetryCommittingSessionManager()); - getRetryCommittingSessionManager().addGlobalSession(globalSession); - } catch (TransactionException e) { - throw new ShouldNeverHappenException(e); - } - } - - private static void queueToRetryRollback(GlobalSession globalSession) { - try { - globalSession.addSessionLifecycleListener(getRetryRollbackingSessionManager()); - getRetryRollbackingSessionManager().addGlobalSession(globalSession); - } catch (TransactionException e) { - throw new ShouldNeverHappenException(e); - } - } - - //endregion - - //region get session manager - - /** - * Gets root session manager. - * - * @return the root session manager - */ - public static SessionManager getRootSessionManager() { - if (ROOT_SESSION_MANAGER == null) { - throw new ShouldNeverHappenException("SessionManager is NOT init!"); - } - return ROOT_SESSION_MANAGER; - } - - /** - * Gets async committing session manager. - * - * @return the async committing session manager - */ - @Deprecated - public static SessionManager getAsyncCommittingSessionManager() { - if (ASYNC_COMMITTING_SESSION_MANAGER == null) { - throw new ShouldNeverHappenException("SessionManager is NOT init!"); - } - return ASYNC_COMMITTING_SESSION_MANAGER; - } - - /** - * Gets retry committing session manager. - * - * @return the retry committing session manager - */ - @Deprecated - public static SessionManager getRetryCommittingSessionManager() { - if (RETRY_COMMITTING_SESSION_MANAGER == null) { - throw new ShouldNeverHappenException("SessionManager is NOT init!"); - } - return RETRY_COMMITTING_SESSION_MANAGER; - } - - /** - * Gets retry rollbacking session manager. - * - * @return the retry rollbacking session manager - */ - @Deprecated - public static SessionManager getRetryRollbackingSessionManager() { - if (RETRY_ROLLBACKING_SESSION_MANAGER == null) { - throw new ShouldNeverHappenException("SessionManager is NOT init!"); - } - return RETRY_ROLLBACKING_SESSION_MANAGER; - } - - //endregion - - /** - * Find global session. - * - * @param xid the xid - * @return the global session - */ - public static GlobalSession findGlobalSession(String xid) { - return findGlobalSession(xid, true); - } - - /** - * Find global session. - * - * @param xid the xid - * @param withBranchSessions the withBranchSessions - * @return the global session - */ - public static GlobalSession findGlobalSession(String xid, boolean withBranchSessions) { - return getRootSessionManager().findGlobalSession(xid, withBranchSessions); - } - - /** - * lock and execute - * - * @param globalSession the global session - * @param lockCallable the lock Callable - * @return the value - */ - public static T lockAndExecute(GlobalSession globalSession, GlobalSession.LockCallable lockCallable) - throws TransactionException { - return getRootSessionManager().lockAndExecute(globalSession, lockCallable); - } - - /** - * acquire lock - * - * @param lockKey the lock key, should be distinct for each lock - * @return the boolean - */ - public static boolean acquireDistributedLock(String lockKey) { - return DISTRIBUTED_LOCKER.acquireLock(new DistributedLockDO(lockKey, XID.getIpAddressAndPort(), DISTRIBUTED_LOCK_EXPIRE_TIME)); - } - - /** - * release lock - * - * @return the boolean - */ - public static boolean releaseDistributedLock(String lockKey) { - return DISTRIBUTED_LOCKER.releaseLock(new DistributedLockDO(lockKey, XID.getIpAddressAndPort(), DISTRIBUTED_LOCK_EXPIRE_TIME)); - } - - /** - * Execute the function after get the distribute lock - * - * @param key the distribute lock key - * @param func the function to be call - * @return whether the func be call - */ - public static boolean distributedLockAndExecute(String key, NoArgsFunc func) { - boolean lock = false; - try { - if (lock = acquireDistributedLock(key)) { - func.call(); - } - } catch (Exception e) { - LOGGER.error("Exception running function with key = {}", key, e); - } finally { - if (lock) { - try { - SessionHolder.releaseDistributedLock(key); - } catch (Exception ex) { - LOGGER.warn("release distribute lock failure, message = {}", ex.getMessage(), ex); - } - } - } - return lock; - } - - public static void destroy() { - if (ROOT_SESSION_MANAGER != null) { - ROOT_SESSION_MANAGER.destroy(); - } - } - - @FunctionalInterface - public interface NoArgsFunc { - void call(); - } -} diff --git a/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/session/SessionLifecycle.java b/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/session/SessionLifecycle.java deleted file mode 100644 index eb9bfcdd..00000000 --- a/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/session/SessionLifecycle.java +++ /dev/null @@ -1,105 +0,0 @@ -/* - * Copyright 1999-2019 Seata.io Group. - * - * Licensed 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 io.seata.server.session; - -import io.seata.core.exception.TransactionException; -import io.seata.core.model.BranchStatus; -import io.seata.core.model.GlobalStatus; - -/** - * The interface Session lifecycle. - * - * @author sharajava - */ -public interface SessionLifecycle { - - /** - * Begin. - * - * @throws TransactionException the transaction exception - */ - void begin() throws TransactionException; - - /** - * Change status. - * - * @param status the status - * @throws TransactionException the transaction exception - */ - void changeGlobalStatus(GlobalStatus status) throws TransactionException; - - /** - * Change branch status. - * - * @param branchSession the branch session - * @param status the status - * @throws TransactionException the transaction exception - */ - void changeBranchStatus(BranchSession branchSession, BranchStatus status) throws TransactionException; - - /** - * Add branch. - * - * @param branchSession the branch session - * @throws TransactionException the transaction exception - */ - void addBranch(BranchSession branchSession) throws TransactionException; - - /** - * Release the lock of branch. - * - * @param branchSession the branch session - * @throws TransactionException the transaction exception - */ - void unlockBranch(BranchSession branchSession) throws TransactionException; - - /** - * Remove branch. - * - * @param branchSession the branch session - * @throws TransactionException the transaction exception - */ - void removeBranch(BranchSession branchSession) throws TransactionException; - - /** - * Remove branch and release the lock of branch. - * - * @param branchSession the branchSession - * @throws TransactionException the TransactionException - */ - void removeAndUnlockBranch(BranchSession branchSession) throws TransactionException; - - /** - * Is active boolean. - * - * @return the boolean - */ - boolean isActive(); - - /** - * Close. - * - * @throws TransactionException the transaction exception - */ - void close() throws TransactionException; - - /** - * end. - * - * @throws TransactionException the transaction exception - */ - void end() throws TransactionException; -} diff --git a/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/session/SessionLifecycleListener.java b/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/session/SessionLifecycleListener.java deleted file mode 100644 index 693d5b69..00000000 --- a/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/session/SessionLifecycleListener.java +++ /dev/null @@ -1,98 +0,0 @@ -/* - * Copyright 1999-2019 Seata.io Group. - * - * Licensed 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 io.seata.server.session; - -import io.seata.core.exception.TransactionException; -import io.seata.core.model.BranchStatus; -import io.seata.core.model.GlobalStatus; - -/** - * The interface Session lifecycle listener. - * - * @author sharajava - */ -public interface SessionLifecycleListener { - - /** - * On begin. - * - * @param globalSession the global session - * @throws TransactionException the transaction exception - */ - void onBegin(GlobalSession globalSession) throws TransactionException; - - /** - * On status change. - * - * @param globalSession the global session - * @param status the status - * @throws TransactionException the transaction exception - */ - void onStatusChange(GlobalSession globalSession, GlobalStatus status) throws TransactionException; - - /** - * On branch status change. - * - * @param globalSession the global session - * @param branchSession the branch session - * @param status the status - * @throws TransactionException the transaction exception - */ - void onBranchStatusChange(GlobalSession globalSession, BranchSession branchSession, BranchStatus status) - throws TransactionException; - - /** - * On add branch. - * - * @param globalSession the global session - * @param branchSession the branch session - * @throws TransactionException the transaction exception - */ - void onAddBranch(GlobalSession globalSession, BranchSession branchSession) throws TransactionException; - - /** - * On remove branch. - * - * @param globalSession the global session - * @param branchSession the branch session - * @throws TransactionException the transaction exception - */ - void onRemoveBranch(GlobalSession globalSession, BranchSession branchSession) throws TransactionException; - - /** - * On close. - * - * @param globalSession the global session - * @throws TransactionException the transaction exception - */ - void onClose(GlobalSession globalSession) throws TransactionException; - - /** - * On end. - * - * @param globalSession the global session - * @throws TransactionException the transaction exception - */ - void onSuccessEnd(GlobalSession globalSession) throws TransactionException; - - /** - * On fail end. - * - * @param globalSession the global session - * @throws TransactionException the transaction exception - */ - void onFailEnd(GlobalSession globalSession) throws TransactionException; -} diff --git a/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/session/SessionManager.java b/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/session/SessionManager.java deleted file mode 100644 index ac357eb9..00000000 --- a/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/session/SessionManager.java +++ /dev/null @@ -1,127 +0,0 @@ -/* - * Copyright 1999-2019 Seata.io Group. - * - * Licensed 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 io.seata.server.session; - -import io.seata.core.exception.TransactionException; -import io.seata.core.model.BranchStatus; -import io.seata.core.model.GlobalStatus; -import io.seata.core.rpc.Disposable; - -import java.util.Collection; -import java.util.List; - -/** - * The interface Session manager. - * - * @author sharajava - */ -public interface SessionManager extends SessionLifecycleListener, Disposable { - - /** - * Add global session. - * - * @param session the session - * @throws TransactionException the transaction exception - */ - void addGlobalSession(GlobalSession session) throws TransactionException; - - /** - * Find global session global session. - * - * @param xid the xid - * @return the global session - */ - GlobalSession findGlobalSession(String xid) ; - - /** - * Find global session global session. - * - * @param xid the xid - * @param withBranchSessions the withBranchSessions - * @return the global session - */ - GlobalSession findGlobalSession(String xid, boolean withBranchSessions); - - /** - * Update global session status. - * - * @param session the session - * @param status the status - * @throws TransactionException the transaction exception - */ - void updateGlobalSessionStatus(GlobalSession session, GlobalStatus status) throws TransactionException; - - /** - * Remove global session. - * - * @param session the session - * @throws TransactionException the transaction exception - */ - void removeGlobalSession(GlobalSession session) throws TransactionException; - - /** - * Add branch session. - * - * @param globalSession the global session - * @param session the session - * @throws TransactionException the transaction exception - */ - void addBranchSession(GlobalSession globalSession, BranchSession session) throws TransactionException; - - /** - * Update branch session status. - * - * @param session the session - * @param status the status - * @throws TransactionException the transaction exception - */ - void updateBranchSessionStatus(BranchSession session, BranchStatus status) throws TransactionException; - - /** - * Remove branch session. - * - * @param globalSession the global session - * @param session the session - * @throws TransactionException the transaction exception - */ - void removeBranchSession(GlobalSession globalSession, BranchSession session) throws TransactionException; - - /** - * All sessions collection. - * - * @return the collection - */ - Collection allSessions(); - - /** - * Find global sessions list. - * - * @param condition the condition - * @return the list - */ - List findGlobalSessions(SessionCondition condition); - - /** - * lock and execute - * - * @param globalSession the global session - * @param lockCallable the lock Callable - * @return the value - * @throws TransactionException the transaction exception - */ - T lockAndExecute(GlobalSession globalSession, GlobalSession.LockCallable lockCallable) - throws TransactionException; -} diff --git a/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/session/SessionStatusValidator.java b/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/session/SessionStatusValidator.java deleted file mode 100644 index 20323a7e..00000000 --- a/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/session/SessionStatusValidator.java +++ /dev/null @@ -1,87 +0,0 @@ -/* - * Copyright 1999-2019 Seata.io Group. - * - * Licensed 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 io.seata.server.session; - -import io.seata.core.model.GlobalStatus; - -/** - * The type change status validator. - * - * @author Bughue - */ -public class SessionStatusValidator { - - /** - * is timeout global status - * - * @param status the global session - */ - public static boolean isTimeoutGlobalStatus(GlobalStatus status) { - return status == GlobalStatus.TimeoutRollbacked - || status == GlobalStatus.TimeoutRollbackFailed - || status == GlobalStatus.TimeoutRollbacking - || status == GlobalStatus.TimeoutRollbackRetrying; - } - - /** - * is rollback global status - * - * @param status the global session - */ - public static boolean isRollbackGlobalStatus(GlobalStatus status) { - return status == GlobalStatus.Rollbacking - || status == GlobalStatus.RollbackRetrying - || status == GlobalStatus.Rollbacked - || status == GlobalStatus.RollbackFailed - || status == GlobalStatus.RollbackRetryTimeout; - } - - /** - * is commit global status - * - * @param status the global session - */ - public static boolean isCommitGlobalStatus(GlobalStatus status) { - return status == GlobalStatus.Committing - || status == GlobalStatus.AsyncCommitting - || status == GlobalStatus.CommitRetrying - || status == GlobalStatus.Committed - || status == GlobalStatus.CommitFailed - || status == GlobalStatus.CommitRetryTimeout; - } - - /** - * check the relation of before status and after status - * - * @param before the global session - * @param after the global session - */ - public static boolean validateUpdateStatus(GlobalStatus before, GlobalStatus after) { - if (isTimeoutGlobalStatus(before) && isCommitGlobalStatus(after)) { - return false; - } - if (isCommitGlobalStatus(before) && isTimeoutGlobalStatus(after)) { - return false; - } - if (isRollbackGlobalStatus(before) && isCommitGlobalStatus(after)) { - return false; - } - if (isCommitGlobalStatus(before) && isRollbackGlobalStatus(after)) { - return false; - } - return true; - } -} diff --git a/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/spring/listener/SeataPropertiesLoader.java b/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/spring/listener/SeataPropertiesLoader.java deleted file mode 100644 index 3a913c93..00000000 --- a/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/spring/listener/SeataPropertiesLoader.java +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright 1999-2019 Seata.io Group. - * - * Licensed 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 io.seata.server.spring.listener; - -import io.seata.common.util.CollectionUtils; -import io.seata.common.util.StringUtils; -import io.seata.config.ConfigurationFactory; -import io.seata.config.FileConfiguration; -import io.seata.config.file.FileConfig; -import io.seata.server.store.StoreConfig; -import org.springframework.context.ApplicationContextInitializer; -import org.springframework.context.ConfigurableApplicationContext; -import org.springframework.core.Ordered; -import org.springframework.core.annotation.Order; -import org.springframework.core.env.ConfigurableEnvironment; -import org.springframework.core.env.PropertiesPropertySource; - -import java.util.*; - -import static io.seata.common.ConfigurationKeys.*; - -@Order(Ordered.HIGHEST_PRECEDENCE) -public class SeataPropertiesLoader implements ApplicationContextInitializer { - - List prefixList = Arrays.asList(FILE_ROOT_PREFIX_CONFIG, FILE_ROOT_PREFIX_REGISTRY, SERVER_PREFIX, - STORE_PREFIX, METRICS_PREFIX, TRANSPORT_PREFIX); - - @Override - public void initialize(ConfigurableApplicationContext applicationContext) { - ConfigurableEnvironment environment = applicationContext.getEnvironment(); - FileConfiguration configuration = ConfigurationFactory.getOriginFileInstanceRegistry(); - FileConfig fileConfig = configuration.getFileConfig(); - Map configs = fileConfig.getAllConfig(); - if (CollectionUtils.isNotEmpty(configs)) { - Optional originFileInstance = ConfigurationFactory.getOriginFileInstance(); - originFileInstance - .ifPresent(fileConfiguration -> configs.putAll(fileConfiguration.getFileConfig().getAllConfig())); - Properties properties = new Properties(); - configs.forEach((k, v) -> { - if (v instanceof String) { - if (StringUtils.isEmpty((String)v)) { - return; - } - } - // Convert the configuration name to the configuration name under Spring Boot - if (prefixList.stream().anyMatch(k::startsWith)) { - properties.put(SEATA_FILE_PREFIX_ROOT_CONFIG + k, v); - } - }); - environment.getPropertySources().addLast(new PropertiesPropertySource("seataOldConfig", properties)); - } - // Load by priority - System.setProperty("sessionMode", StoreConfig.getSessionMode().getName()); - System.setProperty("lockMode", StoreConfig.getLockMode().getName()); - } - -} diff --git a/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/spring/listener/ServerApplicationListener.java b/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/spring/listener/ServerApplicationListener.java deleted file mode 100644 index 5d9e0b16..00000000 --- a/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/spring/listener/ServerApplicationListener.java +++ /dev/null @@ -1,124 +0,0 @@ -/* - * Copyright 1999-2019 Seata.io Group. - * - * Licensed 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 io.seata.server.spring.listener; - -import io.seata.common.holder.ObjectHolder; -import io.seata.common.util.StringUtils; -import io.seata.spring.boot.autoconfigure.SeataCoreEnvironmentPostProcessor; -import io.seata.spring.boot.autoconfigure.SeataServerEnvironmentPostProcessor; -import org.springframework.boot.context.event.ApplicationEnvironmentPreparedEvent; -import org.springframework.boot.context.logging.LoggingApplicationListener; -import org.springframework.context.ApplicationEvent; -import org.springframework.context.event.GenericApplicationListener; -import org.springframework.core.ResolvableType; -import org.springframework.core.env.ConfigurableEnvironment; -import org.springframework.core.env.PropertiesPropertySource; - -import java.util.Properties; - -import static io.seata.common.Constants.OBJECT_KEY_SPRING_CONFIGURABLE_ENVIRONMENT; -import static io.seata.common.DefaultValues.SERVICE_OFFSET_SPRING_BOOT; -import static io.seata.core.constants.ConfigurationKeys.*; - -/** - * @author slievrly - * @author funkye - */ -public class ServerApplicationListener implements GenericApplicationListener { - - @Override - public boolean supportsEventType(ResolvableType eventType) { - return eventType.getRawClass() != null - && ApplicationEnvironmentPreparedEvent.class.isAssignableFrom(eventType.getRawClass()); - } - - @Override - public void onApplicationEvent(ApplicationEvent event) { - if (!(event instanceof ApplicationEnvironmentPreparedEvent)) { - return; - } - ApplicationEnvironmentPreparedEvent environmentPreparedEvent = (ApplicationEnvironmentPreparedEvent)event; - ConfigurableEnvironment environment = environmentPreparedEvent.getEnvironment(); - ObjectHolder.INSTANCE.setObject(OBJECT_KEY_SPRING_CONFIGURABLE_ENVIRONMENT, environment); - SeataCoreEnvironmentPostProcessor.init(); - SeataServerEnvironmentPostProcessor.init(); - - String[] args = environmentPreparedEvent.getArgs(); - - // port: -p > -D > env > yml > default - - //-p 8091 - if (args != null && args.length >= 2) { - for (int i = 0; i < args.length; ++i) { - if ("-p".equalsIgnoreCase(args[i]) && i < args.length - 1) { - setTargetPort(environment, args[i + 1], true); - return; - } - } - } - - // -Dserver.servicePort=8091 - String dPort = environment.getProperty(SERVER_SERVICE_PORT_CAMEL, String.class); - if (StringUtils.isNotBlank(dPort)) { - setTargetPort(environment, dPort, true); - return; - } - - //docker -e SEATA_PORT=8091 - String envPort = environment.getProperty(ENV_SEATA_PORT_KEY, String.class); - if (StringUtils.isNotBlank(envPort)) { - setTargetPort(environment, envPort, true); - return; - } - - //yml properties server.service-port=8091 - String configPort = environment.getProperty(SERVER_SERVICE_PORT_CONFIG, String.class); - if (StringUtils.isNotBlank(configPort)) { - setTargetPort(environment, configPort, false); - return; - } - - // server.port=7091 - String serverPort = environment.getProperty("server.port", String.class); - if (StringUtils.isBlank(serverPort)) { - serverPort = "8080"; - } - String servicePort = String.valueOf(Integer.parseInt(serverPort) + SERVICE_OFFSET_SPRING_BOOT); - setTargetPort(environment, servicePort, true); - } - - private void setTargetPort(ConfigurableEnvironment environment, String port, boolean needAddPropertySource) { - // get rpc port first, use to logback-spring.xml, @see the class named `SystemPropertyLoggerContextListener` - System.setProperty(SERVER_SERVICE_PORT_CAMEL, port); - - if (needAddPropertySource) { - // add property source to the first position - Properties pro = new Properties(); - pro.setProperty(SERVER_SERVICE_PORT_CONFIG, port); - environment.getPropertySources().addFirst(new PropertiesPropertySource("serverProperties", pro)); - } - } - - /** - * higher than LoggingApplicationListener - * - * @return the order - */ - @Override - public int getOrder() { - return LoggingApplicationListener.DEFAULT_ORDER - 1; - } -} diff --git a/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/storage/SessionConverter.java b/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/storage/SessionConverter.java deleted file mode 100644 index b6b2f957..00000000 --- a/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/storage/SessionConverter.java +++ /dev/null @@ -1,207 +0,0 @@ -/* - * Copyright 1999-2019 Seata.io Group. - * - * Licensed 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 io.seata.server.storage; - -import io.seata.common.util.CollectionUtils; -import io.seata.common.util.StringUtils; -import io.seata.core.model.BranchStatus; -import io.seata.core.model.BranchType; -import io.seata.core.model.GlobalStatus; -import io.seata.core.store.BranchTransactionDO; -import io.seata.core.store.GlobalTransactionDO; -import io.seata.server.console.vo.BranchSessionVO; -import io.seata.server.console.vo.GlobalSessionVO; -import io.seata.server.session.BranchSession; -import io.seata.server.session.GlobalSession; -import io.seata.server.store.SessionStorable; -import org.springframework.beans.BeanUtils; - -import java.util.*; - -/** - * The session converter - * - * @author wangzhongxiang - * @author doubleDimple - */ -public class SessionConverter { - - public static GlobalSession convertGlobalSession(GlobalTransactionDO globalTransactionDO, boolean lazyLoadBranch) { - if (globalTransactionDO == null) { - return null; - } - GlobalSession session = new GlobalSession(globalTransactionDO.getApplicationId(), - globalTransactionDO.getTransactionServiceGroup(), - globalTransactionDO.getTransactionName(), - globalTransactionDO.getTimeout(), lazyLoadBranch); - session.setXid(globalTransactionDO.getXid()); - session.setTransactionId(globalTransactionDO.getTransactionId()); - session.setStatus(GlobalStatus.get(globalTransactionDO.getStatus())); - session.setApplicationData(globalTransactionDO.getApplicationData()); - session.setBeginTime(globalTransactionDO.getBeginTime()); - return session; - } - - public static GlobalSession convertGlobalSession(GlobalTransactionDO globalTransactionDO) { - return convertGlobalSession(globalTransactionDO, false); - } - - public static BranchSession convertBranchSession(BranchTransactionDO branchTransactionDO) { - if (branchTransactionDO == null) { - return null; - } - BranchSession branchSession = new BranchSession(); - branchSession.setXid(branchTransactionDO.getXid()); - branchSession.setTransactionId(branchTransactionDO.getTransactionId()); - branchSession.setApplicationData(branchTransactionDO.getApplicationData()); - branchSession.setBranchId(branchTransactionDO.getBranchId()); - branchSession.setBranchType(BranchType.valueOf(branchTransactionDO.getBranchType())); - branchSession.setResourceId(branchTransactionDO.getResourceId()); - branchSession.setClientId(branchTransactionDO.getClientId()); - branchSession.setResourceGroupId(branchTransactionDO.getResourceGroupId()); - branchSession.setStatus(BranchStatus.get(branchTransactionDO.getStatus())); - return branchSession; - } - - public static GlobalTransactionDO convertGlobalTransactionDO(SessionStorable session) { - if (session == null || !(session instanceof GlobalSession)) { - throw new IllegalArgumentException( - "The parameter of SessionStorable is not available, SessionStorable:" + StringUtils.toString(session)); - } - GlobalSession globalSession = (GlobalSession)session; - - GlobalTransactionDO globalTransactionDO = new GlobalTransactionDO(); - globalTransactionDO.setXid(globalSession.getXid()); - globalTransactionDO.setStatus(globalSession.getStatus().getCode()); - globalTransactionDO.setApplicationId(globalSession.getApplicationId()); - globalTransactionDO.setBeginTime(globalSession.getBeginTime()); - globalTransactionDO.setTimeout(globalSession.getTimeout()); - globalTransactionDO.setTransactionId(globalSession.getTransactionId()); - globalTransactionDO.setTransactionName(globalSession.getTransactionName()); - globalTransactionDO.setTransactionServiceGroup(globalSession.getTransactionServiceGroup()); - globalTransactionDO.setApplicationData(globalSession.getApplicationData()); - return globalTransactionDO; - } - - public static BranchTransactionDO convertBranchTransactionDO(SessionStorable session) { - if (session == null || !(session instanceof BranchSession)) { - throw new IllegalArgumentException( - "The parameter of SessionStorable is not available, SessionStorable:" + StringUtils.toString(session)); - } - BranchSession branchSession = (BranchSession)session; - BranchTransactionDO branchTransactionDO = new BranchTransactionDO(); - branchTransactionDO.setXid(branchSession.getXid()); - branchTransactionDO.setBranchId(branchSession.getBranchId()); - branchTransactionDO.setBranchType(branchSession.getBranchType().name()); - branchTransactionDO.setClientId(branchSession.getClientId()); - branchTransactionDO.setResourceGroupId(branchSession.getResourceGroupId()); - branchTransactionDO.setTransactionId(branchSession.getTransactionId()); - branchTransactionDO.setApplicationData(branchSession.getApplicationData()); - branchTransactionDO.setResourceId(branchSession.getResourceId()); - branchTransactionDO.setStatus(branchSession.getStatus().getCode()); - return branchTransactionDO; - } - - public static void convertToGlobalSessionVo(List result, List globalSessions) { - if (CollectionUtils.isNotEmpty(globalSessions)) { - for (GlobalSession globalSession : globalSessions) { - GlobalSessionVO globalSessionVO = new GlobalSessionVO(); - BeanUtils.copyProperties(globalSession,globalSessionVO); - globalSessionVO.setStatus(globalSession.getStatus().getCode()); - globalSessionVO.setTimeout(Long.valueOf(globalSession.getTimeout())); - globalSessionVO.setBranchSessionVOs(converToBranchSession(globalSession.getBranchSessions())); - result.add(globalSessionVO); - } - } - } - - public static Set converToBranchSession(List branchSessions) { - Set branchSessionVOs = new HashSet<>(branchSessions.size()); - if (CollectionUtils.isNotEmpty(branchSessions)) { - for (BranchSession branchSession : branchSessions) { - BranchSessionVO branchSessionVONew = new BranchSessionVO(); - BeanUtils.copyProperties(branchSession,branchSessionVONew); - - branchSessionVONew.setBranchType(branchSession.getBranchType().name()); - branchSessionVONew.setStatus(branchSession.getStatus().getCode()); - branchSessionVOs.add(branchSessionVONew); - } - } - return branchSessionVOs; - } - - /** - * convert GlobalSession to GlobalSessionVO - * - * @param filteredSessions the GlobalSession list - * @return the GlobalSessionVO list - */ - public static List convertGlobalSession(List filteredSessions) { - - if (CollectionUtils.isEmpty(filteredSessions)) { - return Collections.emptyList(); - } - - final ArrayList result = new ArrayList<>(filteredSessions.size()); - - for (GlobalSession session : filteredSessions) { - result.add(new GlobalSessionVO( - session.getXid(), - session.getTransactionId(), - session.getStatus().getCode(), - session.getApplicationId(), - session.getTransactionServiceGroup(), - session.getTransactionName(), - (long) session.getTimeout(), - session.getBeginTime(), - session.getApplicationData(), - convertBranchSession(session.getBranchSessions()) - )); - } - return result; - } - - /** - * convert BranchSession to BranchSessionVO - * - * @param branchSessions the BranchSession list - * @return the BranchSessionVO list - */ - public static Set convertBranchSession(List branchSessions) { - - if (CollectionUtils.isEmpty(branchSessions)) { - return Collections.emptySet(); - } - - final Set result = new HashSet<>(branchSessions.size()); - - for (BranchSession session : branchSessions) { - result.add(new BranchSessionVO( - session.getXid(), - session.getTransactionId(), - session.getBranchId(), - session.getResourceGroupId(), - session.getResourceId(), - session.getBranchType().name(), - session.getStatus().getCode(), - session.getClientId(), - session.getApplicationData() - )); - } - return result; - } - -} diff --git a/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/storage/db/lock/DataBaseDistributedLocker.java b/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/storage/db/lock/DataBaseDistributedLocker.java deleted file mode 100644 index f55668f2..00000000 --- a/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/storage/db/lock/DataBaseDistributedLocker.java +++ /dev/null @@ -1,283 +0,0 @@ -/* - * Copyright 1999-2019 Seata.io Group. - * - * Licensed 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 io.seata.server.storage.db.lock; - -import io.seata.common.exception.ShouldNeverHappenException; -import io.seata.common.loader.EnhancedServiceLoader; -import io.seata.common.loader.LoadLevel; -import io.seata.common.loader.Scope; -import io.seata.common.util.IOUtil; -import io.seata.common.util.StringUtils; -import io.seata.config.*; -import io.seata.core.constants.ConfigurationKeys; -import io.seata.core.constants.ServerTableColumnsName; -import io.seata.core.store.DistributedLockDO; -import io.seata.core.store.DistributedLocker; -import io.seata.core.store.db.DataSourceProvider; -import io.seata.core.store.db.sql.distributed.lock.DistributedLockSqlFactory; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import javax.sql.DataSource; -import java.sql.Connection; -import java.sql.PreparedStatement; -import java.sql.ResultSet; -import java.sql.SQLException; -import java.util.HashSet; -import java.util.Objects; -import java.util.Set; - -import static io.seata.core.constants.ConfigurationKeys.DISTRIBUTED_LOCK_DB_TABLE; - -/** - * @author chd - */ -@LoadLevel(name = "db", scope = Scope.SINGLETON) -public class DataBaseDistributedLocker implements DistributedLocker { - private static final Logger LOGGER = LoggerFactory.getLogger(DataBaseDistributedLocker.class); - - private final String dbType; - - private final String datasourceType; - - private volatile String distributedLockTable; - - private DataSource distributedLockDataSource; - - private static final String LOCK_WAIT_TIMEOUT_MYSQL_MESSAGE = "try restarting transaction"; - - private static final int LOCK_WAIT_TIMEOUT_MYSQL_CODE = 1205; - - private static final Set IGNORE_MYSQL_CODE = new HashSet<>(); - - private static final Set IGNORE_MYSQL_MESSAGE = new HashSet<>(); - - static { - IGNORE_MYSQL_CODE.add(LOCK_WAIT_TIMEOUT_MYSQL_CODE); - IGNORE_MYSQL_MESSAGE.add(LOCK_WAIT_TIMEOUT_MYSQL_MESSAGE); - } - - /** - * whether the distribute lock demotion - * using for 1.5.0 only and will remove in 1.6.0 - */ - @Deprecated - private volatile boolean demotion; - - /** - * Instantiates a new Log store data base dao. - */ - public DataBaseDistributedLocker() { - Configuration configuration = ConfigurationFactory.getInstance(); - - distributedLockTable = configuration.getConfig(DISTRIBUTED_LOCK_DB_TABLE); - dbType = configuration.getConfig(ConfigurationKeys.STORE_DB_TYPE); - datasourceType = configuration.getConfig(ConfigurationKeys.STORE_DB_DATASOURCE_TYPE); - - if (StringUtils.isBlank(distributedLockTable)) { - demotion = true; - ConfigurationCache.addConfigListener(DISTRIBUTED_LOCK_DB_TABLE, new ConfigurationChangeListener() { - @Override - public void onChangeEvent(ConfigurationChangeEvent event) { - String newValue = event.getNewValue(); - if (StringUtils.isNotBlank(newValue)) { - distributedLockTable = newValue; - init(); - demotion = false; - ConfigurationCache.removeConfigListener(DISTRIBUTED_LOCK_DB_TABLE, this); - } - } - }); - - LOGGER.error("The distribute lock table is not config, please create the target table and config it"); - return; - } - - init(); - } - - - @Override - public boolean acquireLock(DistributedLockDO distributedLockDO) { - if (demotion) { - return true; - } - - Connection connection = null; - boolean originalAutoCommit = false; - try { - connection = distributedLockDataSource.getConnection(); - originalAutoCommit = connection.getAutoCommit(); - connection.setAutoCommit(false); - - DistributedLockDO lockFromDB = getDistributedLockDO(connection, distributedLockDO.getLockKey()); - if (null == lockFromDB) { - boolean ret = insertDistribute(connection, distributedLockDO); - connection.commit(); - return ret; - } - - if (lockFromDB.getExpireTime() >= System.currentTimeMillis()) { - LOGGER.debug("the distribute lock for key :{} is holding by :{}, acquire lock failure.", - distributedLockDO.getLockKey(), lockFromDB.getLockValue()); - connection.commit(); - return false; - } - - boolean ret = updateDistributedLock(connection, distributedLockDO); - connection.commit(); - - return ret; - } catch (SQLException ex) { - // ignore "Lock wait timeout exceeded; try restarting transaction" - // TODO: need nowait adaptation - if (!ignoreSQLException(ex)) { - LOGGER.error("execute acquire lock failure, key is: {}", distributedLockDO.getLockKey(), ex); - } - try { - if (connection != null) { - connection.rollback(); - } - } catch (SQLException e) { - LOGGER.warn("rollback fail because of {}", e.getMessage(), e); - } - return false; - } finally { - try { - if (originalAutoCommit) { - connection.setAutoCommit(true); - } - IOUtil.close(connection); - } catch (SQLException ignore) { } - } - } - - @Override - public boolean releaseLock(DistributedLockDO distributedLockDO) { - if (demotion) { - return true; - } - - Connection connection = null; - boolean originalAutoCommit = false; - try { - connection = distributedLockDataSource.getConnection(); - originalAutoCommit = connection.getAutoCommit(); - connection.setAutoCommit(false); - - DistributedLockDO distributedLockDOFromDB = getDistributedLockDO(connection, distributedLockDO.getLockKey()); - if (null == distributedLockDOFromDB) { - throw new ShouldNeverHappenException("distributedLockDO would not be null when release distribute lock"); - } - - if (distributedLockDOFromDB.getExpireTime() >= System.currentTimeMillis() - && !Objects.equals(distributedLockDOFromDB.getLockValue(), distributedLockDO.getLockValue())) { - if (LOGGER.isDebugEnabled()) { - LOGGER.debug("the distribute lock for key :{} is holding by :{}, skip the release lock.", - distributedLockDO.getLockKey(), distributedLockDOFromDB.getLockValue()); - } - connection.commit(); - return true; - } - - distributedLockDO.setLockValue(StringUtils.SPACE); - distributedLockDO.setExpireTime(0L); - boolean ret = updateDistributedLock(connection, distributedLockDO); - - connection.commit(); - return ret; - } catch (SQLException ex) { - if (!ignoreSQLException(ex)) { - LOGGER.error("execute release lock failure, key is: {}", distributedLockDO.getLockKey(), ex); - } - - try { - if (connection != null) { - connection.rollback(); - } - } catch (SQLException e) { - LOGGER.warn("rollback fail because of {}", e.getMessage(), e); - } - return false; - } finally { - try { - if (originalAutoCommit) { - connection.setAutoCommit(true); - } - IOUtil.close(connection); - } catch (SQLException ignore) { } - } - } - - protected DistributedLockDO getDistributedLockDO(Connection connection, String key) throws SQLException { - try (PreparedStatement pst = connection.prepareStatement(DistributedLockSqlFactory.getDistributedLogStoreSql(dbType) - .getSelectDistributeForUpdateSql(distributedLockTable))) { - - pst.setString(1, key); - ResultSet resultSet = pst.executeQuery(); - - if (resultSet.next()) { - DistributedLockDO distributedLock = new DistributedLockDO(); - distributedLock.setExpireTime(resultSet.getLong(ServerTableColumnsName.DISTRIBUTED_LOCK_EXPIRE)); - distributedLock.setLockValue(resultSet.getString(ServerTableColumnsName.DISTRIBUTED_LOCK_VALUE)); - distributedLock.setLockKey(key); - return distributedLock; - } - return null; - } - } - - protected boolean insertDistribute(Connection connection, DistributedLockDO distributedLockDO) throws SQLException { - try (PreparedStatement insertPst = connection.prepareStatement(DistributedLockSqlFactory.getDistributedLogStoreSql(dbType) - .getInsertSql(distributedLockTable))) { - insertPst.setString(1, distributedLockDO.getLockKey()); - insertPst.setString(2, distributedLockDO.getLockValue()); - if (distributedLockDO.getExpireTime() > 0) { - distributedLockDO.setExpireTime(distributedLockDO.getExpireTime() + System.currentTimeMillis()); - } - insertPst.setLong(3, distributedLockDO.getExpireTime()); - return insertPst.executeUpdate() > 0; - } - } - - protected boolean updateDistributedLock(Connection connection, DistributedLockDO distributedLockDO) throws SQLException { - try (PreparedStatement updatePst = connection.prepareStatement(DistributedLockSqlFactory.getDistributedLogStoreSql(dbType) - .getUpdateSql(distributedLockTable))) { - updatePst.setString(1, distributedLockDO.getLockValue()); - if (distributedLockDO.getExpireTime() > 0) { - distributedLockDO.setExpireTime(distributedLockDO.getExpireTime() + System.currentTimeMillis()); - } - updatePst.setLong(2, distributedLockDO.getExpireTime()); - updatePst.setString(3, distributedLockDO.getLockKey()); - return updatePst.executeUpdate() > 0; - } - } - - private void init() { - this.distributedLockDataSource = EnhancedServiceLoader.load(DataSourceProvider.class, datasourceType).provide(); - } - - private boolean ignoreSQLException(SQLException exception) { - if (IGNORE_MYSQL_CODE.contains(exception.getErrorCode())) { - return true; - } - if (StringUtils.isNotBlank(exception.getMessage())) { - return IGNORE_MYSQL_MESSAGE.stream().anyMatch(message -> exception.getMessage().contains(message)); - } - return false; - } - -} diff --git a/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/storage/db/lock/DataBaseLockManager.java b/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/storage/db/lock/DataBaseLockManager.java deleted file mode 100644 index f73df2f9..00000000 --- a/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/storage/db/lock/DataBaseLockManager.java +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Copyright 1999-2019 Seata.io Group. - * - * Licensed 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 io.seata.server.storage.db.lock; - -import io.seata.common.executor.Initialize; -import io.seata.common.loader.EnhancedServiceLoader; -import io.seata.common.loader.LoadLevel; -import io.seata.config.ConfigurationFactory; -import io.seata.core.constants.ConfigurationKeys; -import io.seata.core.exception.TransactionException; -import io.seata.core.lock.Locker; -import io.seata.core.store.db.DataSourceProvider; -import io.seata.server.lock.AbstractLockManager; -import io.seata.server.session.BranchSession; -import io.seata.server.session.GlobalSession; - -import javax.sql.DataSource; - -/** - * The type db lock manager. - * - * @author zjinlei - */ -@LoadLevel(name = "db") -public class DataBaseLockManager extends AbstractLockManager implements Initialize { - - /** - * The locker. - */ - private Locker locker; - - @Override - public void init() { - // init dataSource - String datasourceType = ConfigurationFactory.getInstance().getConfig(ConfigurationKeys.STORE_DB_DATASOURCE_TYPE); - DataSource lockStoreDataSource = EnhancedServiceLoader.load(DataSourceProvider.class, datasourceType).provide(); - locker = new DataBaseLocker(lockStoreDataSource); - } - - @Override - public boolean releaseLock(BranchSession branchSession) throws TransactionException { - try { - return getLocker().releaseLock(branchSession.getXid(), branchSession.getBranchId()); - } catch (Exception t) { - LOGGER.error("unLock error, xid {}, branchId:{}", branchSession.getXid(), branchSession.getBranchId(), t); - return false; - } - } - - @Override - public Locker getLocker(BranchSession branchSession) { - return locker; - } - - @Override - public boolean releaseGlobalSessionLock(GlobalSession globalSession) throws TransactionException { - try { - return getLocker().releaseLock(globalSession.getXid()); - } catch (Exception t) { - LOGGER.error("unLock globalSession error, xid:{}", globalSession.getXid(), t); - return false; - } - } - -} diff --git a/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/storage/db/lock/DataBaseLocker.java b/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/storage/db/lock/DataBaseLocker.java deleted file mode 100644 index 8355bc03..00000000 --- a/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/storage/db/lock/DataBaseLocker.java +++ /dev/null @@ -1,144 +0,0 @@ -/* - * Copyright 1999-2019 Seata.io Group. - * - * Licensed 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 io.seata.server.storage.db.lock; - -import io.seata.common.exception.DataAccessException; -import io.seata.common.exception.StoreException; -import io.seata.common.util.CollectionUtils; -import io.seata.core.lock.AbstractLocker; -import io.seata.core.lock.RowLock; -import io.seata.core.model.LockStatus; -import io.seata.core.store.LockStore; - -import javax.sql.DataSource; -import java.util.List; - -/** - * The type Data base locker. - * - * @author zhangsen - */ -public class DataBaseLocker extends AbstractLocker { - - private LockStore lockStore; - - /** - * Instantiates a new Data base locker. - */ - public DataBaseLocker() { - } - - /** - * Instantiates a new Data base locker. - * - * @param logStoreDataSource the log store data source - */ - public DataBaseLocker(DataSource logStoreDataSource) { - lockStore = new LockStoreDataBaseDAO(logStoreDataSource); - } - - @Override - public boolean acquireLock(List locks) { - return acquireLock(locks, true, false); - } - - @Override - public boolean acquireLock(List locks, boolean autoCommit, boolean skipCheckLock) { - if (CollectionUtils.isEmpty(locks)) { - // no lock - return true; - } - try { - return lockStore.acquireLock(convertToLockDO(locks), autoCommit, skipCheckLock); - } catch (StoreException e) { - throw e; - } catch (Exception t) { - LOGGER.error("AcquireLock error, locks:{}", CollectionUtils.toString(locks), t); - return false; - } - } - - @Override - public boolean releaseLock(List locks) { - if (CollectionUtils.isEmpty(locks)) { - // no lock - return true; - } - try { - return lockStore.unLock(convertToLockDO(locks)); - } catch (StoreException e) { - throw e; - } catch (Exception t) { - LOGGER.error("unLock error, locks:{}", CollectionUtils.toString(locks), t); - return false; - } - } - - @Override - public boolean releaseLock(String xid, Long branchId) { - try { - return lockStore.unLock(branchId); - } catch (StoreException e) { - throw e; - } catch (Exception t) { - LOGGER.error("unLock by branchId error, xid {}, branchId:{}", xid, branchId, t); - return false; - } - } - - @Override - public boolean releaseLock(String xid) { - try { - return lockStore.unLock(xid); - } catch (StoreException e) { - throw e; - } catch (Exception t) { - LOGGER.error("unLock by branchIds error, xid {}", xid, t); - return false; - } - } - - @Override - public boolean isLockable(List locks) { - if (CollectionUtils.isEmpty(locks)) { - // no lock - return true; - } - try { - return lockStore.isLockable(convertToLockDO(locks)); - } catch (DataAccessException e) { - throw e; - } catch (Exception t) { - LOGGER.error("isLockable error, locks:{}", CollectionUtils.toString(locks), t); - return false; - } - } - - @Override - public void updateLockStatus(String xid, LockStatus lockStatus) { - lockStore.updateLockStatus(xid, lockStatus); - } - - /** - * Sets lock store. - * - * @param lockStore the lock store - */ - public void setLockStore(LockStore lockStore) { - this.lockStore = lockStore; - } - -} diff --git a/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/storage/db/lock/LockStoreDataBaseDAO.java b/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/storage/db/lock/LockStoreDataBaseDAO.java deleted file mode 100644 index 21f5fa25..00000000 --- a/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/storage/db/lock/LockStoreDataBaseDAO.java +++ /dev/null @@ -1,437 +0,0 @@ -/* - * Copyright 1999-2019 Seata.io Group. - * - * Licensed 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 io.seata.server.storage.db.lock; - -import io.seata.common.exception.DataAccessException; -import io.seata.common.exception.StoreException; -import io.seata.common.util.CollectionUtils; -import io.seata.common.util.IOUtil; -import io.seata.common.util.LambdaUtils; -import io.seata.common.util.StringUtils; -import io.seata.config.Configuration; -import io.seata.config.ConfigurationFactory; -import io.seata.core.constants.ConfigurationKeys; -import io.seata.core.constants.ServerTableColumnsName; -import io.seata.core.exception.BranchTransactionException; -import io.seata.core.model.LockStatus; -import io.seata.core.store.LockDO; -import io.seata.core.store.LockStore; -import io.seata.core.store.db.sql.lock.LockStoreSqlFactory; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import javax.sql.DataSource; -import java.sql.*; -import java.util.Collections; -import java.util.HashSet; -import java.util.List; -import java.util.Set; -import java.util.stream.Collectors; - -import static io.seata.common.DefaultValues.DEFAULT_LOCK_DB_TABLE; -import static io.seata.core.exception.TransactionExceptionCode.LockKeyConflictFailFast; - -/** - * The type Data base lock store. - * - * @author zhangsen - */ -public class LockStoreDataBaseDAO implements LockStore { - - private static final Logger LOGGER = LoggerFactory.getLogger(LockStoreDataBaseDAO.class); - - /** - * The constant CONFIG. - */ - protected static final Configuration CONFIG = ConfigurationFactory.getInstance(); - - /** - * The Lock store data source. - */ - protected DataSource lockStoreDataSource; - - /** - * The Lock table. - */ - protected String lockTable; - - /** - * The Db type. - */ - protected String dbType; - - /** - * Instantiates a new Data base lock store dao. - * - * @param lockStoreDataSource the log store data source - */ - public LockStoreDataBaseDAO(DataSource lockStoreDataSource) { - this.lockStoreDataSource = lockStoreDataSource; - lockTable = CONFIG.getConfig(ConfigurationKeys.LOCK_DB_TABLE, DEFAULT_LOCK_DB_TABLE); - dbType = CONFIG.getConfig(ConfigurationKeys.STORE_DB_TYPE); - if (StringUtils.isBlank(dbType)) { - throw new StoreException("there must be db type."); - } - if (lockStoreDataSource == null) { - throw new StoreException("there must be lockStoreDataSource."); - } - } - - @Override - public boolean acquireLock(LockDO lockDO) { - return acquireLock(Collections.singletonList(lockDO)); - } - - @Override - public boolean acquireLock(List lockDOs) { - return acquireLock(lockDOs, true, false); - } - - @Override - public boolean acquireLock(List lockDOs, boolean autoCommit, boolean skipCheckLock) { - Connection conn = null; - PreparedStatement ps = null; - ResultSet rs = null; - Set dbExistedRowKeys = new HashSet<>(); - boolean originalAutoCommit = true; - if (lockDOs.size() > 1) { - lockDOs = lockDOs.stream().filter(LambdaUtils.distinctByKey(LockDO::getRowKey)).collect(Collectors.toList()); - } - try { - conn = lockStoreDataSource.getConnection(); - if (originalAutoCommit = conn.getAutoCommit()) { - conn.setAutoCommit(false); - } - List unrepeatedLockDOs = lockDOs; - - //check lock - if (!skipCheckLock) { - - boolean canLock = true; - //query - String checkLockSQL = LockStoreSqlFactory.getLogStoreSql(dbType).getCheckLockableSql(lockTable, lockDOs.size()); - ps = conn.prepareStatement(checkLockSQL); - for (int i = 0; i < lockDOs.size(); i++) { - ps.setString(i + 1, lockDOs.get(i).getRowKey()); - } - rs = ps.executeQuery(); - String currentXID = lockDOs.get(0).getXid(); - boolean failFast = false; - while (rs.next()) { - String dbXID = rs.getString(ServerTableColumnsName.LOCK_TABLE_XID); - if (!StringUtils.equals(dbXID, currentXID)) { - if (LOGGER.isInfoEnabled()) { - String dbPk = rs.getString(ServerTableColumnsName.LOCK_TABLE_PK); - String dbTableName = rs.getString(ServerTableColumnsName.LOCK_TABLE_TABLE_NAME); - long dbBranchId = rs.getLong(ServerTableColumnsName.LOCK_TABLE_BRANCH_ID); - LOGGER.info("Global lock on [{}:{}] is holding by xid {} branchId {}", dbTableName, dbPk, dbXID, dbBranchId); - } - if (!autoCommit) { - int status = rs.getInt(ServerTableColumnsName.LOCK_TABLE_STATUS); - if (status == LockStatus.Rollbacking.getCode()) { - failFast = true; - } - } - canLock = false; - break; - } - - dbExistedRowKeys.add(rs.getString(ServerTableColumnsName.LOCK_TABLE_ROW_KEY)); - } - if (!canLock) { - conn.rollback(); - if (failFast) { - throw new StoreException(new BranchTransactionException(LockKeyConflictFailFast)); - } - return false; - } - // If the lock has been exists in db, remove it from the lockDOs - if (CollectionUtils.isNotEmpty(dbExistedRowKeys)) { - unrepeatedLockDOs = lockDOs.stream().filter(lockDO -> !dbExistedRowKeys.contains(lockDO.getRowKey())) - .collect(Collectors.toList()); - } - if (CollectionUtils.isEmpty(unrepeatedLockDOs)) { - conn.rollback(); - return true; - } - } - - // lock - if (unrepeatedLockDOs.size() == 1) { - LockDO lockDO = unrepeatedLockDOs.get(0); - if (!doAcquireLock(conn, lockDO)) { - if (LOGGER.isInfoEnabled()) { - LOGGER.info("Global lock acquire failed, xid {} branchId {} pk {}", lockDO.getXid(), lockDO.getBranchId(), lockDO.getPk()); - } - conn.rollback(); - return false; - } - } else { - if (!doAcquireLocks(conn, unrepeatedLockDOs)) { - if (LOGGER.isInfoEnabled()) { - LOGGER.info("Global lock batch acquire failed, xid {} branchId {} pks {}", unrepeatedLockDOs.get(0).getXid(), - unrepeatedLockDOs.get(0).getBranchId(), unrepeatedLockDOs.stream().map(lockDO -> lockDO.getPk()).collect(Collectors.toList())); - } - conn.rollback(); - return false; - } - } - conn.commit(); - return true; - } catch (SQLException e) { - throw new StoreException(e); - } finally { - IOUtil.close(rs, ps); - if (conn != null) { - try { - if (originalAutoCommit) { - conn.setAutoCommit(true); - } - conn.close(); - } catch (SQLException e) { - } - } - } - } - - @Override - public boolean unLock(LockDO lockDO) { - return unLock(Collections.singletonList(lockDO)); - } - - @Override - public boolean unLock(List lockDOs) { - Connection conn = null; - PreparedStatement ps = null; - try { - conn = lockStoreDataSource.getConnection(); - conn.setAutoCommit(true); - - //batch release lock - String batchDeleteSQL = LockStoreSqlFactory.getLogStoreSql(dbType).getBatchDeleteLockSql(lockTable, lockDOs.size()); - ps = conn.prepareStatement(batchDeleteSQL); - ps.setString(1, lockDOs.get(0).getXid()); - for (int i = 0; i < lockDOs.size(); i++) { - ps.setString(i + 2, lockDOs.get(i).getRowKey()); - } - ps.executeUpdate(); - } catch (SQLException e) { - throw new StoreException(e); - } finally { - IOUtil.close(ps, conn); - } - return true; - } - - @Override - public boolean unLock(String xid) { - Connection conn = null; - PreparedStatement ps = null; - try { - conn = lockStoreDataSource.getConnection(); - conn.setAutoCommit(true); - //batch release lock by branch list - String batchDeleteSQL = LockStoreSqlFactory.getLogStoreSql(dbType).getBatchDeleteLockSqlByXid(lockTable); - ps = conn.prepareStatement(batchDeleteSQL); - ps.setString(1, xid); - ps.executeUpdate(); - } catch (SQLException e) { - throw new StoreException(e); - } finally { - IOUtil.close(ps, conn); - } - return true; - } - - @Override - public boolean unLock(Long branchId) { - Connection conn = null; - PreparedStatement ps = null; - try { - conn = lockStoreDataSource.getConnection(); - conn.setAutoCommit(true); - //batch release lock by branchId - String batchDeleteSQL = LockStoreSqlFactory.getLogStoreSql(dbType).getBatchDeleteLockSqlByBranchId(lockTable); - ps = conn.prepareStatement(batchDeleteSQL); - ps.setLong(1, branchId); - ps.executeUpdate(); - } catch (SQLException e) { - throw new StoreException(e); - } finally { - IOUtil.close(ps, conn); - } - return true; - } - - @Override - public boolean isLockable(List lockDOs) { - Connection conn = null; - try { - conn = lockStoreDataSource.getConnection(); - conn.setAutoCommit(true); - if (!checkLockable(conn, lockDOs)) { - return false; - } - return true; - } catch (SQLException e) { - throw new DataAccessException(e); - } finally { - IOUtil.close(conn); - } - } - - @Override - public void updateLockStatus(String xid, LockStatus lockStatus) { - String updateStatusLockByGlobalSql = - LockStoreSqlFactory.getLogStoreSql(dbType).getBatchUpdateStatusLockByGlobalSql(lockTable); - try (Connection conn = lockStoreDataSource.getConnection(); - PreparedStatement ps = conn.prepareStatement(updateStatusLockByGlobalSql)) { - conn.setAutoCommit(true); - ps.setInt(1, lockStatus.getCode()); - ps.setString(2, xid); - ps.executeUpdate(); - } catch (SQLException e) { - throw new DataAccessException(e); - } - } - - /** - * Do acquire lock boolean. - * - * @param conn the conn - * @param lockDO the lock do - * @return the boolean - */ - protected boolean doAcquireLock(Connection conn, LockDO lockDO) { - PreparedStatement ps = null; - try { - //insert - String insertLockSQL = LockStoreSqlFactory.getLogStoreSql(dbType).getInsertLockSQL(lockTable); - ps = conn.prepareStatement(insertLockSQL); - ps.setString(1, lockDO.getXid()); - ps.setLong(2, lockDO.getTransactionId()); - ps.setLong(3, lockDO.getBranchId()); - ps.setString(4, lockDO.getResourceId()); - ps.setString(5, lockDO.getTableName()); - ps.setString(6, lockDO.getPk()); - ps.setString(7, lockDO.getRowKey()); - ps.setInt(8, LockStatus.Locked.getCode()); - return ps.executeUpdate() > 0; - } catch (SQLException e) { - if (e instanceof SQLIntegrityConstraintViolationException) { - return false; - } - throw new StoreException(e); - } finally { - IOUtil.close(ps); - } - } - - /** - * Do acquire lock boolean. - * - * @param conn the conn - * @param lockDOs the lock do list - * @return the boolean - */ - protected boolean doAcquireLocks(Connection conn, List lockDOs) throws SQLException { - PreparedStatement ps = null; - try { - //insert - String insertLockSQL = LockStoreSqlFactory.getLogStoreSql(dbType).getInsertLockSQL(lockTable); - ps = conn.prepareStatement(insertLockSQL); - for (LockDO lockDO : lockDOs) { - ps.setString(1, lockDO.getXid()); - ps.setLong(2, lockDO.getTransactionId()); - ps.setLong(3, lockDO.getBranchId()); - ps.setString(4, lockDO.getResourceId()); - ps.setString(5, lockDO.getTableName()); - ps.setString(6, lockDO.getPk()); - ps.setString(7, lockDO.getRowKey()); - ps.setInt(8, lockDO.getStatus()); - ps.addBatch(); - } - return ps.executeBatch().length == lockDOs.size(); - } catch (SQLIntegrityConstraintViolationException e) { - LOGGER.error("Global lock batch acquire error: {}", e.getMessage(), e); - //return false,let the caller go to conn.rollabck() - return false; - } catch (SQLException e) { - throw e; - } finally { - IOUtil.close(ps); - } - } - - /** - * Check lock boolean. - * - * @param conn the conn - * @param lockDOs the lock do - * @return the boolean - */ - protected boolean checkLockable(Connection conn, List lockDOs) { - PreparedStatement ps = null; - ResultSet rs = null; - try { - //query - String checkLockSQL = LockStoreSqlFactory.getLogStoreSql(dbType).getCheckLockableSql(lockTable, lockDOs.size()); - ps = conn.prepareStatement(checkLockSQL); - for (int i = 0; i < lockDOs.size(); i++) { - ps.setString(i + 1, lockDOs.get(i).getRowKey()); - } - rs = ps.executeQuery(); - while (rs.next()) { - String xid = rs.getString("xid"); - if (!StringUtils.equals(xid, lockDOs.get(0).getXid())) { - return false; - } - } - return true; - } catch (SQLException e) { - throw new DataAccessException(e); - } finally { - IOUtil.close(rs, ps); - } - } - - /** - * Sets lock table. - * - * @param lockTable the lock table - */ - public void setLockTable(String lockTable) { - this.lockTable = lockTable; - } - - /** - * Sets db type. - * - * @param dbType the db type - */ - public void setDbType(String dbType) { - this.dbType = dbType; - } - - /** - * Sets log store data source. - * - * @param lockStoreDataSource the log store data source - */ - public void setLogStoreDataSource(DataSource lockStoreDataSource) { - this.lockStoreDataSource = lockStoreDataSource; - } -} diff --git a/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/storage/db/session/DataBaseSessionManager.java b/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/storage/db/session/DataBaseSessionManager.java deleted file mode 100644 index f93e3a9e..00000000 --- a/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/storage/db/session/DataBaseSessionManager.java +++ /dev/null @@ -1,190 +0,0 @@ -/* - * Copyright 1999-2019 Seata.io Group. - * - * Licensed 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 io.seata.server.storage.db.session; - -import io.seata.common.exception.StoreException; -import io.seata.common.executor.Initialize; -import io.seata.common.loader.LoadLevel; -import io.seata.common.loader.Scope; -import io.seata.common.util.StringUtils; -import io.seata.core.exception.TransactionException; -import io.seata.core.model.BranchStatus; -import io.seata.core.model.GlobalStatus; -import io.seata.server.session.*; -import io.seata.server.storage.db.store.DataBaseTransactionStoreManager; -import io.seata.server.store.TransactionStoreManager.LogOperation; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.util.Collection; -import java.util.List; - -/** - * The Data base session manager. - * - * @author zhangsen - */ -@LoadLevel(name = "db", scope = Scope.PROTOTYPE) -public class DataBaseSessionManager extends AbstractSessionManager - implements Initialize { - - /** - * The constant LOGGER. - */ - protected static final Logger LOGGER = LoggerFactory.getLogger(DataBaseSessionManager.class); - - /** - * The Task name. - */ - protected String taskName; - - /** - * Instantiates a new Data base session manager. - */ - public DataBaseSessionManager() { - super(); - } - - /** - * Instantiates a new Data base session manager. - * - * @param name the name - */ - public DataBaseSessionManager(String name) { - super(); - this.taskName = name; - } - - @Override - public void init() { - transactionStoreManager = DataBaseTransactionStoreManager.getInstance(); - } - - @Override - public void addGlobalSession(GlobalSession session) throws TransactionException { - if (StringUtils.isBlank(taskName)) { - boolean ret = transactionStoreManager.writeSession(LogOperation.GLOBAL_ADD, session); - if (!ret) { - throw new StoreException("addGlobalSession failed."); - } - } else { - boolean ret = transactionStoreManager.writeSession(LogOperation.GLOBAL_UPDATE, session); - if (!ret) { - throw new StoreException("addGlobalSession failed."); - } - } - } - - @Override - public void updateGlobalSessionStatus(GlobalSession session, GlobalStatus status) throws TransactionException { - if (StringUtils.isNotBlank(taskName)) { - return; - } - session.setStatus(status); - boolean ret = transactionStoreManager.writeSession(LogOperation.GLOBAL_UPDATE, session); - if (!ret) { - throw new StoreException("updateGlobalSessionStatus failed."); - } - } - - /** - * remove globalSession - * 1. rootSessionManager remove normal globalSession - * 2. retryCommitSessionManager and retryRollbackSessionManager remove retry expired globalSession - * @param session the session - * @throws TransactionException the transaction exception - */ - @Override - public void removeGlobalSession(GlobalSession session) throws TransactionException { - boolean ret = transactionStoreManager.writeSession(LogOperation.GLOBAL_REMOVE, session); - if (!ret) { - throw new StoreException("removeGlobalSession failed."); - } - } - - @Override - public void addBranchSession(GlobalSession globalSession, BranchSession session) throws TransactionException { - if (StringUtils.isNotBlank(taskName)) { - return; - } - boolean ret = transactionStoreManager.writeSession(LogOperation.BRANCH_ADD, session); - if (!ret) { - throw new StoreException("addBranchSession failed."); - } - } - - @Override - public void updateBranchSessionStatus(BranchSession session, BranchStatus status) throws TransactionException { - if (StringUtils.isNotBlank(taskName)) { - return; - } - boolean ret = transactionStoreManager.writeSession(LogOperation.BRANCH_UPDATE, session); - if (!ret) { - throw new StoreException("updateBranchSessionStatus failed."); - } - } - - @Override - public void removeBranchSession(GlobalSession globalSession, BranchSession session) throws TransactionException { - if (StringUtils.isNotBlank(taskName)) { - return; - } - boolean ret = transactionStoreManager.writeSession(LogOperation.BRANCH_REMOVE, session); - if (!ret) { - throw new StoreException("removeBranchSession failed."); - } - } - - @Override - public GlobalSession findGlobalSession(String xid) { - return this.findGlobalSession(xid, true); - } - - @Override - public GlobalSession findGlobalSession(String xid, boolean withBranchSessions) { - return transactionStoreManager.readSession(xid, withBranchSessions); - } - - @Override - public Collection allSessions() { - // get by taskName - if (SessionHolder.ASYNC_COMMITTING_SESSION_MANAGER_NAME.equalsIgnoreCase(taskName)) { - return findGlobalSessions(new SessionCondition(GlobalStatus.AsyncCommitting)); - } else if (SessionHolder.RETRY_COMMITTING_SESSION_MANAGER_NAME.equalsIgnoreCase(taskName)) { - return findGlobalSessions(new SessionCondition(GlobalStatus.CommitRetrying, GlobalStatus.Committing)); - } else if (SessionHolder.RETRY_ROLLBACKING_SESSION_MANAGER_NAME.equalsIgnoreCase(taskName)) { - return findGlobalSessions(new SessionCondition(GlobalStatus.RollbackRetrying, GlobalStatus.Rollbacking, - GlobalStatus.TimeoutRollbacking, GlobalStatus.TimeoutRollbackRetrying)); - } else { - // all data - return findGlobalSessions(new SessionCondition(GlobalStatus.UnKnown, GlobalStatus.Begin, GlobalStatus.Committing, - GlobalStatus.CommitRetrying, GlobalStatus.Rollbacking, GlobalStatus.RollbackRetrying, GlobalStatus.TimeoutRollbacking, - GlobalStatus.TimeoutRollbackRetrying, GlobalStatus.AsyncCommitting)); - } - } - - @Override - public List findGlobalSessions(SessionCondition condition) { - // nothing need to do - return transactionStoreManager.readSession(condition); - } - - @Override - public T lockAndExecute(GlobalSession globalSession, GlobalSession.LockCallable lockCallable) - throws TransactionException { - return lockCallable.call(); - } -} diff --git a/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/storage/db/store/DataBaseTransactionStoreManager.java b/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/storage/db/store/DataBaseTransactionStoreManager.java deleted file mode 100644 index e6eb83e6..00000000 --- a/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/storage/db/store/DataBaseTransactionStoreManager.java +++ /dev/null @@ -1,256 +0,0 @@ -/* - * Copyright 1999-2019 Seata.io Group. - * - * Licensed 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 io.seata.server.storage.db.store; - -import io.seata.common.exception.StoreException; -import io.seata.common.loader.EnhancedServiceLoader; -import io.seata.common.util.CollectionUtils; -import io.seata.common.util.StringUtils; -import io.seata.config.Configuration; -import io.seata.config.ConfigurationFactory; -import io.seata.core.constants.ConfigurationKeys; -import io.seata.core.model.GlobalStatus; -import io.seata.core.store.BranchTransactionDO; -import io.seata.core.store.GlobalTransactionDO; -import io.seata.core.store.LogStore; -import io.seata.core.store.db.DataSourceProvider; -import io.seata.server.session.GlobalSession; -import io.seata.server.session.SessionCondition; -import io.seata.server.storage.SessionConverter; -import io.seata.server.store.AbstractTransactionStoreManager; -import io.seata.server.store.SessionStorable; -import io.seata.server.store.TransactionStoreManager; - -import javax.sql.DataSource; -import java.util.*; -import java.util.stream.Collectors; - -import static io.seata.common.DefaultValues.DEFAULT_QUERY_LIMIT; - -/** - * The type Database transaction store manager. - * - * @author zhangsen - */ -public class DataBaseTransactionStoreManager extends AbstractTransactionStoreManager - implements TransactionStoreManager { - - private static volatile DataBaseTransactionStoreManager instance; - - /** - * The constant CONFIG. - */ - protected static final Configuration CONFIG = ConfigurationFactory.getInstance(); - - /** - * The Log store. - */ - protected LogStore logStore; - - /** - * The Log query limit. - */ - protected int logQueryLimit; - - /** - * Get the instance. - */ - public static DataBaseTransactionStoreManager getInstance() { - if (instance == null) { - synchronized (DataBaseTransactionStoreManager.class) { - if (instance == null) { - instance = new DataBaseTransactionStoreManager(); - } - } - } - return instance; - } - - /** - * Instantiates a new Database transaction store manager. - */ - private DataBaseTransactionStoreManager() { - logQueryLimit = CONFIG.getInt(ConfigurationKeys.STORE_DB_LOG_QUERY_LIMIT, DEFAULT_QUERY_LIMIT); - String datasourceType = CONFIG.getConfig(ConfigurationKeys.STORE_DB_DATASOURCE_TYPE); - //init dataSource - DataSource logStoreDataSource = EnhancedServiceLoader.load(DataSourceProvider.class, datasourceType).provide(); - logStore = new LogStoreDataBaseDAO(logStoreDataSource); - } - - @Override - public boolean writeSession(LogOperation logOperation, SessionStorable session) { - if (LogOperation.GLOBAL_ADD.equals(logOperation)) { - return logStore.insertGlobalTransactionDO(SessionConverter.convertGlobalTransactionDO(session)); - } else if (LogOperation.GLOBAL_UPDATE.equals(logOperation)) { - return logStore.updateGlobalTransactionDO(SessionConverter.convertGlobalTransactionDO(session)); - } else if (LogOperation.GLOBAL_REMOVE.equals(logOperation)) { - return logStore.deleteGlobalTransactionDO(SessionConverter.convertGlobalTransactionDO(session)); - } else if (LogOperation.BRANCH_ADD.equals(logOperation)) { - return logStore.insertBranchTransactionDO(SessionConverter.convertBranchTransactionDO(session)); - } else if (LogOperation.BRANCH_UPDATE.equals(logOperation)) { - return logStore.updateBranchTransactionDO(SessionConverter.convertBranchTransactionDO(session)); - } else if (LogOperation.BRANCH_REMOVE.equals(logOperation)) { - return logStore.deleteBranchTransactionDO(SessionConverter.convertBranchTransactionDO(session)); - } else { - throw new StoreException("Unknown LogOperation:" + logOperation.name()); - } - } - - /** - * Read session global session. - * - * @param transactionId the transaction id - * @return the global session - */ - public GlobalSession readSession(Long transactionId) { - //global transaction - GlobalTransactionDO globalTransactionDO = logStore.queryGlobalTransactionDO(transactionId); - if (globalTransactionDO == null) { - return null; - } - //branch transactions - List branchTransactionDOs = logStore.queryBranchTransactionDO( - globalTransactionDO.getXid()); - return getGlobalSession(globalTransactionDO, branchTransactionDOs); - } - - /** - * Read session global session. - * - * @param xid the xid - * @return the global session - */ - @Override - public GlobalSession readSession(String xid) { - return this.readSession(xid, true); - } - - /** - * Read session global session. - * - * @param xid the xid - * @param withBranchSessions the withBranchSessions - * @return the global session - */ - @Override - public GlobalSession readSession(String xid, boolean withBranchSessions) { - //global transaction - GlobalTransactionDO globalTransactionDO = logStore.queryGlobalTransactionDO(xid); - if (globalTransactionDO == null) { - return null; - } - //branch transactions - List branchTransactionDOs = null; - //reduce rpc with db when branchRegister and getGlobalStatus - if (withBranchSessions) { - branchTransactionDOs = logStore.queryBranchTransactionDO(globalTransactionDO.getXid()); - } - return getGlobalSession(globalTransactionDO, branchTransactionDOs); - } - - @Override - public List readSortByTimeoutBeginSessions(boolean withBranchSessions) { - return readSession(new GlobalStatus[] {GlobalStatus.Begin}, withBranchSessions); - } - - /** - * Read session list. - * - * @param statuses the statuses - * @return the list - */ - @Override - public List readSession(GlobalStatus[] statuses, boolean withBranchSessions) { - int[] states = new int[statuses.length]; - for (int i = 0; i < statuses.length; i++) { - states[i] = statuses[i].getCode(); - } - //global transaction - List globalTransactionDOs = logStore.queryGlobalTransactionDO(states, logQueryLimit); - Map> branchTransactionDOsMap = Collections.emptyMap(); - if (CollectionUtils.isNotEmpty(globalTransactionDOs)) { - List xids = - globalTransactionDOs.stream().map(GlobalTransactionDO::getXid).collect(Collectors.toList()); - if (withBranchSessions) { - List branchTransactionDOs = logStore.queryBranchTransactionDO(xids); - branchTransactionDOsMap = branchTransactionDOs.stream().collect( - Collectors.groupingBy(BranchTransactionDO::getXid, LinkedHashMap::new, Collectors.toList())); - } - } - Map> finalBranchTransactionDOsMap = branchTransactionDOsMap; - return globalTransactionDOs.stream() - .map(globalTransactionDO -> getGlobalSession(globalTransactionDO, - finalBranchTransactionDOsMap.get(globalTransactionDO.getXid()), withBranchSessions)) - .collect(Collectors.toList()); - } - - @Override - public List readSession(SessionCondition sessionCondition) { - if (StringUtils.isNotBlank(sessionCondition.getXid())) { - GlobalSession globalSession = readSession(sessionCondition.getXid()); - if (globalSession != null) { - List globalSessions = new ArrayList<>(); - globalSessions.add(globalSession); - return globalSessions; - } - } else if (sessionCondition.getTransactionId() != null) { - GlobalSession globalSession = readSession(sessionCondition.getTransactionId()); - if (globalSession != null) { - List globalSessions = new ArrayList<>(); - globalSessions.add(globalSession); - return globalSessions; - } - } else if (CollectionUtils.isNotEmpty(sessionCondition.getStatuses())) { - return readSession(sessionCondition.getStatuses(), !sessionCondition.isLazyLoadBranch()); - } - return null; - } - - private GlobalSession getGlobalSession(GlobalTransactionDO globalTransactionDO, - List branchTransactionDOs) { - return getGlobalSession(globalTransactionDO, branchTransactionDOs, true); - } - - private GlobalSession getGlobalSession(GlobalTransactionDO globalTransactionDO, - List branchTransactionDOs, boolean withBranchSessions) { - GlobalSession globalSession = SessionConverter.convertGlobalSession(globalTransactionDO, !withBranchSessions); - // branch transactions - if (CollectionUtils.isNotEmpty(branchTransactionDOs)) { - for (BranchTransactionDO branchTransactionDO : branchTransactionDOs) { - globalSession.add(SessionConverter.convertBranchSession(branchTransactionDO)); - } - } - return globalSession; - } - - /** - * Sets log store. - * - * @param logStore the log store - */ - public void setLogStore(LogStore logStore) { - this.logStore = logStore; - } - - /** - * Sets log query limit. - * - * @param logQueryLimit the log query limit - */ - public void setLogQueryLimit(int logQueryLimit) { - this.logQueryLimit = logQueryLimit; - } -} diff --git a/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/storage/db/store/LogStoreDataBaseDAO.java b/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/storage/db/store/LogStoreDataBaseDAO.java deleted file mode 100644 index 94baf8e3..00000000 --- a/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/storage/db/store/LogStoreDataBaseDAO.java +++ /dev/null @@ -1,601 +0,0 @@ -/* - * Copyright 1999-2019 Seata.io Group. - * - * Licensed 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 io.seata.server.storage.db.store; - -import io.seata.common.exception.DataAccessException; -import io.seata.common.exception.StoreException; -import io.seata.common.util.IOUtil; -import io.seata.common.util.StringUtils; -import io.seata.config.Configuration; -import io.seata.config.ConfigurationFactory; -import io.seata.core.constants.ConfigurationKeys; -import io.seata.core.constants.ServerTableColumnsName; -import io.seata.core.store.BranchTransactionDO; -import io.seata.core.store.GlobalTransactionDO; -import io.seata.core.store.LogStore; -import io.seata.core.store.db.sql.log.LogStoreSqlsFactory; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import javax.sql.DataSource; -import java.sql.*; -import java.util.ArrayList; -import java.util.List; - -import static io.seata.common.DefaultValues.DEFAULT_STORE_DB_BRANCH_TABLE; -import static io.seata.common.DefaultValues.DEFAULT_STORE_DB_GLOBAL_TABLE; - -/** - * The type Log store data base dao. - * - * @author zhangsen - */ -public class LogStoreDataBaseDAO implements LogStore { - - private static final Logger LOGGER = LoggerFactory.getLogger(LogStoreDataBaseDAO.class); - - /** - * The transaction name key - */ - private static final String TRANSACTION_NAME_KEY = "TRANSACTION_NAME"; - /** - * The transaction name default size is 128 - */ - private static final int TRANSACTION_NAME_DEFAULT_SIZE = 128; - - /** - * The constant CONFIG. - */ - protected static final Configuration CONFIG = ConfigurationFactory.getInstance(); - - /** - * The Log store data source. - */ - protected DataSource logStoreDataSource = null; - - /** - * The Global table. - */ - protected String globalTable; - - /** - * The Branch table. - */ - protected String branchTable; - - private String dbType; - - private int transactionNameColumnSize = TRANSACTION_NAME_DEFAULT_SIZE; - - /** - * Instantiates a new Log store data base dao. - * - * @param logStoreDataSource the log store data source - */ - public LogStoreDataBaseDAO(DataSource logStoreDataSource) { - this.logStoreDataSource = logStoreDataSource; - globalTable = CONFIG.getConfig(ConfigurationKeys.STORE_DB_GLOBAL_TABLE, - DEFAULT_STORE_DB_GLOBAL_TABLE); - branchTable = CONFIG.getConfig(ConfigurationKeys.STORE_DB_BRANCH_TABLE, - DEFAULT_STORE_DB_BRANCH_TABLE); - dbType = CONFIG.getConfig(ConfigurationKeys.STORE_DB_TYPE); - if (StringUtils.isBlank(dbType)) { - throw new StoreException("there must be db type."); - } - if (logStoreDataSource == null) { - throw new StoreException("there must be logStoreDataSource."); - } - // init transaction_name size - initTransactionNameSize(); - } - - @Override - public GlobalTransactionDO queryGlobalTransactionDO(String xid) { - String sql = LogStoreSqlsFactory.getLogStoreSqls(dbType).getQueryGlobalTransactionSQL(globalTable); - Connection conn = null; - PreparedStatement ps = null; - ResultSet rs = null; - try { - conn = logStoreDataSource.getConnection(); - conn.setAutoCommit(true); - ps = conn.prepareStatement(sql); - ps.setString(1, xid); - rs = ps.executeQuery(); - if (rs.next()) { - return convertGlobalTransactionDO(rs); - } else { - return null; - } - } catch (SQLException e) { - throw new DataAccessException(e); - } finally { - IOUtil.close(rs, ps, conn); - } - } - - @Override - public GlobalTransactionDO queryGlobalTransactionDO(long transactionId) { - String sql = LogStoreSqlsFactory.getLogStoreSqls(dbType).getQueryGlobalTransactionSQLByTransactionId(globalTable); - Connection conn = null; - PreparedStatement ps = null; - ResultSet rs = null; - try { - conn = logStoreDataSource.getConnection(); - conn.setAutoCommit(true); - ps = conn.prepareStatement(sql); - ps.setLong(1, transactionId); - rs = ps.executeQuery(); - if (rs.next()) { - return convertGlobalTransactionDO(rs); - } else { - return null; - } - } catch (SQLException e) { - throw new DataAccessException(e); - } finally { - IOUtil.close(rs, ps, conn); - } - } - - @Override - public List queryGlobalTransactionDO(int[] statuses, int limit) { - List ret = new ArrayList<>(); - Connection conn = null; - PreparedStatement ps = null; - ResultSet rs = null; - try { - conn = logStoreDataSource.getConnection(); - conn.setAutoCommit(true); - - String paramsPlaceHolder = org.apache.commons.lang.StringUtils.repeat("?", ",", statuses.length); - - String sql = LogStoreSqlsFactory.getLogStoreSqls(dbType).getQueryGlobalTransactionSQLByStatus(globalTable, paramsPlaceHolder); - ps = conn.prepareStatement(sql); - for (int i = 0; i < statuses.length; i++) { - int status = statuses[i]; - ps.setInt(i + 1, status); - } - ps.setInt(statuses.length + 1, limit); - rs = ps.executeQuery(); - while (rs.next()) { - ret.add(convertGlobalTransactionDO(rs)); - } - return ret; - } catch (SQLException e) { - throw new DataAccessException(e); - } finally { - IOUtil.close(rs, ps, conn); - } - } - - @Override - public boolean insertGlobalTransactionDO(GlobalTransactionDO globalTransactionDO) { - String sql = LogStoreSqlsFactory.getLogStoreSqls(dbType).getInsertGlobalTransactionSQL(globalTable); - Connection conn = null; - PreparedStatement ps = null; - try { - int index = 1; - conn = logStoreDataSource.getConnection(); - conn.setAutoCommit(true); - ps = conn.prepareStatement(sql); - ps.setString(index++, globalTransactionDO.getXid()); - ps.setLong(index++, globalTransactionDO.getTransactionId()); - ps.setInt(index++, globalTransactionDO.getStatus()); - ps.setString(index++, globalTransactionDO.getApplicationId()); - ps.setString(index++, globalTransactionDO.getTransactionServiceGroup()); - String transactionName = globalTransactionDO.getTransactionName(); - transactionName = transactionName.length() > transactionNameColumnSize ? - transactionName.substring(0, transactionNameColumnSize) : - transactionName; - ps.setString(index++, transactionName); - ps.setInt(index++, globalTransactionDO.getTimeout()); - ps.setLong(index++, globalTransactionDO.getBeginTime()); - ps.setString(index++, globalTransactionDO.getApplicationData()); - return ps.executeUpdate() > 0; - } catch (SQLException e) { - throw new StoreException(e); - } finally { - IOUtil.close(ps, conn); - } - } - - @Override - public boolean updateGlobalTransactionDO(GlobalTransactionDO globalTransactionDO) { - String sql = LogStoreSqlsFactory.getLogStoreSqls(dbType).getUpdateGlobalTransactionStatusSQL(globalTable); - Connection conn = null; - PreparedStatement ps = null; - try { - int index = 1; - conn = logStoreDataSource.getConnection(); - conn.setAutoCommit(true); - ps = conn.prepareStatement(sql); - ps.setInt(index++, globalTransactionDO.getStatus()); - ps.setString(index++, globalTransactionDO.getXid()); - return ps.executeUpdate() > 0; - } catch (SQLException e) { - throw new StoreException(e); - } finally { - IOUtil.close(ps, conn); - } - } - - @Override - public boolean deleteGlobalTransactionDO(GlobalTransactionDO globalTransactionDO) { - String sql = LogStoreSqlsFactory.getLogStoreSqls(dbType).getDeleteGlobalTransactionSQL(globalTable); - Connection conn = null; - PreparedStatement ps = null; - try { - conn = logStoreDataSource.getConnection(); - conn.setAutoCommit(true); - ps = conn.prepareStatement(sql); - ps.setString(1, globalTransactionDO.getXid()); - ps.executeUpdate(); - } catch (SQLException e) { - throw new StoreException(e); - } finally { - IOUtil.close(ps, conn); - } - return true; - } - - @Override - public List queryBranchTransactionDO(String xid) { - List rets = new ArrayList<>(); - String sql = LogStoreSqlsFactory.getLogStoreSqls(dbType).getQueryBranchTransaction(branchTable); - Connection conn = null; - PreparedStatement ps = null; - ResultSet rs = null; - try { - conn = logStoreDataSource.getConnection(); - conn.setAutoCommit(true); - - ps = conn.prepareStatement(sql); - ps.setString(1, xid); - - rs = ps.executeQuery(); - while (rs.next()) { - rets.add(convertBranchTransactionDO(rs)); - } - return rets; - } catch (SQLException e) { - throw new DataAccessException(e); - } finally { - IOUtil.close(rs, ps, conn); - } - } - - @Override - public List queryBranchTransactionDO(List xids) { - int length = xids.size(); - List rets = new ArrayList<>(length * 3); - String paramsPlaceHolder = org.apache.commons.lang.StringUtils.repeat("?", ",", length); - String sql = LogStoreSqlsFactory.getLogStoreSqls(dbType).getQueryBranchTransaction(branchTable, paramsPlaceHolder); - Connection conn = null; - PreparedStatement ps = null; - ResultSet rs = null; - try { - conn = logStoreDataSource.getConnection(); - conn.setAutoCommit(true); - ps = conn.prepareStatement(sql); - for (int i = 0; i < length; i++) { - ps.setString(i + 1, xids.get(i)); - } - rs = ps.executeQuery(); - while (rs.next()) { - rets.add(convertBranchTransactionDO(rs)); - } - return rets; - } catch (SQLException e) { - throw new DataAccessException(e); - } finally { - IOUtil.close(rs, ps, conn); - } - } - - @Override - public boolean insertBranchTransactionDO(BranchTransactionDO branchTransactionDO) { - String sql = LogStoreSqlsFactory.getLogStoreSqls(dbType).getInsertBranchTransactionSQL(branchTable); - Connection conn = null; - PreparedStatement ps = null; - try { - int index = 1; - conn = logStoreDataSource.getConnection(); - conn.setAutoCommit(true); - ps = conn.prepareStatement(sql); - ps.setString(index++, branchTransactionDO.getXid()); - ps.setLong(index++, branchTransactionDO.getTransactionId()); - ps.setLong(index++, branchTransactionDO.getBranchId()); - ps.setString(index++, branchTransactionDO.getResourceGroupId()); - ps.setString(index++, branchTransactionDO.getResourceId()); - ps.setString(index++, branchTransactionDO.getBranchType()); - ps.setInt(index++, branchTransactionDO.getStatus()); - ps.setString(index++, branchTransactionDO.getClientId()); - ps.setString(index++, branchTransactionDO.getApplicationData()); - return ps.executeUpdate() > 0; - } catch (SQLException e) { - throw new StoreException(e); - } finally { - IOUtil.close(ps, conn); - } - } - - @Override - public boolean updateBranchTransactionDO(BranchTransactionDO branchTransactionDO) { - boolean shouldUpdateAppData = StringUtils.isNotBlank(branchTransactionDO.getApplicationData()); - String sql = shouldUpdateAppData ? - LogStoreSqlsFactory.getLogStoreSqls(dbType).getUpdateBranchTransactionStatusAppDataSQL(branchTable) : - LogStoreSqlsFactory.getLogStoreSqls(dbType).getUpdateBranchTransactionStatusSQL(branchTable); - Connection conn = null; - PreparedStatement ps = null; - try { - int index = 1; - conn = logStoreDataSource.getConnection(); - conn.setAutoCommit(true); - ps = conn.prepareStatement(sql); - ps.setInt(index++, branchTransactionDO.getStatus()); - if (shouldUpdateAppData) { - ps.setString(index++, branchTransactionDO.getApplicationData()); - } - ps.setString(index++, branchTransactionDO.getXid()); - ps.setLong(index++, branchTransactionDO.getBranchId()); - return ps.executeUpdate() > 0; - } catch (SQLException e) { - throw new StoreException(e); - } finally { - IOUtil.close(ps, conn); - } - } - - @Override - public boolean deleteBranchTransactionDO(BranchTransactionDO branchTransactionDO) { - String sql = LogStoreSqlsFactory.getLogStoreSqls(dbType).getDeleteBranchTransactionByBranchIdSQL(branchTable); - Connection conn = null; - PreparedStatement ps = null; - try { - conn = logStoreDataSource.getConnection(); - conn.setAutoCommit(true); - ps = conn.prepareStatement(sql); - ps.setString(1, branchTransactionDO.getXid()); - ps.setLong(2, branchTransactionDO.getBranchId()); - ps.executeUpdate(); - } catch (SQLException e) { - throw new StoreException(e); - } finally { - IOUtil.close(ps, conn); - } - return true; - } - - @Override - public long getCurrentMaxSessionId(long high, long low) { - String transMaxSql = LogStoreSqlsFactory.getLogStoreSqls(dbType).getQueryGlobalMax(globalTable); - String branchMaxSql = LogStoreSqlsFactory.getLogStoreSqls(dbType).getQueryBranchMax(branchTable); - long maxTransId = getCurrentMaxSessionId(transMaxSql, high, low); - long maxBranchId = getCurrentMaxSessionId(branchMaxSql, high, low); - return Math.max(maxBranchId, maxTransId); - } - - private long getCurrentMaxSessionId(String sql, long high, long low) { - long max = 0; - Connection conn = null; - PreparedStatement ps = null; - ResultSet rs = null; - try { - int index = 1; - conn = logStoreDataSource.getConnection(); - conn.setAutoCommit(true); - ps = conn.prepareStatement(sql); - ps.setLong(index++, high); - ps.setLong(index++, low); - - rs = ps.executeQuery(); - while (rs.next()) { - max = rs.getLong(1); - } - } catch (SQLException e) { - throw new DataAccessException(e); - } finally { - IOUtil.close(rs, ps, conn); - } - return max; - } - - private GlobalTransactionDO convertGlobalTransactionDO(ResultSet rs) throws SQLException { - GlobalTransactionDO globalTransactionDO = new GlobalTransactionDO(); - globalTransactionDO.setXid(rs.getString(ServerTableColumnsName.GLOBAL_TABLE_XID)); - globalTransactionDO.setStatus(rs.getInt(ServerTableColumnsName.GLOBAL_TABLE_STATUS)); - globalTransactionDO.setApplicationId(rs.getString(ServerTableColumnsName.GLOBAL_TABLE_APPLICATION_ID)); - globalTransactionDO.setBeginTime(rs.getLong(ServerTableColumnsName.GLOBAL_TABLE_BEGIN_TIME)); - globalTransactionDO.setTimeout(rs.getInt(ServerTableColumnsName.GLOBAL_TABLE_TIMEOUT)); - globalTransactionDO.setTransactionId(rs.getLong(ServerTableColumnsName.GLOBAL_TABLE_TRANSACTION_ID)); - globalTransactionDO.setTransactionName(rs.getString(ServerTableColumnsName.GLOBAL_TABLE_TRANSACTION_NAME)); - globalTransactionDO.setTransactionServiceGroup( - rs.getString(ServerTableColumnsName.GLOBAL_TABLE_TRANSACTION_SERVICE_GROUP)); - globalTransactionDO.setApplicationData(rs.getString(ServerTableColumnsName.GLOBAL_TABLE_APPLICATION_DATA)); - globalTransactionDO.setGmtCreate(rs.getTimestamp(ServerTableColumnsName.GLOBAL_TABLE_GMT_CREATE)); - globalTransactionDO.setGmtModified(rs.getTimestamp(ServerTableColumnsName.GLOBAL_TABLE_GMT_MODIFIED)); - return globalTransactionDO; - } - - private BranchTransactionDO convertBranchTransactionDO(ResultSet rs) throws SQLException { - BranchTransactionDO branchTransactionDO = new BranchTransactionDO(); - branchTransactionDO.setResourceGroupId(rs.getString(ServerTableColumnsName.BRANCH_TABLE_RESOURCE_GROUP_ID)); - branchTransactionDO.setStatus(rs.getInt(ServerTableColumnsName.BRANCH_TABLE_STATUS)); - branchTransactionDO.setApplicationData(rs.getString(ServerTableColumnsName.BRANCH_TABLE_APPLICATION_DATA)); - branchTransactionDO.setClientId(rs.getString(ServerTableColumnsName.BRANCH_TABLE_CLIENT_ID)); - branchTransactionDO.setXid(rs.getString(ServerTableColumnsName.BRANCH_TABLE_XID)); - branchTransactionDO.setResourceId(rs.getString(ServerTableColumnsName.BRANCH_TABLE_RESOURCE_ID)); - branchTransactionDO.setBranchId(rs.getLong(ServerTableColumnsName.BRANCH_TABLE_BRANCH_ID)); - branchTransactionDO.setBranchType(rs.getString(ServerTableColumnsName.BRANCH_TABLE_BRANCH_TYPE)); - branchTransactionDO.setTransactionId(rs.getLong(ServerTableColumnsName.BRANCH_TABLE_TRANSACTION_ID)); - branchTransactionDO.setGmtCreate(rs.getTimestamp(ServerTableColumnsName.BRANCH_TABLE_GMT_CREATE)); - branchTransactionDO.setGmtModified(rs.getTimestamp(ServerTableColumnsName.BRANCH_TABLE_GMT_MODIFIED)); - return branchTransactionDO; - } - - /** - * the public modifier only for test - */ - public void initTransactionNameSize() { - ColumnInfo columnInfo = queryTableStructure(globalTable, TRANSACTION_NAME_KEY); - if (columnInfo == null) { - LOGGER.warn("{} table or {} column not found", globalTable, TRANSACTION_NAME_KEY); - return; - } - this.transactionNameColumnSize = columnInfo.getColumnSize(); - } - - /** - * query column info from table - * - * @param tableName the table name - * @param colName the column name - * @return the column info - */ - private ColumnInfo queryTableStructure(final String tableName, String colName) { - try (Connection conn = logStoreDataSource.getConnection()) { - DatabaseMetaData dbmd = conn.getMetaData(); - String schema = getSchema(conn); - ResultSet tableRs = dbmd.getTables(null, schema, "%", new String[]{"TABLE"}); - while (tableRs.next()) { - String table = tableRs.getString("TABLE_NAME"); - if (StringUtils.equalsIgnoreCase(table, tableName)) { - ResultSet columnRs = conn.getMetaData().getColumns(null, schema, table, null); - while (columnRs.next()) { - ColumnInfo info = new ColumnInfo(); - String columnName = columnRs.getString("COLUMN_NAME"); - info.setColumnName(columnName); - String typeName = columnRs.getString("TYPE_NAME"); - info.setTypeName(typeName); - int columnSize = columnRs.getInt("COLUMN_SIZE"); - info.setColumnSize(columnSize); - String remarks = columnRs.getString("REMARKS"); - info.setRemarks(remarks); - if (StringUtils.equalsIgnoreCase(columnName, colName)) { - return info; - } - } - break; - } - } - } catch (SQLException e) { - LOGGER.error("query transaction_name size fail, {}", e.getMessage(), e); - } - return null; - } - - private String getSchema(Connection conn) throws SQLException { - if ("h2".equalsIgnoreCase(dbType)) { - return null; - } else if ("postgresql".equalsIgnoreCase(dbType)) { - String sql = "select current_schema"; - try (PreparedStatement ps = conn.prepareStatement(sql); - ResultSet rs = ps.executeQuery()) { - String schema = null; - if (rs.next()) { - schema = rs.getString(1); - } - return schema; - } catch (SQLException e) { - throw new StoreException(e); - } - } else { - return conn.getMetaData().getUserName(); - } - } - - /** - * Sets log store data source. - * - * @param logStoreDataSource the log store data source - */ - public void setLogStoreDataSource(DataSource logStoreDataSource) { - this.logStoreDataSource = logStoreDataSource; - } - - /** - * Sets global table. - * - * @param globalTable the global table - */ - public void setGlobalTable(String globalTable) { - this.globalTable = globalTable; - } - - /** - * Sets branch table. - * - * @param branchTable the branch table - */ - public void setBranchTable(String branchTable) { - this.branchTable = branchTable; - } - - /** - * Sets db type. - * - * @param dbType the db type - */ - public void setDbType(String dbType) { - this.dbType = dbType; - } - - public int getTransactionNameColumnSize() { - return transactionNameColumnSize; - } - - /** - * column info - */ - private static class ColumnInfo { - private String columnName; - private String typeName; - private int columnSize; - private String remarks; - - public String getColumnName() { - return columnName; - } - - public void setColumnName(String columnName) { - this.columnName = columnName; - } - - public String getTypeName() { - return typeName; - } - - public void setTypeName(String typeName) { - this.typeName = typeName; - } - - public int getColumnSize() { - return columnSize; - } - - public void setColumnSize(int columnSize) { - this.columnSize = columnSize; - } - - public String getRemarks() { - return remarks; - } - - public void setRemarks(String remarks) { - this.remarks = remarks; - } - } -} diff --git a/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/storage/file/FlushDiskMode.java b/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/storage/file/FlushDiskMode.java deleted file mode 100644 index 9fdb50ee..00000000 --- a/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/storage/file/FlushDiskMode.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright 1999-2019 Seata.io Group. - * - * Licensed 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 io.seata.server.storage.file; - -/** - * @author lizhao - */ -public enum FlushDiskMode { - /** - * sync flush disk - */ - SYNC_MODEL("sync"), - /** - * async flush disk - */ - ASYNC_MODEL("async"); - - private String modeStr; - - FlushDiskMode(String modeStr) { - this.modeStr = modeStr; - } - - public static FlushDiskMode findDiskMode(String modeStr) { - if (SYNC_MODEL.modeStr.equals(modeStr)) { - return SYNC_MODEL; - } - return ASYNC_MODEL; - } -} diff --git a/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/storage/file/ReloadableStore.java b/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/storage/file/ReloadableStore.java deleted file mode 100644 index be45305c..00000000 --- a/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/storage/file/ReloadableStore.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright 1999-2019 Seata.io Group. - * - * Licensed 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 io.seata.server.storage.file; - -import java.util.List; - -/** - * The interface Reloadable store. - * - * @author zhangsen - */ -public interface ReloadableStore { - - /** - * Read write store. - * - * @param readSize the read size - * @param isHistory the is history - * @return the list - */ - List readWriteStore(int readSize, boolean isHistory); - - /** - * Has remaining boolean. - * - * @param isHistory the is history - * @return the boolean - */ - boolean hasRemaining(boolean isHistory); - - -} diff --git a/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/storage/file/TransactionWriteStore.java b/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/storage/file/TransactionWriteStore.java deleted file mode 100644 index d5e4d3e2..00000000 --- a/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/storage/file/TransactionWriteStore.java +++ /dev/null @@ -1,129 +0,0 @@ -/* - * Copyright 1999-2019 Seata.io Group. - * - * Licensed 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 io.seata.server.storage.file; - -import io.seata.common.exception.ShouldNeverHappenException; -import io.seata.server.session.BranchSession; -import io.seata.server.session.GlobalSession; -import io.seata.server.store.SessionStorable; -import io.seata.server.store.TransactionStoreManager.LogOperation; - -import java.nio.ByteBuffer; - -/** - * The type Transaction write store. - * - * @author slievrly - */ -public class TransactionWriteStore implements SessionStorable { - private SessionStorable sessionRequest; - private LogOperation operate; - - /** - * Instantiates a new Transaction write store. - * - * @param sessionRequest the session request - * @param operate the operate - */ - public TransactionWriteStore(SessionStorable sessionRequest, LogOperation operate) { - this.sessionRequest = sessionRequest; - this.operate = operate; - } - - /** - * Instantiates a new Transaction write store. - */ - public TransactionWriteStore() {} - - /** - * Gets session request. - * - * @return the session request - */ - public SessionStorable getSessionRequest() { - return sessionRequest; - } - - /** - * Sets session request. - * - * @param sessionRequest the session request - */ - public void setSessionRequest(SessionStorable sessionRequest) { - this.sessionRequest = sessionRequest; - } - - /** - * Gets operate. - * - * @return the operate - */ - public LogOperation getOperate() { - return operate; - } - - /** - * Sets operate. - * - * @param operate the operate - */ - public void setOperate(LogOperation operate) { - this.operate = operate; - } - - @Override - public byte[] encode() { - byte[] bySessionRequest = this.sessionRequest.encode(); - byte byOpCode = this.getOperate().getCode(); - int len = bySessionRequest.length + 1; - byte[] byResult = new byte[len]; - ByteBuffer byteBuffer = ByteBuffer.wrap(byResult); - byteBuffer.put(bySessionRequest); - byteBuffer.put(byOpCode); - return byResult; - } - - @Override - public void decode(byte[] src) { - ByteBuffer byteBuffer = ByteBuffer.wrap(src); - byte[] bySessionRequest = new byte[src.length - 1]; - byteBuffer.get(bySessionRequest); - byte byOpCode = byteBuffer.get(); - this.operate = LogOperation.getLogOperationByCode(byOpCode); - SessionStorable tmpSessionStorable = getSessionInstanceByOperation(this.operate); - tmpSessionStorable.decode(bySessionRequest); - this.sessionRequest = tmpSessionStorable; - } - - private SessionStorable getSessionInstanceByOperation(LogOperation logOperation) { - SessionStorable sessionStorable = null; - switch (logOperation) { - case GLOBAL_ADD: - case GLOBAL_UPDATE: - case GLOBAL_REMOVE: - sessionStorable = new GlobalSession(); - break; - case BRANCH_ADD: - case BRANCH_UPDATE: - case BRANCH_REMOVE: - sessionStorable = new BranchSession(); - break; - default: - throw new ShouldNeverHappenException("incorrect logOperation"); - } - return sessionStorable; - } -} diff --git a/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/storage/file/lock/FileLockManager.java b/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/storage/file/lock/FileLockManager.java deleted file mode 100644 index 72e897e7..00000000 --- a/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/storage/file/lock/FileLockManager.java +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright 1999-2019 Seata.io Group. - * - * Licensed 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 io.seata.server.storage.file.lock; - -import io.seata.common.loader.LoadLevel; -import io.seata.core.exception.TransactionException; -import io.seata.core.lock.Locker; -import io.seata.server.lock.AbstractLockManager; -import io.seata.server.session.BranchSession; -import io.seata.server.session.GlobalSession; -import org.slf4j.MDC; - -import java.util.List; - -import static io.seata.core.context.RootContext.MDC_KEY_BRANCH_ID; - -/** - * The type file lock manager. - * - * @author zhangsen - */ -@LoadLevel(name = "file") -public class FileLockManager extends AbstractLockManager { - - @Override - public Locker getLocker(BranchSession branchSession) { - return new FileLocker(branchSession); - } - - @Override - public boolean releaseGlobalSessionLock(GlobalSession globalSession) throws TransactionException { - List branchSessions = globalSession.getBranchSessions(); - boolean releaseLockResult = true; - for (BranchSession branchSession : branchSessions) { - try { - MDC.put(MDC_KEY_BRANCH_ID, String.valueOf(branchSession.getBranchId())); - if (!this.releaseLock(branchSession)) { - releaseLockResult = false; - } - } finally { - MDC.remove(MDC_KEY_BRANCH_ID); - } - } - return releaseLockResult; - } - -} diff --git a/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/storage/file/lock/FileLocker.java b/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/storage/file/lock/FileLocker.java deleted file mode 100644 index fe111022..00000000 --- a/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/storage/file/lock/FileLocker.java +++ /dev/null @@ -1,220 +0,0 @@ -/* - * Copyright 1999-2019 Seata.io Group. - * - * Licensed 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 io.seata.server.storage.file.lock; - -import io.seata.common.exception.FrameworkException; -import io.seata.common.exception.StoreException; -import io.seata.common.util.CollectionUtils; -import io.seata.core.exception.BranchTransactionException; -import io.seata.core.exception.TransactionException; -import io.seata.core.lock.AbstractLocker; -import io.seata.core.lock.RowLock; -import io.seata.core.model.LockStatus; -import io.seata.server.session.BranchSession; - -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentMap; - -import static io.seata.core.exception.TransactionExceptionCode.LockKeyConflictFailFast; - -/** - * The type Memory locker. - * - * @author zhangsen - */ -public class FileLocker extends AbstractLocker { - - private static final int BUCKET_PER_TABLE = 128; - - private static final ConcurrentMap>> - LOCK_MAP = new ConcurrentHashMap<>(); - - /** - * The Branch session. - */ - protected BranchSession branchSession; - - /** - * Instantiates a new Memory locker. - * - * @param branchSession the branch session - */ - public FileLocker(BranchSession branchSession) { - this.branchSession = branchSession; - } - - @Override - public boolean acquireLock(List rowLocks) { - return acquireLock(rowLocks, true, false); - } - - @Override - public boolean acquireLock(List rowLocks, boolean autoCommit, boolean skipCheckLock) { - if (CollectionUtils.isEmpty(rowLocks)) { - // no lock - return true; - } - String resourceId = branchSession.getResourceId(); - long transactionId = branchSession.getTransactionId(); - - ConcurrentMap> bucketHolder = branchSession.getLockHolder(); - ConcurrentMap> dbLockMap = CollectionUtils.computeIfAbsent( - LOCK_MAP, resourceId, key -> new ConcurrentHashMap<>()); - boolean failFast = false; - boolean canLock = true; - for (RowLock lock : rowLocks) { - String tableName = lock.getTableName(); - String pk = lock.getPk(); - ConcurrentMap tableLockMap = CollectionUtils.computeIfAbsent(dbLockMap, tableName, - key -> new ConcurrentHashMap<>()); - - int bucketId = pk.hashCode() % BUCKET_PER_TABLE; - BucketLockMap bucketLockMap = CollectionUtils.computeIfAbsent(tableLockMap, bucketId, - key -> new BucketLockMap()); - BranchSession previousLockBranchSession = bucketLockMap.get().putIfAbsent(pk, branchSession); - if (previousLockBranchSession == null) { - // No existing lock, and now locked by myself - Set keysInHolder = CollectionUtils.computeIfAbsent(bucketHolder, bucketLockMap, - key -> ConcurrentHashMap.newKeySet()); - keysInHolder.add(pk); - } else if (previousLockBranchSession.getTransactionId() == transactionId) { - // Locked by me before - continue; - } else { - LOGGER.info("Global lock on [" + tableName + ":" + pk + "] is holding by " + previousLockBranchSession.getBranchId()); - try { - // Release all acquired locks. - branchSession.unlock(); - } catch (TransactionException e) { - throw new FrameworkException(e); - } - if (!autoCommit && previousLockBranchSession.getLockStatus() == LockStatus.Rollbacking) { - failFast = true; - break; - } - if (canLock) { - canLock = false; - if (autoCommit) { - break; - } - } - } - } - if (failFast) { - throw new StoreException(new BranchTransactionException(LockKeyConflictFailFast)); - } - return canLock; - } - - @Override - public boolean releaseLock(List rowLock) { - if (CollectionUtils.isEmpty(rowLock)) { - //no lock - return true; - } - ConcurrentMap> lockHolder = branchSession.getLockHolder(); - if (CollectionUtils.isEmpty(lockHolder)) { - return true; - } - for (Map.Entry> entry : lockHolder.entrySet()) { - BucketLockMap bucket = entry.getKey(); - Set keys = entry.getValue(); - for (String key : keys) { - // remove lock only if it locked by myself - bucket.get().remove(key, branchSession); - } - } - lockHolder.clear(); - return true; - } - - @Override - public boolean isLockable(List rowLocks) { - if (CollectionUtils.isEmpty(rowLocks)) { - //no lock - return true; - } - Long transactionId = rowLocks.get(0).getTransactionId(); - String resourceId = rowLocks.get(0).getResourceId(); - ConcurrentMap> dbLockMap = LOCK_MAP.get(resourceId); - if (dbLockMap == null) { - return true; - } - for (RowLock rowLock : rowLocks) { - String tableName = rowLock.getTableName(); - String pk = rowLock.getPk(); - - ConcurrentMap tableLockMap = dbLockMap.get(tableName); - if (tableLockMap == null) { - continue; - } - int bucketId = pk.hashCode() % BUCKET_PER_TABLE; - BucketLockMap bucketLockMap = tableLockMap.get(bucketId); - if (bucketLockMap == null) { - continue; - } - BranchSession branchSession = bucketLockMap.get().get(pk); - Long lockingTransactionId = branchSession != null ? branchSession.getTransactionId() : null; - if (lockingTransactionId == null || lockingTransactionId.longValue() == transactionId) { - // Locked by me - continue; - } else { - LOGGER.info("Global lock on [" + tableName + ":" + pk + "] is holding by " + lockingTransactionId); - return false; - } - } - return true; - } - - - @Override - public void updateLockStatus(String xid, LockStatus lockStatus) { - } - - @Override - public void cleanAllLocks() { - LOCK_MAP.clear(); - } - - /** - * Because bucket lock map will be key of HashMap(lockHolder), however {@link ConcurrentHashMap} overwrites - * {@link Object#hashCode()} and {@link Object#equals(Object)}, that leads to hash key conflict in lockHolder. - * We define a {@link BucketLockMap} to hold the ConcurrentHashMap(bucketLockMap) and replace it as key of - * HashMap(lockHolder). - */ - public static class BucketLockMap { - private final ConcurrentHashMap bucketLockMap - = new ConcurrentHashMap<>(); - - ConcurrentHashMap get() { - return bucketLockMap; - } - - @Override - public int hashCode() { - return super.hashCode(); - } - - @Override - public boolean equals(Object o) { - return super.equals(o); - } - } -} diff --git a/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/storage/file/session/FileSessionManager.java b/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/storage/file/session/FileSessionManager.java deleted file mode 100644 index 9eeca2f3..00000000 --- a/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/storage/file/session/FileSessionManager.java +++ /dev/null @@ -1,370 +0,0 @@ -/* - * Copyright 1999-2019 Seata.io Group. - * - * Licensed 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 io.seata.server.storage.file.session; - -import io.seata.common.exception.ShouldNeverHappenException; -import io.seata.common.loader.LoadLevel; -import io.seata.common.loader.Scope; -import io.seata.common.util.CollectionUtils; -import io.seata.common.util.StringUtils; -import io.seata.config.ConfigurationFactory; -import io.seata.core.constants.ConfigurationKeys; -import io.seata.core.exception.TransactionException; -import io.seata.core.model.GlobalStatus; -import io.seata.server.session.*; -import io.seata.server.storage.file.ReloadableStore; -import io.seata.server.storage.file.TransactionWriteStore; -import io.seata.server.storage.file.store.FileTransactionStoreManager; -import io.seata.server.store.AbstractTransactionStoreManager; -import io.seata.server.store.SessionStorable; -import io.seata.server.store.TransactionStoreManager; - -import java.io.File; -import java.io.IOException; -import java.util.*; -import java.util.concurrent.ConcurrentHashMap; - -import static io.seata.common.DefaultValues.DEFAULT_SERVICE_SESSION_RELOAD_READ_SIZE; - - -/** - * The type File based session manager. - * - * @author slievrly - */ -@LoadLevel(name = "file", scope = Scope.PROTOTYPE) -public class FileSessionManager extends AbstractSessionManager implements Reloadable { - - private static final int READ_SIZE = ConfigurationFactory.getInstance().getInt( - ConfigurationKeys.SERVICE_SESSION_RELOAD_READ_SIZE, DEFAULT_SERVICE_SESSION_RELOAD_READ_SIZE); - /** - * The Session map. - */ - private Map sessionMap = new ConcurrentHashMap<>(); - - /** - * Instantiates a new File based session manager. - * - * @param name the name - * @param sessionStoreFilePath the session store file path - * @throws IOException the io exception - */ - public FileSessionManager(String name, String sessionStoreFilePath) throws IOException { - super(name); - if (StringUtils.isNotBlank(sessionStoreFilePath)) { - transactionStoreManager = new FileTransactionStoreManager( - sessionStoreFilePath + File.separator + name, this); - } else { - transactionStoreManager = new AbstractTransactionStoreManager() { - @Override - public boolean writeSession(LogOperation logOperation, SessionStorable session) { - return true; - } - }; - } - } - - @Override - public void reload() { - restoreSessions(); - } - - @Override - public void addGlobalSession(GlobalSession session) throws TransactionException { - CollectionUtils.computeIfAbsent(sessionMap, session.getXid(), k -> { - try { - super.addGlobalSession(session); - } catch (TransactionException e) { - LOGGER.error("addGlobalSession fail, msg: {}", e.getMessage()); - } - return session; - }); - } - - @Override - public GlobalSession findGlobalSession(String xid) { - return sessionMap.get(xid); - } - - @Override - public GlobalSession findGlobalSession(String xid, boolean withBranchSessions) { - // withBranchSessions without process in memory - return sessionMap.get(xid); - } - - @Override - public void removeGlobalSession(GlobalSession session) throws TransactionException { - if (sessionMap.remove(session.getXid()) != null) { - super.removeGlobalSession(session); - } - } - - @Override - public Collection allSessions() { - return sessionMap.values(); - } - - @Override - public List findGlobalSessions(SessionCondition condition) { - List found = new ArrayList<>(); - - List globalStatuses = null; - if (null != condition.getStatuses() && condition.getStatuses().length > 0) { - globalStatuses = Arrays.asList(condition.getStatuses()); - } - for (GlobalSession globalSession : sessionMap.values()) { - if (null != condition.getOverTimeAliveMills() && condition.getOverTimeAliveMills() > 0) { - if (System.currentTimeMillis() - globalSession.getBeginTime() <= condition.getOverTimeAliveMills()) { - continue; - } - } - - if (!StringUtils.isEmpty(condition.getXid())) { - if (Objects.equals(condition.getXid(), globalSession.getXid())) { - // Only one will be found, just add and return - found.add(globalSession); - return found; - } else { - continue; - } - } - - if (null != condition.getTransactionId() && condition.getTransactionId() > 0) { - if (Objects.equals(condition.getTransactionId(), globalSession.getTransactionId())) { - // Only one will be found, just add and return - found.add(globalSession); - return found; - } else { - continue; - } - } - - if (null != globalStatuses) { - if (!globalStatuses.contains(globalSession.getStatus())) { - continue; - } - } - - // All test pass, add to resp - found.add(globalSession); - } - return found; - } - - @Override - public T lockAndExecute(GlobalSession globalSession, GlobalSession.LockCallable lockCallable) - throws TransactionException { - globalSession.lock(); - try { - return lockCallable.call(); - } finally { - globalSession.unlock(); - } - } - - private void restoreSessions() { - final Set removedGlobalBuffer = new HashSet<>(); - final Map> unhandledBranchBuffer = new HashMap<>(); - - restoreSessions(true, removedGlobalBuffer, unhandledBranchBuffer); - restoreSessions(false, removedGlobalBuffer, unhandledBranchBuffer); - - if (!unhandledBranchBuffer.isEmpty()) { - unhandledBranchBuffer.values().forEach(unhandledBranchSessions -> { - unhandledBranchSessions.values().forEach(branchSession -> { - String xid = branchSession.getXid(); - if (removedGlobalBuffer.contains(xid)) { - return; - } - - long bid = branchSession.getBranchId(); - GlobalSession found = sessionMap.get(xid); - if (found == null) { - // Ignore - if (LOGGER.isInfoEnabled()) { - LOGGER.info("GlobalSession Does Not Exists For BranchSession [" + bid + "/" + xid + "]"); - } - } else { - BranchSession existingBranch = found.getBranch(branchSession.getBranchId()); - if (existingBranch == null) { - found.add(branchSession); - } else { - existingBranch.setStatus(branchSession.getStatus()); - } - } - }); - }); - } - } - - private boolean checkSessionStatus(GlobalSession globalSession) { - GlobalStatus globalStatus = globalSession.getStatus(); - switch (globalStatus) { - case UnKnown: - case Committed: - case CommitFailed: - case Rollbacked: - case RollbackFailed: - case TimeoutRollbacked: - case TimeoutRollbackFailed: - case RollbackRetryTimeout: - case Finished: - return false; - default: - return true; - } - } - - private void restoreSessions(boolean isHistory, Set removedGlobalBuffer, Map> unhandledBranchBuffer) { - if (!(transactionStoreManager instanceof ReloadableStore)) { - return; - } - while (((ReloadableStore)transactionStoreManager).hasRemaining(isHistory)) { - List stores = ((ReloadableStore)transactionStoreManager).readWriteStore(READ_SIZE, - isHistory); - restore(stores, removedGlobalBuffer, unhandledBranchBuffer); - } - } - - private void restore(List stores, Set removedGlobalBuffer, - Map> unhandledBranchBuffer) { - for (TransactionWriteStore store : stores) { - TransactionStoreManager.LogOperation logOperation = store.getOperate(); - SessionStorable sessionStorable = store.getSessionRequest(); - switch (logOperation) { - case GLOBAL_ADD: - case GLOBAL_UPDATE: { - GlobalSession globalSession = (GlobalSession)sessionStorable; - if (globalSession.getTransactionId() == 0) { - LOGGER.error( - "Restore globalSession from file failed, the transactionId is zero , xid:" + globalSession - .getXid()); - break; - } - if (removedGlobalBuffer.contains(globalSession.getXid())) { - break; - } - GlobalSession foundGlobalSession = sessionMap.get(globalSession.getXid()); - if (foundGlobalSession == null) { - if (this.checkSessionStatus(globalSession)) { - sessionMap.put(globalSession.getXid(), globalSession); - } else { - removedGlobalBuffer.add(globalSession.getXid()); - unhandledBranchBuffer.remove(globalSession.getXid()); - } - } else { - if (this.checkSessionStatus(globalSession)) { - foundGlobalSession.setStatus(globalSession.getStatus()); - } else { - sessionMap.remove(globalSession.getXid()); - removedGlobalBuffer.add(globalSession.getXid()); - unhandledBranchBuffer.remove(globalSession.getXid()); - } - } - break; - } - case GLOBAL_REMOVE: { - GlobalSession globalSession = (GlobalSession)sessionStorable; - if (globalSession.getTransactionId() == 0) { - LOGGER.error( - "Restore globalSession from file failed, the transactionId is zero , xid:" + globalSession - .getXid()); - break; - } - if (removedGlobalBuffer.contains(globalSession.getXid())) { - break; - } - if (sessionMap.remove(globalSession.getXid()) == null) { - if (LOGGER.isInfoEnabled()) { - LOGGER.info("GlobalSession To Be Removed Does Not Exists [" + globalSession.getXid() + "]"); - } - } - removedGlobalBuffer.add(globalSession.getXid()); - unhandledBranchBuffer.remove(globalSession.getXid()); - break; - } - case BRANCH_ADD: - case BRANCH_UPDATE: { - BranchSession branchSession = (BranchSession)sessionStorable; - if (branchSession.getTransactionId() == 0) { - LOGGER.error( - "Restore branchSession from file failed, the transactionId is zero , xid:" + branchSession - .getXid()); - break; - } - if (removedGlobalBuffer.contains(branchSession.getXid())) { - break; - } - GlobalSession foundGlobalSession = sessionMap.get(branchSession.getXid()); - if (foundGlobalSession == null) { - unhandledBranchBuffer.computeIfAbsent(branchSession.getXid(), key -> new HashMap<>()) - .put(branchSession.getBranchId(), branchSession); - } else { - BranchSession existingBranch = foundGlobalSession.getBranch(branchSession.getBranchId()); - if (existingBranch == null) { - foundGlobalSession.add(branchSession); - } else { - existingBranch.setStatus(branchSession.getStatus()); - } - } - break; - } - case BRANCH_REMOVE: { - BranchSession branchSession = (BranchSession)sessionStorable; - String xid = branchSession.getXid(); - if (removedGlobalBuffer.contains(xid)) { - break; - } - long bid = branchSession.getBranchId(); - if (branchSession.getTransactionId() == 0) { - LOGGER.error( - "Restore branchSession from file failed, the transactionId is zero , xid:" + branchSession - .getXid()); - break; - } - GlobalSession found = sessionMap.get(xid); - if (found == null) { - if (LOGGER.isInfoEnabled()) { - LOGGER.info( - "GlobalSession To Be Updated (Remove Branch) Does Not Exists [" + bid + "/" + xid - + "]"); - } - } else { - BranchSession theBranch = found.getBranch(bid); - if (theBranch == null) { - if (LOGGER.isInfoEnabled()) { - LOGGER.info("BranchSession To Be Updated Does Not Exists [" + bid + "/" + xid + "]"); - } - } else { - found.remove(theBranch); - } - } - break; - } - default: - throw new ShouldNeverHappenException("Unknown Operation: " + logOperation); - } - } - - } - - @Override - public void destroy() { - transactionStoreManager.shutdown(); - } - -} diff --git a/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/storage/file/store/FileTransactionStoreManager.java b/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/storage/file/store/FileTransactionStoreManager.java deleted file mode 100644 index 6b3c1c77..00000000 --- a/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/storage/file/store/FileTransactionStoreManager.java +++ /dev/null @@ -1,651 +0,0 @@ -/* - * Copyright 1999-2019 Seata.io Group. - * - * Licensed 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 io.seata.server.storage.file.store; - -import io.seata.common.exception.StoreException; -import io.seata.common.thread.NamedThreadFactory; -import io.seata.common.util.CollectionUtils; -import io.seata.server.session.BranchSession; -import io.seata.server.session.GlobalSession; -import io.seata.server.session.SessionCondition; -import io.seata.server.session.SessionManager; -import io.seata.server.storage.file.FlushDiskMode; -import io.seata.server.storage.file.ReloadableStore; -import io.seata.server.storage.file.TransactionWriteStore; -import io.seata.server.store.AbstractTransactionStoreManager; -import io.seata.server.store.SessionStorable; -import io.seata.server.store.StoreConfig; -import io.seata.server.store.TransactionStoreManager; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.slf4j.MDC; - -import java.io.File; -import java.io.IOException; -import java.io.RandomAccessFile; -import java.nio.ByteBuffer; -import java.nio.channels.FileChannel; -import java.nio.file.Files; -import java.nio.file.StandardCopyOption; -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.*; -import java.util.concurrent.atomic.AtomicLong; -import java.util.concurrent.locks.ReentrantLock; - -import static io.seata.core.context.RootContext.MDC_KEY_BRANCH_ID; - -/** - * The type File transaction store manager. - * - * @author slievrly - */ -public class FileTransactionStoreManager extends AbstractTransactionStoreManager - implements TransactionStoreManager, ReloadableStore { - private static final Logger LOGGER = LoggerFactory.getLogger(FileTransactionStoreManager.class); - - private static final int MAX_THREAD_WRITE = 1; - - private ExecutorService fileWriteExecutor; - - private volatile boolean stopping = false; - - private static final int MAX_SHUTDOWN_RETRY = 3; - - private static final int SHUTDOWN_CHECK_INTERVAL = 1 * 1000; - - private static final int MAX_WRITE_RETRY = 5; - - private static final String HIS_DATA_FILENAME_POSTFIX = ".1"; - - private static final AtomicLong FILE_TRX_NUM = new AtomicLong(0); - - private static final AtomicLong FILE_FLUSH_NUM = new AtomicLong(0); - - private static final int MARK_SIZE = 4; - - private static final int MAX_WAIT_TIME_MILLS = 2 * 1000; - - private static final int MAX_FLUSH_TIME_MILLS = 2 * 1000; - - private static final int MAX_FLUSH_NUM = 10; - - private static final int PER_FILE_BLOCK_SIZE = 65535 * 8; - - private static final long MAX_TRX_TIMEOUT_MILLS = 30 * 60 * 1000; - - private static volatile long trxStartTimeMills = System.currentTimeMillis(); - - private File currDataFile; - - private RandomAccessFile currRaf; - - private FileChannel currFileChannel; - - private long recoverCurrOffset = 0; - - private long recoverHisOffset = 0; - - private SessionManager sessionManager; - - private String currFullFileName; - - private String hisFullFileName; - - private WriteDataFileRunnable writeDataFileRunnable; - - private ReentrantLock writeSessionLock = new ReentrantLock(); - - private volatile long lastModifiedTime; - - private static final int MAX_WRITE_BUFFER_SIZE = StoreConfig.getFileWriteBufferCacheSize(); - - private final ByteBuffer writeBuffer = ByteBuffer.allocateDirect(MAX_WRITE_BUFFER_SIZE); - - private static final FlushDiskMode FLUSH_DISK_MODE = StoreConfig.getFlushDiskMode(); - - private static final int MAX_WAIT_FOR_FLUSH_TIME_MILLS = 2 * 1000; - - private static final int MAX_WAIT_FOR_CLOSE_TIME_MILLS = 2 * 1000; - - private static final int INT_BYTE_SIZE = 4; - - /** - * Instantiates a new File transaction store manager. - * - * @param fullFileName the dir path - * @param sessionManager the session manager - * @throws IOException the io exception - */ - public FileTransactionStoreManager(String fullFileName, SessionManager sessionManager) throws IOException { - initFile(fullFileName); - fileWriteExecutor = new ThreadPoolExecutor(MAX_THREAD_WRITE, MAX_THREAD_WRITE, Integer.MAX_VALUE, - TimeUnit.MILLISECONDS, new LinkedBlockingQueue(), - new NamedThreadFactory("fileTransactionStore", MAX_THREAD_WRITE, true)); - writeDataFileRunnable = new WriteDataFileRunnable(); - fileWriteExecutor.submit(writeDataFileRunnable); - this.sessionManager = sessionManager; - } - - private void initFile(String fullFileName) throws IOException { - this.currFullFileName = fullFileName; - this.hisFullFileName = fullFileName + HIS_DATA_FILENAME_POSTFIX; - try { - currDataFile = new File(currFullFileName); - if (!currDataFile.exists()) { - // create parent dir first - if (currDataFile.getParentFile() != null && !currDataFile.getParentFile().exists()) { - currDataFile.getParentFile().mkdirs(); - } - currDataFile.createNewFile(); - trxStartTimeMills = System.currentTimeMillis(); - } else { - trxStartTimeMills = currDataFile.lastModified(); - } - lastModifiedTime = System.currentTimeMillis(); - currRaf = new RandomAccessFile(currDataFile, "rw"); - currRaf.seek(currDataFile.length()); - currFileChannel = currRaf.getChannel(); - } catch (IOException exx) { - LOGGER.error("init file error,{}", exx.getMessage(), exx); - throw exx; - } - } - - @Override - public boolean writeSession(LogOperation logOperation, SessionStorable session) { - long curFileTrxNum; - writeSessionLock.lock(); - try { - if (!writeDataFile(new TransactionWriteStore(session, logOperation).encode())) { - return false; - } - lastModifiedTime = System.currentTimeMillis(); - curFileTrxNum = FILE_TRX_NUM.incrementAndGet(); - if (curFileTrxNum % PER_FILE_BLOCK_SIZE == 0 - && (System.currentTimeMillis() - trxStartTimeMills) > MAX_TRX_TIMEOUT_MILLS) { - return saveHistory(); - } - } catch (Exception exx) { - LOGGER.error("writeSession error, {}", exx.getMessage(), exx); - return false; - } finally { - writeSessionLock.unlock(); - } - flushDisk(curFileTrxNum, currFileChannel); - return true; - } - - private void flushDisk(long curFileNum, FileChannel currFileChannel) { - - if (FLUSH_DISK_MODE == FlushDiskMode.SYNC_MODEL) { - SyncFlushRequest syncFlushRequest = new SyncFlushRequest(curFileNum, currFileChannel); - writeDataFileRunnable.putRequest(syncFlushRequest); - syncFlushRequest.waitForFlush(MAX_WAIT_FOR_FLUSH_TIME_MILLS); - } else { - writeDataFileRunnable.putRequest(new AsyncFlushRequest(curFileNum, currFileChannel)); - } - } - - /** - * get all overTimeSessionStorables - * merge write file - * - * @throws IOException - */ - private boolean saveHistory() throws IOException { - boolean result; - try { - result = findTimeoutAndSave(); - CloseFileRequest request = new CloseFileRequest(currFileChannel, currRaf); - writeDataFileRunnable.putRequest(request); - request.waitForClose(MAX_WAIT_FOR_CLOSE_TIME_MILLS); - Files.move(currDataFile.toPath(), new File(hisFullFileName).toPath(), StandardCopyOption.REPLACE_EXISTING); - } catch (IOException exx) { - LOGGER.error("save history data file error, {}", exx.getMessage(), exx); - result = false; - } finally { - initFile(currFullFileName); - } - return result; - } - - private boolean writeDataFrame(byte[] data) { - if (data == null || data.length <= 0) { - return true; - } - int dataLength = data.length; - int bufferRemainingSize = writeBuffer.remaining(); - if (bufferRemainingSize <= INT_BYTE_SIZE) { - if (!flushWriteBuffer(writeBuffer)) { - return false; - } - } - bufferRemainingSize = writeBuffer.remaining(); - if (bufferRemainingSize <= INT_BYTE_SIZE) { - throw new IllegalStateException( - String.format("Write buffer remaining size %d was too small", bufferRemainingSize)); - } - writeBuffer.putInt(dataLength); - bufferRemainingSize = writeBuffer.remaining(); - int dataPos = 0; - while (dataPos < dataLength) { - int dataLengthToWrite = dataLength - dataPos; - dataLengthToWrite = Math.min(dataLengthToWrite, bufferRemainingSize); - writeBuffer.put(data, dataPos, dataLengthToWrite); - bufferRemainingSize = writeBuffer.remaining(); - if (bufferRemainingSize == 0) { - if (!flushWriteBuffer(writeBuffer)) { - return false; - } - bufferRemainingSize = writeBuffer.remaining(); - } - dataPos += dataLengthToWrite; - } - return true; - } - - private boolean flushWriteBuffer(ByteBuffer writeBuffer) { - writeBuffer.flip(); - if (!writeDataFileByBuffer(writeBuffer)) { - return false; - } - writeBuffer.clear(); - return true; - } - - private boolean findTimeoutAndSave() throws IOException { - List globalSessionsOverMaxTimeout = sessionManager.findGlobalSessions( - new SessionCondition(MAX_TRX_TIMEOUT_MILLS)); - if (CollectionUtils.isEmpty(globalSessionsOverMaxTimeout)) { - return true; - } - for (GlobalSession globalSession : globalSessionsOverMaxTimeout) { - TransactionWriteStore globalWriteStore = new TransactionWriteStore(globalSession, LogOperation.GLOBAL_ADD); - byte[] data = globalWriteStore.encode(); - if (!writeDataFrame(data)) { - return false; - } - List branchSessIonsOverMaXTimeout = globalSession.getSortedBranches(); - if (branchSessIonsOverMaXTimeout != null) { - for (BranchSession branchSession : branchSessIonsOverMaXTimeout) { - try { - MDC.put(MDC_KEY_BRANCH_ID, String.valueOf(branchSession.getBranchId())); - TransactionWriteStore branchWriteStore = new TransactionWriteStore(branchSession, - LogOperation.BRANCH_ADD); - data = branchWriteStore.encode(); - if (!writeDataFrame(data)) { - return false; - } - } finally { - MDC.remove(MDC_KEY_BRANCH_ID); - } - } - } - } - if (flushWriteBuffer(writeBuffer)) { - currFileChannel.force(false); - return true; - } - return false; - } - - @Override - public GlobalSession readSession(String xid) { - throw new StoreException("unsupport for read from file, xid:" + xid); - } - - @Override - public List readSession(SessionCondition sessionCondition) { - throw new StoreException("unsupport for read from file"); - } - - @Override - public void shutdown() { - if (fileWriteExecutor != null) { - fileWriteExecutor.shutdown(); - stopping = true; - int retry = 0; - while (!fileWriteExecutor.isTerminated() && retry < MAX_SHUTDOWN_RETRY) { - ++retry; - try { - Thread.sleep(SHUTDOWN_CHECK_INTERVAL); - } catch (InterruptedException ignore) { - } - } - if (retry >= MAX_SHUTDOWN_RETRY) { - fileWriteExecutor.shutdownNow(); - } - } - try { - if (currFileChannel.isOpen()) { - currFileChannel.force(true); - } - } catch (IOException e) { - LOGGER.error("fileChannel force error: {}", e.getMessage(), e); - } - closeFile(currRaf); - } - - @Override - public List readWriteStore(int readSize, boolean isHistory) { - File file = null; - long currentOffset = 0; - if (isHistory) { - file = new File(hisFullFileName); - currentOffset = recoverHisOffset; - } else { - file = new File(currFullFileName); - currentOffset = recoverCurrOffset; - } - if (file.exists()) { - return parseDataFile(file, readSize, currentOffset, isHistory); - } - return null; - } - - @Override - public boolean hasRemaining(boolean isHistory) { - File file; - RandomAccessFile raf = null; - long currentOffset; - if (isHistory) { - file = new File(hisFullFileName); - currentOffset = recoverHisOffset; - } else { - file = new File(currFullFileName); - currentOffset = recoverCurrOffset; - } - try { - raf = new RandomAccessFile(file, "r"); - return currentOffset < raf.length(); - - } catch (IOException ignore) { - } finally { - closeFile(raf); - } - return false; - } - - private List parseDataFile(File file, int readSize, long currentOffset, boolean isHistory) { - List transactionWriteStores = new ArrayList<>(readSize); - RandomAccessFile raf = null; - FileChannel fileChannel = null; - try { - raf = new RandomAccessFile(file, "r"); - raf.seek(currentOffset); - fileChannel = raf.getChannel(); - fileChannel.position(currentOffset); - long size = raf.length(); - ByteBuffer buffSize = ByteBuffer.allocate(MARK_SIZE); - while (fileChannel.position() < size) { - try { - buffSize.clear(); - int avilReadSize = fileChannel.read(buffSize); - if (avilReadSize != MARK_SIZE) { - break; - } - buffSize.flip(); - int bodySize = buffSize.getInt(); - byte[] byBody = new byte[bodySize]; - ByteBuffer buffBody = ByteBuffer.wrap(byBody); - avilReadSize = fileChannel.read(buffBody); - if (avilReadSize != bodySize) { - break; - } - TransactionWriteStore writeStore = new TransactionWriteStore(); - writeStore.decode(byBody); - transactionWriteStores.add(writeStore); - if (transactionWriteStores.size() == readSize) { - break; - } - } catch (Exception ex) { - LOGGER.error("decode data file error:{}", ex.getMessage(), ex); - break; - } - } - return transactionWriteStores; - } catch (IOException exx) { - LOGGER.error("parse data file error:{},file:{}", exx.getMessage(), file.getName(), exx); - return null; - } finally { - try { - if (fileChannel != null) { - if (isHistory) { - recoverHisOffset = fileChannel.position(); - } else { - recoverCurrOffset = fileChannel.position(); - } - } - closeFile(raf); - } catch (IOException exx) { - LOGGER.error("file close error{}", exx.getMessage(), exx); - } - } - } - - private void closeFile(RandomAccessFile raf) { - try { - if (raf != null) { - raf.close(); - raf = null; - } - } catch (IOException exx) { - LOGGER.error("file close error,{}", exx.getMessage(), exx); - } - } - - private boolean writeDataFile(byte[] bs) { - if (bs == null || bs.length >= Integer.MAX_VALUE - 3) { - return false; - } - if (!writeDataFrame(bs)) { - return false; - } - return flushWriteBuffer(writeBuffer); - } - - private boolean writeDataFileByBuffer(ByteBuffer byteBuffer) { - for (int retry = 0; retry < MAX_WRITE_RETRY; retry++) { - try { - while (byteBuffer.hasRemaining()) { - currFileChannel.write(byteBuffer); - } - return true; - } catch (Exception exx) { - LOGGER.error("write data file error:{}", exx.getMessage(), exx); - } - } - LOGGER.error("write dataFile failed,retry more than :{}", MAX_WRITE_RETRY); - return false; - } - - interface StoreRequest { - - } - - abstract static class AbstractFlushRequest implements StoreRequest { - private final long curFileTrxNum; - - private final FileChannel curFileChannel; - - protected AbstractFlushRequest(long curFileTrxNum, FileChannel curFileChannel) { - this.curFileTrxNum = curFileTrxNum; - this.curFileChannel = curFileChannel; - } - - public long getCurFileTrxNum() { - return curFileTrxNum; - } - - public FileChannel getCurFileChannel() { - return curFileChannel; - } - } - - class SyncFlushRequest extends AbstractFlushRequest { - - private final CountDownLatch countDownLatch = new CountDownLatch(1); - - public SyncFlushRequest(long curFileTrxNum, FileChannel curFileChannel) { - super(curFileTrxNum, curFileChannel); - } - - public void wakeup() { - this.countDownLatch.countDown(); - } - - public void waitForFlush(long timeout) { - try { - this.countDownLatch.await(timeout, TimeUnit.MILLISECONDS); - } catch (InterruptedException e) { - LOGGER.error("Interrupted", e); - } - } - } - - class AsyncFlushRequest extends AbstractFlushRequest { - - public AsyncFlushRequest(long curFileTrxNum, FileChannel curFileChannel) { - super(curFileTrxNum, curFileChannel); - } - - } - - static class CloseFileRequest implements StoreRequest { - private final CountDownLatch countDownLatch = new CountDownLatch(1); - private FileChannel fileChannel; - - private RandomAccessFile file; - - public CloseFileRequest(FileChannel fileChannel, RandomAccessFile file) { - this.fileChannel = fileChannel; - this.file = file; - } - - public FileChannel getFileChannel() { - return fileChannel; - } - - public RandomAccessFile getFile() { - return file; - } - - public void wakeup() { - this.countDownLatch.countDown(); - } - - public void waitForClose(long timeout) { - try { - this.countDownLatch.await(timeout, TimeUnit.MILLISECONDS); - } catch (InterruptedException e) { - LOGGER.error("Interrupted", e); - } - } - } - - /** - * The type Write data file runnable. - */ - class WriteDataFileRunnable implements Runnable { - - private LinkedBlockingQueue storeRequests = new LinkedBlockingQueue<>(); - - public void putRequest(final StoreRequest request) { - storeRequests.add(request); - } - - @Override - public void run() { - while (!stopping) { - try { - StoreRequest storeRequest = storeRequests.poll(MAX_WAIT_TIME_MILLS, TimeUnit.MILLISECONDS); - handleStoreRequest(storeRequest); - } catch (Exception exx) { - LOGGER.error("write file error: {}", exx.getMessage(), exx); - } - } - handleRestRequest(); - } - - /** - * handle the rest requests when stopping is true - */ - private void handleRestRequest() { - int remainNums = storeRequests.size(); - for (int i = 0; i < remainNums; i++) { - handleStoreRequest(storeRequests.poll()); - } - } - - private void handleStoreRequest(StoreRequest storeRequest) { - if (storeRequest == null) { - flushOnCondition(currFileChannel); - } - if (storeRequest instanceof SyncFlushRequest) { - syncFlush((SyncFlushRequest)storeRequest); - } else if (storeRequest instanceof AsyncFlushRequest) { - async((AsyncFlushRequest)storeRequest); - } else if (storeRequest instanceof CloseFileRequest) { - closeAndFlush((CloseFileRequest)storeRequest); - } - } - - private void closeAndFlush(CloseFileRequest req) { - long diff = FILE_TRX_NUM.get() - FILE_FLUSH_NUM.get(); - flush(req.getFileChannel()); - FILE_FLUSH_NUM.addAndGet(diff); - closeFile(req.getFile()); - req.wakeup(); - } - - private void async(AsyncFlushRequest req) { - flushOnCondition(req.getCurFileChannel()); - } - - private void syncFlush(SyncFlushRequest req) { - if (req.getCurFileTrxNum() > FILE_FLUSH_NUM.get()) { - long diff = FILE_TRX_NUM.get() - FILE_FLUSH_NUM.get(); - flush(req.getCurFileChannel()); - FILE_FLUSH_NUM.addAndGet(diff); - } - // notify - req.wakeup(); - } - - private void flushOnCondition(FileChannel fileChannel) { - if (FLUSH_DISK_MODE == FlushDiskMode.SYNC_MODEL) { - return; - } - long diff = FILE_TRX_NUM.get() - FILE_FLUSH_NUM.get(); - if (diff == 0) { - return; - } - if (diff % MAX_FLUSH_NUM == 0 || System.currentTimeMillis() - lastModifiedTime > MAX_FLUSH_TIME_MILLS) { - flush(fileChannel); - FILE_FLUSH_NUM.addAndGet(diff); - } - } - - private void flush(FileChannel fileChannel) { - try { - fileChannel.force(false); - } catch (IOException exx) { - LOGGER.error("flush error: {}", exx.getMessage(), exx); - } - } - } -} diff --git a/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/storage/redis/JedisPooledFactory.java b/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/storage/redis/JedisPooledFactory.java deleted file mode 100644 index 6c32b7e9..00000000 --- a/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/storage/redis/JedisPooledFactory.java +++ /dev/null @@ -1,125 +0,0 @@ -/* - * Copyright 1999-2019 Seata.io Group. - * - * Licensed 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 io.seata.server.storage.redis; - -import io.seata.common.exception.RedisException; -import io.seata.common.util.ConfigTools; -import io.seata.common.util.StringUtils; -import io.seata.config.Configuration; -import io.seata.config.ConfigurationFactory; -import io.seata.core.constants.ConfigurationKeys; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import redis.clients.jedis.*; - -import java.util.Arrays; -import java.util.HashSet; -import java.util.Set; - -import static io.seata.common.DefaultValues.*; - -/** - * @author funkye - */ -public class JedisPooledFactory { - /** - * The constant LOGGER. - */ - protected static final Logger LOGGER = LoggerFactory.getLogger(JedisPooledFactory.class); - - private static volatile JedisPoolAbstract jedisPool = null; - - private static final String HOST = "127.0.0.1"; - - private static final int PORT = 6379; - private static final int DATABASE = 0; - - private static final int SENTINEL_HOST_NUMBER = 3; - - private static final Configuration CONFIGURATION = ConfigurationFactory.getInstance(); - - /** - * get the RedisPool instance (singleton) - * - * @return redisPool - */ - public static JedisPoolAbstract getJedisPoolInstance(JedisPoolAbstract... jedisPools) { - if (jedisPool == null) { - synchronized (JedisPooledFactory.class) { - if (jedisPool == null) { - JedisPoolAbstract tempJedisPool = null; - if (jedisPools != null && jedisPools.length > 0) { - tempJedisPool = jedisPools[0]; - } else { - String password = CONFIGURATION.getConfig(ConfigurationKeys.STORE_REDIS_PASSWORD); - if (StringUtils.isBlank(password)) { - password = null; - } else { - String publicKey = CONFIGURATION.getConfig(ConfigurationKeys.STORE_PUBLIC_KEY); - if (StringUtils.isNotBlank(publicKey)) { - try { - password = ConfigTools.publicDecrypt(password, publicKey); - } catch (Exception e) { - LOGGER.error("decryption failed,please confirm whether the ciphertext and secret key are correct! error msg: {}", e.getMessage()); - } - } - } - JedisPoolConfig poolConfig = new JedisPoolConfig(); - poolConfig.setMinIdle(CONFIGURATION.getInt(ConfigurationKeys.STORE_REDIS_MIN_CONN, - DEFAULT_REDIS_MIN_IDLE)); - poolConfig.setMaxIdle(CONFIGURATION.getInt(ConfigurationKeys.STORE_REDIS_MAX_CONN, - DEFAULT_REDIS_MAX_IDLE)); - poolConfig.setMaxTotal(CONFIGURATION.getInt(ConfigurationKeys.STORE_REDIS_MAX_TOTAL, DEFAULT_REDIS_MAX_TOTAL)); - String mode = CONFIGURATION.getConfig(ConfigurationKeys.STORE_REDIS_MODE,ConfigurationKeys.REDIS_SINGLE_MODE); - if (mode.equals(ConfigurationKeys.REDIS_SENTINEL_MODE)) { - String masterName = CONFIGURATION.getConfig(ConfigurationKeys.STORE_REDIS_SENTINEL_MASTERNAME); - if (StringUtils.isBlank(masterName)) { - throw new RedisException("The masterName is null in redis sentinel mode"); - } - Set sentinels = new HashSet<>(SENTINEL_HOST_NUMBER); - String[] sentinelHosts = CONFIGURATION.getConfig(ConfigurationKeys.STORE_REDIS_SENTINEL_HOST).split(","); - Arrays.asList(sentinelHosts).forEach(sentinelHost -> sentinels.add(sentinelHost)); - tempJedisPool = new JedisSentinelPool(masterName, sentinels, poolConfig, 60000, password, CONFIGURATION.getInt(ConfigurationKeys.STORE_REDIS_DATABASE, DATABASE)); - } else if (mode.equals(ConfigurationKeys.REDIS_SINGLE_MODE)) { - String host = CONFIGURATION.getConfig(ConfigurationKeys.STORE_REDIS_SINGLE_HOST); - host = StringUtils.isBlank(host) ? CONFIGURATION.getConfig(ConfigurationKeys.STORE_REDIS_HOST, HOST) : host; - int port = CONFIGURATION.getInt(ConfigurationKeys.STORE_REDIS_SINGLE_PORT); - port = port == 0 ? CONFIGURATION.getInt(ConfigurationKeys.STORE_REDIS_PORT, PORT) : port; - tempJedisPool = new JedisPool(poolConfig, host, port, 60000, password, CONFIGURATION.getInt(ConfigurationKeys.STORE_REDIS_DATABASE, DATABASE)); - } else { - throw new RedisException("Configuration error of redis cluster mode"); - } - } - if (LOGGER.isInfoEnabled()) { - LOGGER.info("initialization of the build redis connection pool is complete"); - } - jedisPool = tempJedisPool; - } - } - } - return jedisPool; - } - - /** - * get an instance of Jedis (connection) from the connection pool - * - * @return jedis - */ - public static Jedis getJedisInstance() { - return getJedisPoolInstance().getResource(); - } - -} diff --git a/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/storage/redis/lock/RedisDistributedLocker.java b/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/storage/redis/lock/RedisDistributedLocker.java deleted file mode 100644 index ecd60cac..00000000 --- a/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/storage/redis/lock/RedisDistributedLocker.java +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Copyright 1999-2019 Seata.io Group. - * - * Licensed 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 io.seata.server.storage.redis.lock; - -import io.seata.common.loader.LoadLevel; -import io.seata.common.loader.Scope; -import io.seata.core.store.DistributedLockDO; -import io.seata.core.store.DistributedLocker; -import io.seata.server.storage.redis.JedisPooledFactory; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import redis.clients.jedis.Jedis; -import redis.clients.jedis.Transaction; -import redis.clients.jedis.params.SetParams; - -/** - * Redis distributed lock - * @author zhongxiang.wang - */ -@LoadLevel(name = "redis", scope = Scope.SINGLETON) -public class RedisDistributedLocker implements DistributedLocker { - - protected static final Logger LOGGER = LoggerFactory.getLogger(RedisDistributedLocker.class); - private static final String SUCCESS = "OK"; - - /** - * Acquire the distributed lock - * - * @param distributedLockDO the distributed lock info - * @return the distributed lock info - */ - @Override - public boolean acquireLock(DistributedLockDO distributedLockDO) { - try (Jedis jedis = JedisPooledFactory.getJedisInstance()) { - //Don't need retry,if can't acquire the lock,let the other get the lock - String result = jedis.set(distributedLockDO.getLockKey(), distributedLockDO.getLockValue(), SetParams.setParams().nx().px(distributedLockDO.getExpireTime())); - return SUCCESS.equalsIgnoreCase(result); - } catch (Exception ex) { - LOGGER.error("The {} acquired the {} distributed lock failed.", distributedLockDO.getLockValue(), distributedLockDO.getLockKey(), ex); - return false; - } - } - - - /** - * Release the distributed lock - * - * @param distributedLockDO the distributed lock info - * @return the boolean - */ - @Override - public boolean releaseLock(DistributedLockDO distributedLockDO) { - String lockKey = distributedLockDO.getLockKey(); - String lockValue = distributedLockDO.getLockValue(); - try (Jedis jedis = JedisPooledFactory.getJedisInstance()) { - jedis.watch(lockKey); - //Check the value to prevent release the other's lock - if (lockValue.equals(jedis.get(lockKey))) { - Transaction multi = jedis.multi(); - multi.del(lockKey); - multi.exec(); - return true; - } - //The lock hold by others,If other one get the lock,we release lock success too as for current lockKey - jedis.unwatch(); - return true; - } catch (Exception ex) { - LOGGER.error("The {} release the {} distributed lock failed.", lockValue, lockKey, ex); - return false; - } - } -} diff --git a/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/storage/redis/lock/RedisLockManager.java b/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/storage/redis/lock/RedisLockManager.java deleted file mode 100644 index 067fd50d..00000000 --- a/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/storage/redis/lock/RedisLockManager.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright 1999-2019 Seata.io Group. - * - * Licensed 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 io.seata.server.storage.redis.lock; - -import io.seata.common.executor.Initialize; -import io.seata.common.loader.LoadLevel; -import io.seata.core.exception.TransactionException; -import io.seata.core.lock.Locker; -import io.seata.server.lock.AbstractLockManager; -import io.seata.server.session.BranchSession; -import io.seata.server.session.GlobalSession; - -/** - * @author funkye - */ -@LoadLevel(name = "redis") -public class RedisLockManager extends AbstractLockManager implements Initialize { - - /** - * The locker. - */ - private Locker locker; - - @Override - public void init() { - locker = new RedisLocker(); - } - - @Override - public Locker getLocker(BranchSession branchSession) { - return locker; - } - - @Override - public boolean releaseLock(BranchSession branchSession) throws TransactionException { - try { - return getLocker().releaseLock(branchSession.getXid(), branchSession.getBranchId()); - } catch (Exception t) { - LOGGER.error("unLock error, xid {}, branchId:{}", branchSession.getXid(), branchSession.getBranchId(), t); - return false; - } - } - - @Override - public boolean releaseGlobalSessionLock(GlobalSession globalSession) throws TransactionException { - try { - return getLocker().releaseLock(globalSession.getXid()); - } catch (Exception t) { - LOGGER.error("unLock globalSession error, xid:{}", globalSession.getXid(), t); - return false; - } - } -} \ No newline at end of file diff --git a/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/storage/redis/lock/RedisLocker.java b/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/storage/redis/lock/RedisLocker.java deleted file mode 100644 index 361b1624..00000000 --- a/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/storage/redis/lock/RedisLocker.java +++ /dev/null @@ -1,385 +0,0 @@ -/* - * Copyright 1999-2019 Seata.io Group. - * - * Licensed 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 io.seata.server.storage.redis.lock; - -import com.google.common.collect.Lists; -import io.seata.common.exception.StoreException; -import io.seata.common.io.FileLoader; -import io.seata.common.util.CollectionUtils; -import io.seata.common.util.LambdaUtils; -import io.seata.common.util.StringUtils; -import io.seata.core.exception.BranchTransactionException; -import io.seata.core.lock.AbstractLocker; -import io.seata.core.lock.RowLock; -import io.seata.core.model.LockStatus; -import io.seata.core.store.LockDO; -import io.seata.server.storage.redis.JedisPooledFactory; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import redis.clients.jedis.Jedis; -import redis.clients.jedis.Pipeline; - -import java.io.*; -import java.util.*; -import java.util.stream.Collectors; - -import static io.seata.common.Constants.ROW_LOCK_KEY_SPLIT_CHAR; -import static io.seata.core.constants.RedisKeyConstants.DEFAULT_REDIS_SEATA_GLOBAL_LOCK_PREFIX; -import static io.seata.core.constants.RedisKeyConstants.DEFAULT_REDIS_SEATA_ROW_LOCK_PREFIX; -import static io.seata.core.exception.TransactionExceptionCode.LockKeyConflictFailFast; -/** - * The redis lock store operation - * - * @author funkye - * @author wangzhongxiang - */ -public class RedisLocker extends AbstractLocker { - - private static final Logger LOGGER = LoggerFactory.getLogger(RedisLocker.class); - - private static final Integer SUCCEED = 1; - - private static final Integer FAILED = 0; - - private static final String XID = "xid"; - - private static final String TRANSACTION_ID = "transactionId"; - - private static final String BRANCH_ID = "branchId"; - - private static final String RESOURCE_ID = "resourceId"; - - private static final String TABLE_NAME = "tableName"; - - private static final String PK = "pk"; - - private static final String STATUS = "status"; - - private static final String ROW_KEY = "rowKey"; - - private static final String REDIS_LUA_FILE_NAME = "lua/redislocker/redislock.lua"; - - private static String ACQUIRE_LOCK_SHA; - - private static final String WHITE_SPACE = " "; - - private static final String ANNOTATION_LUA = "--"; - - /** - * Instantiates a new Redis locker. - */ - public RedisLocker() { - if (ACQUIRE_LOCK_SHA == null) { - File luaFile = FileLoader.load(REDIS_LUA_FILE_NAME); - if (luaFile != null) { - StringBuilder acquireLockLuaByFile = new StringBuilder(); - try (FileInputStream fis = new FileInputStream(luaFile)) { - BufferedReader br = new BufferedReader(new InputStreamReader(fis)); - String line; - while ((line = br.readLine()) != null) { - if (line.trim().startsWith(ANNOTATION_LUA)) { - continue; - } - acquireLockLuaByFile.append(line); - acquireLockLuaByFile.append(WHITE_SPACE); - } - // if it fails to read the file, pipeline mode is used - } catch (IOException e) { - LOGGER.info("redis locker use pipeline mode"); - return; - } - try (Jedis jedis = JedisPooledFactory.getJedisInstance()) { - ACQUIRE_LOCK_SHA = jedis.scriptLoad(acquireLockLuaByFile.toString()); - LOGGER.info("redis locker use lua mode"); - } - } else { - LOGGER.info("redis locker use pipeline mode"); - } - } - } - - @Override - public boolean acquireLock(List rowLocks) { - return acquireLock(rowLocks, true, false); - } - - @Override - public boolean acquireLock(List rowLocks, boolean autoCommit, boolean skipCheckLock) { - if (CollectionUtils.isEmpty(rowLocks)) { - return true; - } - try (Jedis jedis = JedisPooledFactory.getJedisInstance()) { - if (ACQUIRE_LOCK_SHA != null && autoCommit) { - return acquireLockByLua(jedis, rowLocks); - } else { - return acquireLockByPipeline(jedis, rowLocks, autoCommit, skipCheckLock); - } - } - } - - private boolean acquireLockByPipeline(Jedis jedis, List rowLocks, boolean autoCommit, boolean skipCheckLock) { - String needLockXid = rowLocks.get(0).getXid(); - Long branchId = rowLocks.get(0).getBranchId(); - List needLockDOS = convertToLockDO(rowLocks); - if (needLockDOS.size() > 1) { - needLockDOS = - needLockDOS.stream().filter(LambdaUtils.distinctByKey(LockDO::getRowKey)).collect(Collectors.toList()); - } - List needLockKeys = new ArrayList<>(); - needLockDOS.forEach(lockDO -> needLockKeys.add(buildLockKey(lockDO.getRowKey()))); - Map needAddLock = new HashMap<>(needLockKeys.size(), 1); - - if (!skipCheckLock) { - Pipeline pipeline1 = jedis.pipelined(); - needLockKeys.stream().forEachOrdered(needLockKey -> { - pipeline1.hget(needLockKey, XID); - if (!autoCommit) { - pipeline1.hget(needLockKey, STATUS); - } - }); - List> existedLockInfos = - Lists.partition((List)(List)pipeline1.syncAndReturnAll(), autoCommit ? 1 : 2); - - // When the local transaction and the global transaction are enabled, - // the branch registration fails to acquire the global lock, - // the lock holder is in the second-stage rollback, - // and the branch registration fails to be retried quickly, - // because the retry with the local transaction does not release the database lock , - // resulting in a two-phase rollback wait. - // Therefore, if a global lock is found in the Rollbacking state, - // the fail-fast code is returned directly. - if (!autoCommit) { - boolean hasRollBackingLock = existedLockInfos.parallelStream().anyMatch( - result -> StringUtils.equals(result.get(1), String.valueOf(LockStatus.Rollbacking.getCode()))); - if (hasRollBackingLock) { - throw new StoreException(new BranchTransactionException(LockKeyConflictFailFast)); - } - } - - // The logic is executed here, there must be a lock without Rollbacking status when autoCommit equals false - for (int i = 0; i < needLockKeys.size(); i++) { - List results = existedLockInfos.get(i); - String existedLockXid = CollectionUtils.isEmpty(results) ? null : existedLockInfos.get(i).get(0); - if (StringUtils.isEmpty(existedLockXid)) { - // If empty,we need to lock this row - needAddLock.put(needLockKeys.get(i), needLockDOS.get(i)); - } else { - if (!StringUtils.equals(existedLockXid, needLockXid)) { - // If not equals,means the rowkey is holding by another global transaction - logGlobalLockConflictInfo(needLockXid, needLockKeys.get(i), existedLockXid); - return false; - } - } - } - if (needAddLock.isEmpty()) { - return true; - } - } - - Pipeline pipeline = jedis.pipelined(); - List readyKeys = new ArrayList<>(needAddLock.keySet()); - needAddLock.forEach((key, value) -> { - pipeline.hsetnx(key, XID, value.getXid()); - pipeline.hsetnx(key, TRANSACTION_ID, value.getTransactionId().toString()); - pipeline.hsetnx(key, BRANCH_ID, value.getBranchId().toString()); - pipeline.hset(key, ROW_KEY, value.getRowKey()); - pipeline.hset(key, RESOURCE_ID, value.getResourceId()); - pipeline.hset(key, TABLE_NAME, value.getTableName()); - pipeline.hset(key, PK, value.getPk()); - }); - List results = (List) (List) pipeline.syncAndReturnAll(); - List> partitions = Lists.partition(results, 7); - - ArrayList success = new ArrayList<>(partitions.size()); - Integer status = SUCCEED; - for (int i = 0; i < partitions.size(); i++) { - if (Objects.equals(partitions.get(i).get(0), FAILED)) { - status = FAILED; - } else { - success.add(readyKeys.get(i)); - } - } - - // If someone has failed,all the lockkey which has been added need to be delete. - if (FAILED.equals(status)) { - if (success.size() > 0) { - jedis.del(success.toArray(new String[0])); - } - return false; - } - String xidLockKey = buildXidLockKey(needLockXid); - StringJoiner lockKeysString = new StringJoiner(ROW_LOCK_KEY_SPLIT_CHAR); - needLockKeys.forEach(lockKeysString::add); - jedis.hset(xidLockKey, branchId.toString(), lockKeysString.toString()); - return true; - } - - private boolean acquireLockByLua(Jedis jedis, List rowLocks) { - String needLockXid = rowLocks.get(0).getXid(); - Long branchId = rowLocks.get(0).getBranchId(); - List needLockDOs = rowLocks.stream() - .map(this::convertToLockDO) - .filter(LambdaUtils.distinctByKey(LockDO::getRowKey)) - .collect(Collectors.toList()); - ArrayList keys = new ArrayList<>(); - ArrayList args = new ArrayList<>(); - int size = needLockDOs.size(); - args.add(String.valueOf(size)); - // args index 2 placeholder - args.add(null); - args.add(needLockXid); - for (LockDO lockDO : needLockDOs) { - keys.add(buildLockKey(lockDO.getRowKey())); - args.add(lockDO.getTransactionId().toString()); - args.add(lockDO.getBranchId().toString()); - args.add(lockDO.getResourceId()); - args.add(lockDO.getTableName()); - args.add(lockDO.getRowKey()); - args.add(lockDO.getPk()); - } - String xidLockKey = buildXidLockKey(needLockXid); - StringJoiner lockKeysString = new StringJoiner(ROW_LOCK_KEY_SPLIT_CHAR); - needLockDOs.stream().map(lockDO -> buildLockKey(lockDO.getRowKey())).forEach(lockKeysString::add); - keys.add(xidLockKey); - keys.add(branchId.toString()); - args.add(lockKeysString.toString()); - // reset args index 2 - args.set(1, String.valueOf(args.size())); - String xIdOwnLock = (String) jedis.evalsha(ACQUIRE_LOCK_SHA, keys, args); - if (xIdOwnLock.equals(needLockXid)) { - return true; - } else { - logGlobalLockConflictInfo(needLockXid, keys.get(0), xIdOwnLock); - return false; - } - } - - private void logGlobalLockConflictInfo(String needLockXid, String lockKey, String xIdOwnLock) { - LOGGER.info("tx:[{}] acquire Global lock failed. Global lock on [{}] is holding by xid {}", needLockXid, lockKey, xIdOwnLock); - } - - @Override - public boolean releaseLock(List rowLocks) { - if (CollectionUtils.isEmpty(rowLocks)) { - return true; - } - String currentXid = rowLocks.get(0).getXid(); - Long branchId = rowLocks.get(0).getBranchId(); - List needReleaseLocks = convertToLockDO(rowLocks); - String[] needReleaseKeys = new String[needReleaseLocks.size()]; - for (int i = 0; i < needReleaseLocks.size(); i++) { - needReleaseKeys[i] = buildLockKey(needReleaseLocks.get(i).getRowKey()); - } - - try (Jedis jedis = JedisPooledFactory.getJedisInstance(); Pipeline pipelined = jedis.pipelined()) { - pipelined.del(needReleaseKeys); - pipelined.hdel(buildXidLockKey(currentXid), branchId.toString()); - pipelined.sync(); - return true; - } - } - - @Override - public boolean releaseLock(String xid) { - return doReleaseLock(xid, null); - } - - @Override - public boolean releaseLock(String xid, Long branchId) { - if (branchId == null) { - return true; - } - return doReleaseLock(xid, branchId); - } - - @Override - public boolean isLockable(List rowLocks) { - if (CollectionUtils.isEmpty(rowLocks)) { - return true; - } - try (Jedis jedis = JedisPooledFactory.getJedisInstance()) { - List locks = convertToLockDO(rowLocks); - Set lockKeys = new HashSet<>(); - for (LockDO rowlock : locks) { - lockKeys.add(buildLockKey(rowlock.getRowKey())); - } - - String xid = rowLocks.get(0).getXid(); - try (Pipeline pipeline = jedis.pipelined()) { - lockKeys.forEach(key -> pipeline.hget(key, XID)); - List existedXids = (List)(List)pipeline.syncAndReturnAll(); - return existedXids.stream().allMatch(existedXid -> existedXid == null || xid.equals(existedXid)); - } - } - } - - @Override - public void updateLockStatus(String xid, LockStatus lockStatus) { - try (Jedis jedis = JedisPooledFactory.getJedisInstance()) { - String xidLockKey = buildXidLockKey(xid); - Map branchAndLockKeys = jedis.hgetAll(xidLockKey); - if (CollectionUtils.isNotEmpty(branchAndLockKeys)) { - try (Pipeline pipeline = jedis.pipelined()) { - branchAndLockKeys.values() - .forEach(k -> pipeline.hset(k, STATUS, String.valueOf(lockStatus.getCode()))); - pipeline.sync(); - } - } - } - } - - private boolean doReleaseLock(String xid, Long branchId) { - try (Jedis jedis = JedisPooledFactory.getJedisInstance()) { - String xidLockKey = buildXidLockKey(xid); - final List rowKeys = new ArrayList<>(); - if (null == branchId) { - Map rowKeyMap = jedis.hgetAll(xidLockKey); - rowKeyMap.forEach((branch, rowKey) -> rowKeys.add(rowKey)); - } else { - rowKeys.add(jedis.hget(xidLockKey, branchId.toString())); - } - if (CollectionUtils.isNotEmpty(rowKeys)) { - Pipeline pipelined = jedis.pipelined(); - if (null == branchId) { - pipelined.del(xidLockKey); - } else { - pipelined.hdel(xidLockKey, branchId.toString()); - } - rowKeys.forEach(rowKeyStr -> { - if (StringUtils.isNotEmpty(rowKeyStr)) { - if (rowKeyStr.contains(ROW_LOCK_KEY_SPLIT_CHAR)) { - String[] keys = rowKeyStr.split(ROW_LOCK_KEY_SPLIT_CHAR); - pipelined.del(keys); - } else { - pipelined.del(rowKeyStr); - } - } - }); - pipelined.sync(); - } - return true; - } - } - - private String buildXidLockKey(String xid) { - return DEFAULT_REDIS_SEATA_GLOBAL_LOCK_PREFIX + xid; - } - - private String buildLockKey(String rowKey) { - return DEFAULT_REDIS_SEATA_ROW_LOCK_PREFIX + rowKey; - } - -} diff --git a/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/storage/redis/session/RedisSessionManager.java b/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/storage/redis/session/RedisSessionManager.java deleted file mode 100644 index 50120200..00000000 --- a/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/storage/redis/session/RedisSessionManager.java +++ /dev/null @@ -1,189 +0,0 @@ -/* - * Copyright 1999-2019 Seata.io Group. - * - * Licensed 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 io.seata.server.storage.redis.session; - -import io.seata.common.exception.StoreException; -import io.seata.common.executor.Initialize; -import io.seata.common.loader.LoadLevel; -import io.seata.common.loader.Scope; -import io.seata.common.util.StringUtils; -import io.seata.core.exception.TransactionException; -import io.seata.core.model.BranchStatus; -import io.seata.core.model.GlobalStatus; -import io.seata.server.session.*; -import io.seata.server.storage.redis.store.RedisTransactionStoreManager; -import io.seata.server.store.TransactionStoreManager.LogOperation; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.util.Collection; -import java.util.List; - -/** - * @author funkye - */ -@LoadLevel(name = "redis", scope = Scope.PROTOTYPE) -public class RedisSessionManager extends AbstractSessionManager - implements Initialize { - /** - * The constant LOGGER. - */ - protected static final Logger LOGGER = LoggerFactory.getLogger(RedisSessionManager.class); - - /** - * The Task name. - */ - protected String taskName; - - /** - * Instantiates a new Data base session manager. - */ - public RedisSessionManager() { - super(); - } - - /** - * Instantiates a new Data base session manager. - * - * @param name - * the name - */ - public RedisSessionManager(String name) { - super(); - this.taskName = name; - } - - @Override - public void init() { - transactionStoreManager = RedisTransactionStoreManager.getInstance(); - } - - @Override - public void addGlobalSession(GlobalSession session) throws TransactionException { - if (StringUtils.isBlank(taskName)) { - boolean ret = transactionStoreManager.writeSession(LogOperation.GLOBAL_ADD, session); - if (!ret) { - throw new StoreException("addGlobalSession failed."); - } - } else { - boolean ret = transactionStoreManager.writeSession(LogOperation.GLOBAL_UPDATE, session); - if (!ret) { - throw new StoreException("addGlobalSession failed."); - } - } - } - - @Override - public void updateGlobalSessionStatus(GlobalSession session, GlobalStatus status) throws TransactionException { - if (!StringUtils.isEmpty(taskName)) { - return; - } - session.setStatus(status); - boolean ret = transactionStoreManager.writeSession(LogOperation.GLOBAL_UPDATE, session); - if (!ret) { - throw new StoreException("updateGlobalSessionStatus failed."); - } - } - - /** - * remove globalSession 1. rootSessionManager remove normal globalSession 2. retryCommitSessionManager and - * retryRollbackSessionManager remove retry expired globalSession - * - * @param session - * the session - * @throws TransactionException - */ - @Override - public void removeGlobalSession(GlobalSession session) throws TransactionException { - boolean ret = transactionStoreManager.writeSession(LogOperation.GLOBAL_REMOVE, session); - if (!ret) { - throw new StoreException("removeGlobalSession failed."); - } - } - - @Override - public void addBranchSession(GlobalSession globalSession, BranchSession session) throws TransactionException { - if (!StringUtils.isEmpty(taskName)) { - return; - } - boolean ret = transactionStoreManager.writeSession(LogOperation.BRANCH_ADD, session); - if (!ret) { - throw new StoreException("addBranchSession failed."); - } - } - - @Override - public void updateBranchSessionStatus(BranchSession session, BranchStatus status) throws TransactionException { - if (!StringUtils.isEmpty(taskName)) { - return; - } - boolean ret = transactionStoreManager.writeSession(LogOperation.BRANCH_UPDATE, session); - if (!ret) { - throw new StoreException("updateBranchSessionStatus failed."); - } - } - - @Override - public void removeBranchSession(GlobalSession globalSession, BranchSession session) throws TransactionException { - if (!StringUtils.isEmpty(taskName)) { - return; - } - boolean ret = transactionStoreManager.writeSession(LogOperation.BRANCH_REMOVE, session); - if (!ret) { - throw new StoreException("removeBranchSession failed."); - } - } - - @Override - public GlobalSession findGlobalSession(String xid) { - return this.findGlobalSession(xid, true); - } - - @Override - public GlobalSession findGlobalSession(String xid, boolean withBranchSessions) { - return transactionStoreManager.readSession(xid, withBranchSessions); - } - - @Override - public Collection allSessions() { - // get by taskName - if (SessionHolder.ASYNC_COMMITTING_SESSION_MANAGER_NAME.equalsIgnoreCase(taskName)) { - return findGlobalSessions(new SessionCondition(GlobalStatus.AsyncCommitting)); - } else if (SessionHolder.RETRY_COMMITTING_SESSION_MANAGER_NAME.equalsIgnoreCase(taskName)) { - return findGlobalSessions(new SessionCondition(GlobalStatus.CommitRetrying, GlobalStatus.Committing)); - } else if (SessionHolder.RETRY_ROLLBACKING_SESSION_MANAGER_NAME.equalsIgnoreCase(taskName)) { - return findGlobalSessions(new SessionCondition(GlobalStatus.RollbackRetrying, GlobalStatus.Rollbacking, - GlobalStatus.TimeoutRollbacking, GlobalStatus.TimeoutRollbackRetrying)); - } else { - // all data - return findGlobalSessions(new SessionCondition(GlobalStatus.UnKnown, GlobalStatus.Begin, GlobalStatus.Committing, - GlobalStatus.CommitRetrying, GlobalStatus.Rollbacking, GlobalStatus.RollbackRetrying, GlobalStatus.TimeoutRollbacking, - GlobalStatus.TimeoutRollbackRetrying, GlobalStatus.AsyncCommitting)); - } - } - - @Override - public List findGlobalSessions(SessionCondition condition) { - // nothing need to do - return transactionStoreManager.readSession(condition); - } - - @Override - public T lockAndExecute(GlobalSession globalSession, GlobalSession.LockCallable lockCallable) - throws TransactionException { - return lockCallable.call(); - } -} diff --git a/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/storage/redis/store/RedisTransactionStoreManager.java b/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/storage/redis/store/RedisTransactionStoreManager.java deleted file mode 100644 index 573d120e..00000000 --- a/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/storage/redis/store/RedisTransactionStoreManager.java +++ /dev/null @@ -1,835 +0,0 @@ -/* - * Copyright 1999-2019 Seata.io Group. - * - * Licensed 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 io.seata.server.storage.redis.store; - -import com.google.common.collect.ImmutableMap; -import io.seata.common.XID; -import io.seata.common.exception.RedisException; -import io.seata.common.exception.StoreException; -import io.seata.common.util.BeanUtils; -import io.seata.common.util.CollectionUtils; -import io.seata.common.util.StringUtils; -import io.seata.config.Configuration; -import io.seata.config.ConfigurationFactory; -import io.seata.core.model.GlobalStatus; -import io.seata.core.store.BranchTransactionDO; -import io.seata.core.store.GlobalTransactionDO; -import io.seata.server.console.param.GlobalSessionParam; -import io.seata.server.session.GlobalSession; -import io.seata.server.session.SessionCondition; -import io.seata.server.session.SessionStatusValidator; -import io.seata.server.storage.SessionConverter; -import io.seata.server.storage.redis.JedisPooledFactory; -import io.seata.server.store.AbstractTransactionStoreManager; -import io.seata.server.store.SessionStorable; -import io.seata.server.store.TransactionStoreManager; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import redis.clients.jedis.Jedis; -import redis.clients.jedis.Pipeline; -import redis.clients.jedis.Transaction; - -import java.util.*; -import java.util.function.Function; -import java.util.stream.Collectors; - -import static io.seata.common.ConfigurationKeys.STORE_REDIS_QUERY_LIMIT; -import static io.seata.common.DefaultValues.DEFAULT_QUERY_LIMIT; -import static io.seata.core.constants.RedisKeyConstants.*; - -/** - * The redis transaction store manager - * - * @author funkye - * @author wangzhongxiang - * @author doubleDimple - */ -public class RedisTransactionStoreManager extends AbstractTransactionStoreManager implements TransactionStoreManager { - - private static final Logger LOGGER = LoggerFactory.getLogger(RedisTransactionStoreManager.class); - - /**the prefix of the branch transactions*/ - private static final String REDIS_SEATA_BRANCHES_PREFIX = "SEATA_BRANCHES_"; - - /**the prefix of the branch transaction*/ - private static final String REDIS_SEATA_BRANCH_PREFIX = "SEATA_BRANCH_"; - - /**the prefix of the global transaction*/ - private static final String REDIS_SEATA_GLOBAL_PREFIX = "SEATA_GLOBAL_"; - - /**the prefix of the global transaction status*/ - private static final String REDIS_SEATA_STATUS_PREFIX = "SEATA_STATUS_"; - - /**the key of global transaction status for begin*/ - private static final String REDIS_SEATA_BEGIN_TRANSACTIONS_KEY = "SEATA_BEGIN_TRANSACTIONS"; - - private static volatile RedisTransactionStoreManager instance; - - private static final String OK = "OK"; - - /** - * The constant CONFIG. - */ - private static final Configuration CONFIG = ConfigurationFactory.getInstance(); - - /** - * The Log query limit. - */ - private int logQueryLimit; - - /** - * Get the instance. - */ - public static RedisTransactionStoreManager getInstance() { - if (instance == null) { - synchronized (RedisTransactionStoreManager.class) { - if (instance == null) { - instance = new RedisTransactionStoreManager(); - } - } - } - return instance; - } - - /** - * init map to constructor - */ - public RedisTransactionStoreManager() { - super(); - initGlobalMap(); - initBranchMap(); - logQueryLimit = CONFIG.getInt(STORE_REDIS_QUERY_LIMIT, DEFAULT_QUERY_LIMIT); - } - - /** - * Map for LogOperation Global Operation - */ - public static volatile ImmutableMap> globalMap; - - /** - * Map for LogOperation Branch Operation - */ - public static volatile ImmutableMap> branchMap; - - - /** - * init globalMap - * - */ - public void initGlobalMap() { - if (CollectionUtils.isEmpty(branchMap)) { - globalMap = ImmutableMap.>builder() - .put(LogOperation.GLOBAL_ADD, this::insertGlobalTransactionDO) - .put(LogOperation.GLOBAL_UPDATE, this::updateGlobalTransactionDO) - .put(LogOperation.GLOBAL_REMOVE, this::deleteGlobalTransactionDO) - .build(); - } - } - - /** - * init branchMap - * - */ - public void initBranchMap() { - if (CollectionUtils.isEmpty(branchMap)) { - branchMap = ImmutableMap.>builder() - .put(LogOperation.BRANCH_ADD, this::insertBranchTransactionDO) - .put(LogOperation.BRANCH_UPDATE, this::updateBranchTransactionDO) - .put(LogOperation.BRANCH_REMOVE, this::deleteBranchTransactionDO) - .build(); - } - } - - - @Override - public boolean writeSession(LogOperation logOperation, SessionStorable session) { - if (globalMap.containsKey(logOperation) || branchMap.containsKey(logOperation)) { - return globalMap.containsKey(logOperation) ? - globalMap.get(logOperation).apply(SessionConverter.convertGlobalTransactionDO(session)) : - branchMap.get(logOperation).apply(SessionConverter.convertBranchTransactionDO(session)); - } else { - throw new StoreException("Unknown LogOperation:" + logOperation.name()); - } - } - - /** - * Insert branch transaction - * @param branchTransactionDO - * @return the boolean - */ - private boolean insertBranchTransactionDO(BranchTransactionDO branchTransactionDO) { - String branchKey = buildBranchKey(branchTransactionDO.getBranchId()); - String branchListKey = buildBranchListKeyByXid(branchTransactionDO.getXid()); - try (Jedis jedis = JedisPooledFactory.getJedisInstance(); Pipeline pipelined = jedis.pipelined()) { - Date now = new Date(); - branchTransactionDO.setGmtCreate(now); - branchTransactionDO.setGmtModified(now); - pipelined.hmset(branchKey, BeanUtils.objectToMap(branchTransactionDO)); - pipelined.rpush(branchListKey, branchKey); - pipelined.sync(); - return true; - } catch (Exception ex) { - throw new RedisException(ex); - } - } - - /** - * Delete the branch transaction - * @param branchTransactionDO - * @return - */ - private boolean deleteBranchTransactionDO(BranchTransactionDO branchTransactionDO) { - String branchKey = buildBranchKey(branchTransactionDO.getBranchId()); - try (Jedis jedis = JedisPooledFactory.getJedisInstance()) { - String xid = jedis.hget(branchKey, REDIS_KEY_BRANCH_XID); - if (StringUtils.isEmpty(xid)) { - return true; - } - String branchListKey = buildBranchListKeyByXid(branchTransactionDO.getXid()); - try (Pipeline pipelined = jedis.pipelined()) { - pipelined.lrem(branchListKey, 0, branchKey); - pipelined.del(branchKey); - pipelined.sync(); - } - return true; - } catch (Exception ex) { - throw new RedisException(ex); - } - } - - /** - * Update the branch transaction - * @param branchTransactionDO - * @return - */ - private boolean updateBranchTransactionDO(BranchTransactionDO branchTransactionDO) { - String branchKey = buildBranchKey(branchTransactionDO.getBranchId()); - try (Jedis jedis = JedisPooledFactory.getJedisInstance()) { - String previousBranchStatus = jedis.hget(branchKey, REDIS_KEY_BRANCH_STATUS); - if (StringUtils.isEmpty(previousBranchStatus)) { - throw new StoreException("Branch transaction is not exist, update branch transaction failed."); - } - Map map = new HashMap<>(3, 1); - map.put(REDIS_KEY_BRANCH_STATUS, String.valueOf(branchTransactionDO.getStatus())); - map.put(REDIS_KEY_BRANCH_GMT_MODIFIED, String.valueOf((new Date()).getTime())); - if (StringUtils.isNotBlank(branchTransactionDO.getApplicationData())) { - map.put(REDIS_KEY_BRANCH_APPLICATION_DATA, String.valueOf(branchTransactionDO.getApplicationData())); - } - jedis.hmset(branchKey, map); - return true; - } catch (Exception ex) { - throw new RedisException(ex); - } - } - - /** - * Insert the global transaction. - * @param globalTransactionDO - * @return - */ - private boolean insertGlobalTransactionDO(GlobalTransactionDO globalTransactionDO) { - String globalKey = buildGlobalKeyByTransactionId(globalTransactionDO.getTransactionId()); - try (Jedis jedis = JedisPooledFactory.getJedisInstance(); Pipeline pipelined = jedis.pipelined()) { - Date now = new Date(); - globalTransactionDO.setGmtCreate(now); - globalTransactionDO.setGmtModified(now); - pipelined.hmset(globalKey, BeanUtils.objectToMap(globalTransactionDO)); - String xid = globalTransactionDO.getXid(); - pipelined.rpush(buildGlobalStatus(globalTransactionDO.getStatus()), xid); - pipelined.zadd(REDIS_SEATA_BEGIN_TRANSACTIONS_KEY, - globalTransactionDO.getBeginTime() + globalTransactionDO.getTimeout(), globalKey); - pipelined.sync(); - return true; - } catch (Exception ex) { - throw new RedisException(ex); - } - } - - /** - * Delete the global transaction. - * It will operate two parts: - * 1.delete the global session map - * 2.remove the xid from the global status list - * If the operate failed,the succeed operates will rollback - * @param globalTransactionDO - * @return - */ - private boolean deleteGlobalTransactionDO(GlobalTransactionDO globalTransactionDO) { - String globalKey = buildGlobalKeyByTransactionId(globalTransactionDO.getTransactionId()); - try (Jedis jedis = JedisPooledFactory.getJedisInstance()) { - String xid = jedis.hget(globalKey, REDIS_KEY_GLOBAL_XID); - if (StringUtils.isEmpty(xid)) { - LOGGER.warn("Global transaction is not exist,xid = {}.Maybe has been deleted by another tc server", - globalTransactionDO.getXid()); - return true; - } - try (Pipeline pipelined = jedis.pipelined()) { - pipelined.lrem(buildGlobalStatus(globalTransactionDO.getStatus()), 0, globalTransactionDO.getXid()); - pipelined.del(globalKey); - if (GlobalStatus.Begin.getCode() == globalTransactionDO.getStatus() - || GlobalStatus.UnKnown.getCode() == globalTransactionDO.getStatus()) { - pipelined.zrem(REDIS_SEATA_BEGIN_TRANSACTIONS_KEY, globalKey); - } - pipelined.sync(); - } - return true; - } catch (Exception ex) { - throw new RedisException(ex); - } - } - - /** - * Update the global transaction. - * It will update two parts: - * 1.the global session map - * 2.the global status list - * If the update failed,the succeed operates will rollback - * @param globalTransactionDO - * @return - */ - private boolean updateGlobalTransactionDO(GlobalTransactionDO globalTransactionDO) { - String xid = globalTransactionDO.getXid(); - String globalKey = buildGlobalKeyByTransactionId(globalTransactionDO.getTransactionId()); - try (Jedis jedis = JedisPooledFactory.getJedisInstance()) { - // Defensive watch to prevent other TC server operating concurrently,Fail fast - jedis.watch(globalKey); - List statusAndGmtModified = jedis.hmget(globalKey, REDIS_KEY_GLOBAL_STATUS, REDIS_KEY_GLOBAL_GMT_MODIFIED); - String previousStatus = statusAndGmtModified.get(0); - if (StringUtils.isEmpty(previousStatus)) { - jedis.unwatch(); - throw new StoreException("Global transaction is not exist, update global transaction failed."); - } - if (previousStatus.equals(String.valueOf(globalTransactionDO.getStatus()))) { - jedis.unwatch(); - return true; - } - GlobalStatus before = GlobalStatus.get(Integer.parseInt(previousStatus)); - GlobalStatus after = GlobalStatus.get(globalTransactionDO.getStatus()); - if (!SessionStatusValidator.validateUpdateStatus(before, after)) { - throw new StoreException("Illegal changing of global status, update global transaction failed." - + " beforeStatus[" + before.name() + "] cannot be changed to afterStatus[" + after.name() + "]"); - } - - String previousGmtModified = statusAndGmtModified.get(1); - Transaction multi = jedis.multi(); - Map map = new HashMap<>(2); - map.put(REDIS_KEY_GLOBAL_STATUS,String.valueOf(globalTransactionDO.getStatus())); - map.put(REDIS_KEY_GLOBAL_GMT_MODIFIED,String.valueOf((new Date()).getTime())); - multi.hmset(globalKey, map); - multi.lrem(buildGlobalStatus(Integer.valueOf(previousStatus)), 0, xid); - multi.rpush(buildGlobalStatus(globalTransactionDO.getStatus()), xid); - multi.zrem(REDIS_SEATA_BEGIN_TRANSACTIONS_KEY, globalKey); - List exec = multi.exec(); - if (CollectionUtils.isEmpty(exec)) { - //The data has changed by another tc, so we still think the modification is successful. - LOGGER.warn("The global transaction xid = {}, maybe changed by another TC. It does not affect the results",globalTransactionDO.getXid()); - return true; - } - String hmset = exec.get(0).toString(); - long lrem = (long)exec.get(1); - long rpush = (long)exec.get(2); - if (OK.equalsIgnoreCase(hmset) && lrem > 0 && rpush > 0) { - return true; - } else { - // If someone failed, the succeed operations need rollback - if (OK.equalsIgnoreCase(hmset)) { - // Defensive watch to prevent other TC server operating concurrently,give up this operate - jedis.watch(globalKey); - String xid2 = jedis.hget(globalKey, REDIS_KEY_GLOBAL_XID); - if (StringUtils.isNotEmpty(xid2)) { - Map mapPrevious = new HashMap<>(2,1); - mapPrevious.put(REDIS_KEY_GLOBAL_STATUS,previousStatus); - mapPrevious.put(REDIS_KEY_GLOBAL_GMT_MODIFIED,previousGmtModified); - Transaction multi2 = jedis.multi(); - multi2.hmset(globalKey,mapPrevious); - multi2.exec(); - } - } - if (lrem > 0) { - jedis.rpush(buildGlobalStatus(Integer.valueOf(previousStatus)), xid); - } - if (rpush > 0) { - jedis.lrem(buildGlobalStatus(globalTransactionDO.getStatus()), 0, xid); - } - return false; - } - } catch (Exception ex) { - throw new RedisException(ex); - } - } - - /** - * Read session global session. - * - * @param xid the xid - * @param withBranchSessions the withBranchSessions - * @return the global session - */ - @Override - public GlobalSession readSession(String xid, boolean withBranchSessions) { - String transactionId = String.valueOf(XID.getTransactionId(xid)); - String globalKey = buildGlobalKeyByTransactionId(transactionId); - try (Jedis jedis = JedisPooledFactory.getJedisInstance()) { - Map map = jedis.hgetAll(globalKey); - if (CollectionUtils.isEmpty(map)) { - return null; - } - GlobalTransactionDO globalTransactionDO = (GlobalTransactionDO)BeanUtils.mapToObject(map, GlobalTransactionDO.class); - List branchTransactionDOs = null; - if (withBranchSessions) { - branchTransactionDOs = this.readBranchSessionByXid(jedis, xid); - } - GlobalSession session = getGlobalSession(globalTransactionDO, branchTransactionDOs, withBranchSessions); - return session; - } - } - - /** - * Read session global session. - * - * @param xid - * the xid - * @return the global session - */ - @Override - public GlobalSession readSession(String xid) { - return this.readSession(xid, true); - } - - /** - * Read globalSession list by global status - * - * @param statuses the statuses - * @return the list - */ - @Override - public List readSession(GlobalStatus[] statuses, boolean withBranchSessions) { - List globalSessions = Collections.synchronizedList(new ArrayList<>()); - List statusKeys = convertStatusKeys(statuses); - Map targetMap = calculateStatuskeysHasData(statusKeys); - if (targetMap.size() == 0 || logQueryLimit <= 0) { - return globalSessions; - } - int perStatusLimit = resetLogQueryLimit(targetMap); - final long countGlobalSessions = targetMap.values().stream().collect(Collectors.summarizingInt(Integer::intValue)).getSum(); - // queryCount - final long queryCount = Math.min(logQueryLimit, countGlobalSessions); - List> list = new ArrayList<>(); - dogetXidsForTargetMapRecursive(targetMap, 0L, perStatusLimit - 1, queryCount, list); - if (CollectionUtils.isNotEmpty(list)) { - List xids = list.stream().flatMap(Collection::stream).collect(Collectors.toList()); - xids.parallelStream().forEach(xid -> { - GlobalSession globalSession = this.readSession(xid, withBranchSessions); - if (globalSession != null) { - globalSessions.add(globalSession); - } - }); - } - return globalSessions; - } - - @Override - public List readSortByTimeoutBeginSessions(boolean withBranchSessions) { - List list = Collections.emptyList(); - List statusKeys = convertStatusKeys(GlobalStatus.Begin); - Map targetMap = calculateStatuskeysHasData(statusKeys); - if (targetMap.size() == 0 || logQueryLimit <= 0) { - return list; - } - final long countGlobalSessions = targetMap.values().stream().collect(Collectors.summarizingInt(Integer::intValue)).getSum(); - // queryCount - final long queryCount = Math.min(logQueryLimit, countGlobalSessions); - try (Jedis jedis = JedisPooledFactory.getJedisInstance()) { - Set values = - jedis.zrangeByScore(REDIS_SEATA_BEGIN_TRANSACTIONS_KEY, 0, System.currentTimeMillis(), 0, - (int) queryCount); - List> rep; - try (Pipeline pipeline = jedis.pipelined()) { - for (String value : values) { - pipeline.hgetAll(value); - } - rep = (List>) (List) pipeline.syncAndReturnAll(); - } - list = rep.stream().map(map -> { - GlobalTransactionDO globalTransactionDO = (GlobalTransactionDO) BeanUtils.mapToObject(map, - GlobalTransactionDO.class); - if (globalTransactionDO != null) { - String xid = globalTransactionDO.getXid(); - List branchTransactionDOs = new ArrayList<>(); - if (withBranchSessions) { - branchTransactionDOs = this.readBranchSessionByXid(jedis, xid); - } - return getGlobalSession(globalTransactionDO, branchTransactionDOs, withBranchSessions); - } - return null; - }).filter(Objects::nonNull).collect(Collectors.toList()); - } - return list; - } - - /** - * get everyone keys limit - * - * @param targetMap - * @return - */ - private int resetLogQueryLimit(Map targetMap) { - int resetLimitQuery = logQueryLimit; - if (targetMap.size() > 1) { - int size = targetMap.size(); - resetLimitQuery = (logQueryLimit / size) == 0 ? 1 : (logQueryLimit / size); - } - return resetLimitQuery; - } - - /** - * read the global session list by different condition - * @param sessionCondition the session condition - * @return the global sessions - */ - @Override - public List readSession(SessionCondition sessionCondition) { - List globalSessions = new ArrayList<>(); - if (StringUtils.isNotEmpty(sessionCondition.getXid())) { - GlobalSession globalSession = this.readSession(sessionCondition.getXid(), !sessionCondition.isLazyLoadBranch()); - if (globalSession != null) { - globalSessions.add(globalSession); - } - return globalSessions; - } else if (sessionCondition.getTransactionId() != null) { - GlobalSession globalSession = this - .readSessionByTransactionId(sessionCondition.getTransactionId().toString(), !sessionCondition.isLazyLoadBranch()); - if (globalSession != null) { - globalSessions.add(globalSession); - } - return globalSessions; - } else if (CollectionUtils.isNotEmpty(sessionCondition.getStatuses())) { - if (sessionCondition.getStatuses().length == 1 && sessionCondition.getStatuses()[0] == GlobalStatus.Begin) { - return this.readSortByTimeoutBeginSessions(!sessionCondition.isLazyLoadBranch()); - } else { - return readSession(sessionCondition.getStatuses(), !sessionCondition.isLazyLoadBranch()); - } - } - return null; - } - - /** - * query GlobalSession by status with page - * - * @param param - * @return List - */ - public List readSessionStatusByPage(GlobalSessionParam param) { - List globalSessions = new ArrayList<>(); - - int pageNum = param.getPageNum(); - int pageSize = param.getPageSize(); - int start = Math.max((pageNum - 1) * pageSize, 0); - int end = pageNum * pageSize - 1; - - if (param.getStatus() != null) { - String statusKey = buildGlobalStatus(GlobalStatus.get(param.getStatus()).getCode()); - try (Jedis jedis = JedisPooledFactory.getJedisInstance()) { - final List xids = jedis.lrange(statusKey, start, end); - xids.forEach(xid -> { - GlobalSession globalSession = this.readSession(xid, param.isWithBranch()); - if (globalSession != null) { - globalSessions.add(globalSession); - } - }); - } - } - return globalSessions; - } - - /** - * assemble the global session and branch session - * @param globalTransactionDO the global transactionDo - * @param branchTransactionDOs the branch transactionDos - * @param withBranchSessions if read branch sessions - * @return the global session with branch session - */ - private GlobalSession getGlobalSession(GlobalTransactionDO globalTransactionDO, - List branchTransactionDOs, boolean withBranchSessions) { - GlobalSession globalSession = SessionConverter.convertGlobalSession(globalTransactionDO, !withBranchSessions); - if (CollectionUtils.isNotEmpty(branchTransactionDOs)) { - for (BranchTransactionDO branchTransactionDO : branchTransactionDOs) { - globalSession.add(SessionConverter.convertBranchSession(branchTransactionDO)); - } - } - return globalSession; - } - - /** - * read the global session by transactionId - * @param transactionId the transaction id - * @param withBranchSessions if read branch sessions - * @return the global session - */ - private GlobalSession readSessionByTransactionId(String transactionId, boolean withBranchSessions) { - String globalKey = buildGlobalKeyByTransactionId(transactionId); - String xid = null; - try (Jedis jedis = JedisPooledFactory.getJedisInstance()) { - Map map = jedis.hgetAll(globalKey); - if (CollectionUtils.isEmpty(map)) { - return null; - } - GlobalTransactionDO globalTransactionDO = (GlobalTransactionDO)BeanUtils.mapToObject(map, GlobalTransactionDO.class); - if (globalTransactionDO != null) { - xid = globalTransactionDO.getXid(); - } - List branchTransactionDOs = new ArrayList<>(); - if (withBranchSessions) { - branchTransactionDOs = this.readBranchSessionByXid(jedis, xid); - } - return getGlobalSession(globalTransactionDO, branchTransactionDOs, withBranchSessions); - } - } - - - /** - * Read the branch session list by xid - * @param jedis the jedis - * @param xid the xid - * @return the branch transactionDo list - */ - private List readBranchSessionByXid(Jedis jedis, String xid) { - List branchTransactionDOs = new ArrayList<>(); - String branchListKey = buildBranchListKeyByXid(xid); - List branchKeys = lRange(jedis, branchListKey); - if (CollectionUtils.isNotEmpty(branchKeys)) { - try (Pipeline pipeline = jedis.pipelined()) { - branchKeys.stream().forEach(branchKey -> pipeline.hgetAll(branchKey)); - List branchInfos = pipeline.syncAndReturnAll(); - for (Object branchInfo : branchInfos) { - if (branchInfo != null) { - Map branchInfoMap = (Map)branchInfo; - Optional branchTransactionDO = Optional.ofNullable( - (BranchTransactionDO)BeanUtils.mapToObject(branchInfoMap, BranchTransactionDO.class)); - branchTransactionDO.ifPresent(branchTransactionDOs::add); - } - } - } - } - if (CollectionUtils.isNotEmpty(branchTransactionDOs)) { - Collections.sort(branchTransactionDOs); - } - return branchTransactionDOs; - } - - private List lRange(Jedis jedis, String key) { - List keys = new ArrayList<>(); - List values; - int limit = 20; - int start = 0; - int stop = limit; - for (;;) { - values = jedis.lrange(key, start, stop); - keys.addAll(values); - if (CollectionUtils.isEmpty(values) || values.size() < limit) { - break; - } - start = keys.size(); - stop = start + limit; - } - return keys; - } - - public List findBranchSessionByXid(String xid) { - try (Jedis jedis = JedisPooledFactory.getJedisInstance()) { - return readBranchSessionByXid(jedis, xid); - } - } - - /** - * query globalSession by page - * - * @param pageNum - * @param pageSize - * @param withBranchSessions - * @return List - */ - public List findGlobalSessionByPage(int pageNum, int pageSize, boolean withBranchSessions) { - List globalSessions = new ArrayList<>(); - int start = Math.max((pageNum - 1) * pageSize, 0); - int end = pageNum * pageSize - 1; - - List statusKeys = convertStatusKeys(GlobalStatus.values()); - Map stringLongMap = calculateStatuskeysHasData(statusKeys); - - List> list = dogetXidsForTargetMap(stringLongMap, start, end, pageSize); - - if (CollectionUtils.isNotEmpty(list)) { - List xids = list.stream().flatMap(Collection::stream).collect(Collectors.toList()); - xids.forEach(xid -> { - if (globalSessions.size() < pageSize) { - GlobalSession globalSession = this.readSession(xid, withBranchSessions); - if (globalSession != null) { - globalSessions.add(globalSession); - } - } - }); - } - return globalSessions; - } - - /** - * query and sort existing values - * - * @param statusKeys - * @return - */ - private Map calculateStatuskeysHasData(List statusKeys) { - Map resultMap = new LinkedHashMap<>(); - Map keysMap = new HashMap<>(statusKeys.size()); - try (Jedis jedis = JedisPooledFactory.getJedisInstance(); Pipeline pipelined = jedis.pipelined()) { - statusKeys.forEach(key -> pipelined.llen(key)); - List counts = (List) pipelined.syncAndReturnAll(); - for (int i = 0; i < counts.size(); i++) { - if (counts.get(i) > 0) { - keysMap.put(statusKeys.get(i), counts.get(i).intValue()); - } - } - } - - //sort - List> list = new ArrayList<>(keysMap.entrySet()); - list.sort((o1, o2) -> o2.getValue() - o1.getValue()); - list.forEach(e -> resultMap.put(e.getKey(), e.getValue())); - - return resultMap; - } - - /** - * count GlobalSession total by status - * - * @param values - * @return Long - */ - public Long countByGlobalSessions(GlobalStatus[] values) { - List statusKeys = new ArrayList<>(); - Long total = 0L; - for (GlobalStatus status : values) { - statusKeys.add(buildGlobalStatus(status.getCode())); - } - try (Jedis jedis = JedisPooledFactory.getJedisInstance(); Pipeline pipelined = jedis.pipelined()) { - statusKeys.stream().forEach(statusKey -> pipelined.llen(statusKey)); - List list = (List)(List)pipelined.syncAndReturnAll(); - if (list.size() > 0) { - total = list.stream().mapToLong(value -> value).sum(); - } - return total; - } - } - - private List convertStatusKeys(GlobalStatus... statuses) { - List statusKeys = new ArrayList<>(); - for (int i = 0; i < statuses.length; i++) { - statusKeys.add(buildGlobalStatus(statuses[i].getCode())); - } - return statusKeys; - } - - private void dogetXidsForTargetMapRecursive(Map targetMap, long start, long end, - long queryCount, List> listList) { - - long total = listList.stream().mapToLong(List::size).sum(); - - if (total >= queryCount) { - return; - } - // when start greater than offset(totalCount) - if (start >= queryCount) { - return; - } - - if (targetMap.size() == 0) { - return; - } - - try (Jedis jedis = JedisPooledFactory.getJedisInstance()) { - Iterator> iterator = targetMap.entrySet().iterator(); - while (iterator.hasNext()) { - String key = iterator.next().getKey(); - final long sum = listList.stream().mapToLong(List::size).sum(); - final long diffCount = queryCount - sum; - if (diffCount <= 0) { - return; - } - List list; - if (end - start >= diffCount) { - long endNew = start + diffCount - 1; - list = jedis.lrange(key, start, endNew); - } else { - list = jedis.lrange(key, start, end); - } - - if (list.size() > 0) { - listList.add(list); - } else { - iterator.remove(); - } - } - } - long startNew = end + 1; - long endNew = startNew + end - start; - dogetXidsForTargetMapRecursive(targetMap, startNew, endNew, queryCount, listList); - } - - private List> dogetXidsForTargetMap(Map targetMap, int start, int end, - int totalCount) { - List> listList = new ArrayList<>(); - try (Jedis jedis = JedisPooledFactory.getJedisInstance()) { - for (String key : targetMap.keySet()) { - final List list = jedis.lrange(key, start, end); - final long sum = listList.stream().mapToLong(List::size).sum(); - if (list.size() > 0 && sum < totalCount) { - listList.add(list); - } else { - start = 0; - end = totalCount - 1; - } - } - } - return listList; - } - - private String buildBranchListKeyByXid(String xid) { - return REDIS_SEATA_BRANCHES_PREFIX + xid; - } - - private String buildGlobalKeyByTransactionId(Object transactionId) { - return REDIS_SEATA_GLOBAL_PREFIX + transactionId; - } - - private String buildBranchKey(Long branchId) { - return REDIS_SEATA_BRANCH_PREFIX + branchId; - } - - private String buildGlobalStatus(Integer status) { - return REDIS_SEATA_STATUS_PREFIX + status; - } - - /** - * Sets log query limit. - * - * @param logQueryLimit the log query limit - */ - public void setLogQueryLimit(int logQueryLimit) { - this.logQueryLimit = logQueryLimit; - } - -} diff --git a/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/store/AbstractTransactionStoreManager.java b/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/store/AbstractTransactionStoreManager.java deleted file mode 100644 index 3595a72c..00000000 --- a/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/store/AbstractTransactionStoreManager.java +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright 1999-2019 Seata.io Group. - * - * Licensed 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 io.seata.server.store; - -import io.seata.core.model.GlobalStatus; -import io.seata.server.session.GlobalSession; -import io.seata.server.session.SessionCondition; - -import java.util.Collections; -import java.util.List; - -/** - * The type Abstract transaction store manager. - * - * @author zhangsen - */ -public abstract class AbstractTransactionStoreManager implements TransactionStoreManager { - - @Override - public GlobalSession readSession(String xid) { - return null; - } - - @Override - public GlobalSession readSession(String xid, boolean withBranchSessions) { - return null; - } - - @Override - public List readSortByTimeoutBeginSessions(boolean withBranchSessions) { - return Collections.emptyList(); - } - - @Override - public List readSession(GlobalStatus[] statuses, boolean withBranchSessions) { - return Collections.emptyList(); - } - - @Override - public List readSession(SessionCondition sessionCondition) { - return Collections.emptyList(); - } - - @Override - public void shutdown() { - } -} diff --git a/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/store/DbcpDataSourceProvider.java b/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/store/DbcpDataSourceProvider.java deleted file mode 100644 index 3d6fc5c9..00000000 --- a/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/store/DbcpDataSourceProvider.java +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright 1999-2019 Seata.io Group. - * - * Licensed 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 io.seata.server.store; - -import io.seata.common.loader.LoadLevel; -import io.seata.core.store.db.AbstractDataSourceProvider; -import org.apache.commons.dbcp2.BasicDataSource; - -import javax.sql.DataSource; -import java.sql.Connection; - -/** - * The dbcp datasource provider - * @author zhangsen - * @author ggndnn - * @author will - */ -@LoadLevel(name = "dbcp") -public class DbcpDataSourceProvider extends AbstractDataSourceProvider { - - @Override - public DataSource generate() { - BasicDataSource ds = new BasicDataSource(); - ds.setDriverClassName(getDriverClassName()); - // DriverClassLoader works if upgrade commons-dbcp to at least 1.3.1. - // https://issues.apache.org/jira/browse/DBCP-333 - ds.setDriverClassLoader(getDriverClassLoader()); - ds.setUrl(getUrl()); - ds.setUsername(getUser()); - - ds.setPassword(getPassword()); - ds.setInitialSize(getMinConn()); - ds.setMaxTotal(getMaxConn()); - ds.setMinIdle(getMinConn()); - ds.setMaxIdle(getMinConn()); - ds.setMaxWaitMillis(getMaxWait()); - ds.setTimeBetweenEvictionRunsMillis(120000); - ds.setNumTestsPerEvictionRun(1); - ds.setTestWhileIdle(true); - ds.setValidationQuery(getValidationQuery(getDBType())); - ds.setConnectionProperties("useUnicode=yes;characterEncoding=utf8;socketTimeout=5000;connectTimeout=500"); - ds.setDefaultTransactionIsolation(Connection.TRANSACTION_READ_COMMITTED); - return ds; - } -} diff --git a/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/store/DruidDataSourceProvider.java b/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/store/DruidDataSourceProvider.java deleted file mode 100644 index ad09895b..00000000 --- a/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/store/DruidDataSourceProvider.java +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright 1999-2019 Seata.io Group. - * - * Licensed 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 io.seata.server.store; - -import com.alibaba.druid.pool.DruidDataSource; -import io.seata.common.loader.LoadLevel; -import io.seata.core.store.db.AbstractDataSourceProvider; - -import javax.sql.DataSource; -import java.sql.Connection; - -/** - * The druid datasource provider - * @author zhangsen - * @author ggndnn - * @author will - */ -@LoadLevel(name = "druid") -public class DruidDataSourceProvider extends AbstractDataSourceProvider { - - @Override - public DataSource generate() { - DruidDataSource ds = new DruidDataSource(); - ds.setDriverClassName(getDriverClassName()); - ds.setDriverClassLoader(getDriverClassLoader()); - ds.setUrl(getUrl()); - ds.setUsername(getUser()); - ds.setPassword(getPassword()); - ds.setInitialSize(getMinConn()); - ds.setMaxActive(getMaxConn()); - ds.setMinIdle(getMinConn()); - ds.setMaxWait(getMaxWait()); - ds.setTimeBetweenEvictionRunsMillis(120000); - ds.setMinEvictableIdleTimeMillis(300000); - ds.setTestWhileIdle(true); - ds.setTestOnBorrow(false); - ds.setPoolPreparedStatements(true); - ds.setMaxPoolPreparedStatementPerConnectionSize(20); - ds.setValidationQuery(getValidationQuery(getDBType())); - ds.setDefaultAutoCommit(true); - // fix issue 5030 - ds.setUseOracleImplicitCache(false); - ds.setDefaultTransactionIsolation(Connection.TRANSACTION_READ_COMMITTED); - return ds; - } -} diff --git a/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/store/HikariDataSourceProvider.java b/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/store/HikariDataSourceProvider.java deleted file mode 100644 index 60eb0d43..00000000 --- a/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/store/HikariDataSourceProvider.java +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright 1999-2019 Seata.io Group. - * - * Licensed 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 io.seata.server.store; - -import com.zaxxer.hikari.HikariConfig; -import com.zaxxer.hikari.HikariDataSource; -import com.zaxxer.hikari.util.IsolationLevel; -import io.seata.common.loader.LoadLevel; -import io.seata.core.store.db.AbstractDataSourceProvider; - -import javax.sql.DataSource; -import java.util.Properties; - -/** - * The hikari datasource provider - * @author diguage - * @author will - */ -@LoadLevel(name = "hikari") -public class HikariDataSourceProvider extends AbstractDataSourceProvider { - - @Override - public DataSource generate() { - Properties properties = new Properties(); - properties.setProperty("dataSource.cachePrepStmts", "true"); - properties.setProperty("dataSource.prepStmtCacheSize", "250"); - properties.setProperty("dataSource.prepStmtCacheSqlLimit", "2048"); - properties.setProperty("dataSource.useServerPrepStmts", "true"); - properties.setProperty("dataSource.useLocalSessionState", "true"); - properties.setProperty("dataSource.rewriteBatchedStatements", "true"); - properties.setProperty("dataSource.cacheResultSetMetadata", "true"); - properties.setProperty("dataSource.cacheServerConfiguration", "true"); - properties.setProperty("dataSource.elideSetAutoCommits", "true"); - properties.setProperty("dataSource.maintainTimeStats", "false"); - - HikariConfig config = new HikariConfig(properties); - config.setDriverClassName(getDriverClassName()); - config.setJdbcUrl(getUrl()); - config.setUsername(getUser()); - config.setPassword(getPassword()); - config.setMaximumPoolSize(getMaxConn()); - config.setMinimumIdle(getMinConn()); - config.setAutoCommit(true); - config.setConnectionTimeout(getMaxWait()); - config.setInitializationFailTimeout(-1); - config.setTransactionIsolation(IsolationLevel.TRANSACTION_READ_COMMITTED.name()); - return new HikariDataSource(config); - } -} diff --git a/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/store/SessionStorable.java b/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/store/SessionStorable.java deleted file mode 100644 index cdcebeb0..00000000 --- a/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/store/SessionStorable.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright 1999-2019 Seata.io Group. - * - * Licensed 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 io.seata.server.store; - -/** - * The interface Session storable. - * - * @author slievrly - */ -public interface SessionStorable { - - /** - * Encode byte [ ]. - * - * @return the byte [ ] - */ - byte[] encode(); - - /** - * Decode. - * - * @param src the src - */ - void decode(byte[] src); -} diff --git a/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/store/StoreConfig.java b/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/store/StoreConfig.java deleted file mode 100644 index 362c7992..00000000 --- a/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/store/StoreConfig.java +++ /dev/null @@ -1,248 +0,0 @@ -/* - * Copyright 1999-2019 Seata.io Group. - * - * Licensed 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 io.seata.server.store; - -import io.seata.common.util.StringUtils; -import io.seata.config.Configuration; -import io.seata.config.ConfigurationFactory; -import io.seata.core.constants.ConfigurationKeys; -import io.seata.server.env.ContainerHelper; -import io.seata.server.storage.file.FlushDiskMode; - -import static io.seata.common.DefaultValues.SERVER_DEFAULT_STORE_MODE; -import static io.seata.core.constants.ConfigurationKeys.STORE_FILE_PREFIX; - -/** - * @author lizhao - */ -public class StoreConfig { - - private static final Configuration CONFIGURATION = ConfigurationFactory.getInstance(); - private static StoreMode storeMode; - private static SessionMode sessionMode; - private static LockMode lockMode; - - /** - * set storeMode sessionMode lockMode from StartupParameter - * - * @param storeMode storeMode - * @param sessionMode sessionMode - * @param lockMode lockMode - */ - public static void setStartupParameter(String storeMode, String sessionMode, String lockMode) { - if (StringUtils.isNotBlank(storeMode)) { - StoreConfig.storeMode = StoreMode.get(storeMode); - } - if (StringUtils.isNotBlank(sessionMode)) { - StoreConfig.sessionMode = SessionMode.get(sessionMode); - } - if (StringUtils.isNotBlank(lockMode)) { - StoreConfig.lockMode = LockMode.get(lockMode); - } - } - - /** - * Default 16kb. - */ - private static final int DEFAULT_MAX_BRANCH_SESSION_SIZE = 1024 * 16; - - /** - * Default 512b. - */ - private static final int DEFAULT_MAX_GLOBAL_SESSION_SIZE = 512; - - /** - * Default 16kb. - */ - private static final int DEFAULT_WRITE_BUFFER_SIZE = 1024 * 16; - - public static int getMaxBranchSessionSize() { - return CONFIGURATION.getInt(STORE_FILE_PREFIX + "maxBranchSessionSize", DEFAULT_MAX_BRANCH_SESSION_SIZE); - } - - public static int getMaxGlobalSessionSize() { - return CONFIGURATION.getInt(STORE_FILE_PREFIX + "maxGlobalSessionSize", DEFAULT_MAX_GLOBAL_SESSION_SIZE); - } - - public static int getFileWriteBufferCacheSize() { - return CONFIGURATION.getInt(STORE_FILE_PREFIX + "fileWriteBufferCacheSize", DEFAULT_WRITE_BUFFER_SIZE); - } - - public static FlushDiskMode getFlushDiskMode() { - return FlushDiskMode.findDiskMode(CONFIGURATION.getConfig(STORE_FILE_PREFIX + "flushDiskMode")); - } - - /** - * only for inner call - * - * @return - */ - private static StoreMode getStoreMode() { - //startup - if (null != storeMode) { - return storeMode; - } - //env - String storeModeEnv = ContainerHelper.getStoreMode(); - if (StringUtils.isNotBlank(storeModeEnv)) { - return StoreMode.get(storeModeEnv); - } - //config - String storeModeConfig = CONFIGURATION.getConfig(ConfigurationKeys.STORE_MODE, SERVER_DEFAULT_STORE_MODE); - return StoreMode.get(storeModeConfig); - } - - public static SessionMode getSessionMode() { - //startup - if (null != sessionMode) { - return sessionMode; - } - //env - String sessionModeEnv = ContainerHelper.getSessionStoreMode(); - if (StringUtils.isNotBlank(sessionModeEnv)) { - return SessionMode.get(sessionModeEnv); - } - //config - String sessionModeConfig = CONFIGURATION.getConfig(ConfigurationKeys.STORE_SESSION_MODE); - if (StringUtils.isNotBlank(sessionModeConfig)) { - return SessionMode.get(sessionModeConfig); - } - // complication old config - return SessionMode.get(getStoreMode().name()); - } - - public static LockMode getLockMode() { - //startup - if (null != lockMode) { - return lockMode; - } - //env - String lockModeEnv = ContainerHelper.getLockStoreMode(); - if (StringUtils.isNotBlank(lockModeEnv)) { - return LockMode.get(lockModeEnv); - } - //config - String lockModeConfig = CONFIGURATION.getConfig(ConfigurationKeys.STORE_LOCK_MODE); - if (StringUtils.isNotBlank(lockModeConfig)) { - return LockMode.get(lockModeConfig); - } - // complication old config - return LockMode.get(getStoreMode().name()); - } - - public enum StoreMode { - /** - * The File store mode. - */ - FILE("file"), - /** - * The Db store mode. - */ - DB("db"), - /** - * The Redis store mode. - */ - REDIS("redis"); - - private String name; - - StoreMode(String name) { - this.name = name; - } - - public String getName() { - return name; - } - - public static StoreMode get(String name) { - for (StoreMode mode : StoreMode.values()) { - if (mode.getName().equalsIgnoreCase(name)) { - return mode; - } - } - throw new IllegalArgumentException("unknown store mode:" + name); - } - } - - public enum SessionMode { - /** - * The File store mode. - */ - FILE("file"), - /** - * The Db store mode. - */ - DB("db"), - /** - * The Redis store mode. - */ - REDIS("redis"); - - private String name; - - SessionMode(String name) { - this.name = name; - } - - public String getName() { - return name; - } - - public static SessionMode get(String name) { - for (SessionMode mode : SessionMode.values()) { - if (mode.getName().equalsIgnoreCase(name)) { - return mode; - } - } - throw new IllegalArgumentException("unknown session mode:" + name); - } - } - - public enum LockMode { - /** - * The File store mode. - */ - FILE("file"), - /** - * The Db store mode. - */ - DB("db"), - /** - * The Redis store mode. - */ - REDIS("redis"); - - private String name; - - LockMode(String name) { - this.name = name; - } - - public String getName() { - return name; - } - - public static LockMode get(String name) { - for (LockMode mode : LockMode.values()) { - if (mode.getName().equalsIgnoreCase(name)) { - return mode; - } - } - throw new IllegalArgumentException("unknown lock mode:" + name); - } - } - -} diff --git a/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/store/TransactionStoreManager.java b/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/store/TransactionStoreManager.java deleted file mode 100644 index 2fb6473b..00000000 --- a/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/store/TransactionStoreManager.java +++ /dev/null @@ -1,148 +0,0 @@ -/* - * Copyright 1999-2019 Seata.io Group. - * - * Licensed 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 io.seata.server.store; - -import io.seata.core.model.GlobalStatus; -import io.seata.server.session.GlobalSession; -import io.seata.server.session.SessionCondition; - -import java.util.List; - -/** - * The interface Transaction store manager. - * - * @author slievrly - */ -public interface TransactionStoreManager { - - /** - * Write session boolean. - * - * @param logOperation the log operation - * @param session the session - * @return the boolean - */ - boolean writeSession(LogOperation logOperation, SessionStorable session); - - - /** - * Read global session global session. - * - * @param xid the xid - * @return the global session - */ - GlobalSession readSession(String xid); - - /** - * Read session global session. - * - * @param xid the xid - * @param withBranchSessions the withBranchSessions - * @return the global session - */ - GlobalSession readSession(String xid, boolean withBranchSessions); - - /** - * Read session global session by sort by timeout begin status. - * - * @param withBranchSessions the withBranchSessions - * @return the global session - */ - List readSortByTimeoutBeginSessions(boolean withBranchSessions); - /** - * Read session global session. - * - * @param statuses the statuses - * @param withBranchSessions the withBranchSessions - * @return the global session list - */ - List readSession(GlobalStatus[] statuses, boolean withBranchSessions); - - /** - * Read session by status list. - * - * @param sessionCondition the session condition - * @return the list - */ - List readSession(SessionCondition sessionCondition); - - /** - * Shutdown. - */ - void shutdown(); - - - /** - * The enum Log operation. - */ - enum LogOperation { - - /** - * Global add log operation. - */ - GLOBAL_ADD((byte)1), - /** - * Global update log operation. - */ - GLOBAL_UPDATE((byte)2), - /** - * Global remove log operation. - */ - GLOBAL_REMOVE((byte)3), - /** - * Branch add log operation. - */ - BRANCH_ADD((byte)4), - /** - * Branch update log operation. - */ - BRANCH_UPDATE((byte)5), - /** - * Branch remove log operation. - */ - BRANCH_REMOVE((byte)6); - - private byte code; - - LogOperation(byte code) { - this.code = code; - } - - /** - * Gets code. - * - * @return the code - */ - public byte getCode() { - return this.code; - } - - /** - * Gets log operation by code. - * - * @param code the code - * @return the log operation by code - */ - public static LogOperation getLogOperationByCode(byte code) { - for (LogOperation temp : values()) { - if (temp.getCode() == code) { - return temp; - } - } - throw new IllegalArgumentException("Unknown LogOperation[" + code + "]"); - } - } -} diff --git a/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/transaction/at/ATCore.java b/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/transaction/at/ATCore.java deleted file mode 100644 index da318240..00000000 --- a/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/transaction/at/ATCore.java +++ /dev/null @@ -1,104 +0,0 @@ -/* - * Copyright 1999-2019 Seata.io Group. - * - * Licensed 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 io.seata.server.transaction.at; - -import com.fasterxml.jackson.databind.ObjectMapper; -import io.seata.common.exception.StoreException; -import io.seata.common.util.StringUtils; -import io.seata.core.exception.BranchTransactionException; -import io.seata.core.exception.TransactionException; -import io.seata.core.model.BranchType; -import io.seata.core.rpc.RemotingServer; -import io.seata.server.coordinator.AbstractCore; -import io.seata.server.session.BranchSession; -import io.seata.server.session.GlobalSession; - -import java.io.IOException; -import java.util.HashMap; -import java.util.Map; - -import static io.seata.common.Constants.AUTO_COMMIT; -import static io.seata.common.Constants.SKIP_CHECK_LOCK; -import static io.seata.core.exception.TransactionExceptionCode.LockKeyConflict; - -/** - * The type at core. - * - * @author ph3636 - */ -public class ATCore extends AbstractCore { - - private final ObjectMapper objectMapper = new ObjectMapper(); - - public ATCore(RemotingServer remotingServer) { - super(remotingServer); - } - - @Override - public BranchType getHandleBranchType() { - return BranchType.AT; - } - - @Override - protected void branchSessionLock(GlobalSession globalSession, BranchSession branchSession) - throws TransactionException { - String applicationData = branchSession.getApplicationData(); - boolean autoCommit = true; - boolean skipCheckLock = false; - if (StringUtils.isNotBlank(applicationData)) { - try { - Map data = objectMapper.readValue(applicationData, HashMap.class); - Object clientAutoCommit = data.get(AUTO_COMMIT); - if (clientAutoCommit != null && !(boolean)clientAutoCommit) { - autoCommit = (boolean)clientAutoCommit; - } - Object clientSkipCheckLock = data.get(SKIP_CHECK_LOCK); - if (clientSkipCheckLock instanceof Boolean) { - skipCheckLock = (boolean)clientSkipCheckLock; - } - } catch (IOException e) { - LOGGER.error("failed to get application data: {}", e.getMessage(), e); - } - } - try { - if (!branchSession.lock(autoCommit, skipCheckLock)) { - throw new BranchTransactionException(LockKeyConflict, - String.format("Global lock acquire failed xid = %s branchId = %s", globalSession.getXid(), - branchSession.getBranchId())); - } - } catch (StoreException e) { - Throwable cause = e.getCause(); - if (cause instanceof BranchTransactionException) { - throw new BranchTransactionException(((BranchTransactionException)cause).getCode(), - String.format("Global lock acquire failed xid = %s branchId = %s", globalSession.getXid(), - branchSession.getBranchId())); - } - throw e; - } - } - - @Override - protected void branchSessionUnlock(BranchSession branchSession) throws TransactionException { - branchSession.unlock(); - } - - @Override - public boolean lockQuery(BranchType branchType, String resourceId, String xid, String lockKeys) - throws TransactionException { - return lockManager.isLockable(xid, resourceId, lockKeys); - } - -} diff --git a/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/transaction/saga/SagaCore.java b/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/transaction/saga/SagaCore.java deleted file mode 100644 index f57cd6a5..00000000 --- a/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/transaction/saga/SagaCore.java +++ /dev/null @@ -1,230 +0,0 @@ -/* - * Copyright 1999-2019 Seata.io Group. - * - * Licensed 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 io.seata.server.transaction.saga; - -import io.netty.channel.Channel; -import io.seata.common.util.CollectionUtils; -import io.seata.core.exception.GlobalTransactionException; -import io.seata.core.exception.TransactionException; -import io.seata.core.model.BranchStatus; -import io.seata.core.model.BranchType; -import io.seata.core.model.GlobalStatus; -import io.seata.core.protocol.transaction.BranchCommitRequest; -import io.seata.core.protocol.transaction.BranchCommitResponse; -import io.seata.core.protocol.transaction.BranchRollbackRequest; -import io.seata.core.protocol.transaction.BranchRollbackResponse; -import io.seata.core.rpc.RemotingServer; -import io.seata.core.rpc.netty.ChannelManager; -import io.seata.server.coordinator.AbstractCore; -import io.seata.server.session.BranchSession; -import io.seata.server.session.GlobalSession; -import io.seata.server.session.SessionHelper; -import io.seata.server.session.SessionHolder; - -import java.io.IOException; -import java.util.Map; -import java.util.concurrent.TimeoutException; - -/** - * The type saga core. - * - * @author ph3636 - */ -public class SagaCore extends AbstractCore { - - public SagaCore(RemotingServer remotingServer) { - super(remotingServer); - } - - @Override - public BranchType getHandleBranchType() { - return BranchType.SAGA; - } - - @Override - public void globalSessionStatusCheck(GlobalSession globalSession) throws GlobalTransactionException { - // SAGA type accept forward(retry) operation on timeout or commit fail, forward operation will register remaining branches - } - - @Override - public BranchStatus branchCommitSend(BranchCommitRequest request, GlobalSession globalSession, - BranchSession branchSession) throws IOException, TimeoutException { - Map channels = ChannelManager.getRmChannels(); - if (CollectionUtils.isEmpty(channels)) { - LOGGER.error("Failed to commit SAGA global[" + globalSession.getXid() + ", RM channels is empty."); - return BranchStatus.PhaseTwo_CommitFailed_Retryable; - } - String sagaResourceId = getSagaResourceId(globalSession); - Channel sagaChannel = channels.get(sagaResourceId); - if (sagaChannel == null) { - LOGGER.error("Failed to commit SAGA global[" + globalSession.getXid() - + ", cannot find channel by resourceId[" + sagaResourceId + "]"); - return BranchStatus.PhaseTwo_CommitFailed_Retryable; - } - BranchCommitResponse response = (BranchCommitResponse) remotingServer.sendSyncRequest(sagaChannel, request); - return response.getBranchStatus(); - } - - @Override - public BranchStatus branchRollbackSend(BranchRollbackRequest request, GlobalSession globalSession, - BranchSession branchSession) throws IOException, TimeoutException { - Map channels = ChannelManager.getRmChannels(); - if (CollectionUtils.isEmpty(channels)) { - LOGGER.error("Failed to rollback SAGA global[" + globalSession.getXid() + ", RM channels is empty."); - return BranchStatus.PhaseTwo_RollbackFailed_Retryable; - } - String sagaResourceId = getSagaResourceId(globalSession); - Channel sagaChannel = channels.get(sagaResourceId); - if (sagaChannel == null) { - LOGGER.error("Failed to rollback SAGA global[" + globalSession.getXid() - + ", cannot find channel by resourceId[" + sagaResourceId + "]"); - return BranchStatus.PhaseTwo_RollbackFailed_Retryable; - } - BranchRollbackResponse response = (BranchRollbackResponse) remotingServer.sendSyncRequest(sagaChannel, request); - return response.getBranchStatus(); - } - - @Override - public boolean doGlobalCommit(GlobalSession globalSession, boolean retrying) throws TransactionException { - try { - BranchStatus branchStatus = branchCommit(globalSession, SessionHelper.newBranch(BranchType.SAGA, - globalSession.getXid(), -1, getSagaResourceId(globalSession), globalSession.getStatus().name())); - - switch (branchStatus) { - case PhaseTwo_Committed: - SessionHelper.removeAllBranch(globalSession, !retrying); - LOGGER.info("Successfully committed SAGA global[" + globalSession.getXid() + "]"); - break; - case PhaseTwo_Rollbacked: - LOGGER.info("Successfully rollbacked SAGA global[" + globalSession.getXid() + "]"); - SessionHelper.removeAllBranch(globalSession, !retrying); - SessionHelper.endRollbacked(globalSession, retrying); - return false; - case PhaseTwo_RollbackFailed_Retryable: - LOGGER.error("By [{}], failed to rollback SAGA global [{}], will retry later.", branchStatus, - globalSession.getXid()); - SessionHolder.getRetryCommittingSessionManager().removeGlobalSession(globalSession); - globalSession.queueToRetryRollback(); - return false; - case PhaseOne_Failed: - LOGGER.error("By [{}], finish SAGA global [{}]", branchStatus, globalSession.getXid()); - SessionHelper.removeAllBranch(globalSession, !retrying); - globalSession.changeGlobalStatus(GlobalStatus.Finished); - globalSession.end(); - return false; - case PhaseTwo_CommitFailed_Unretryable: - if (globalSession.canBeCommittedAsync()) { - LOGGER.error("By [{}], failed to commit SAGA global [{}]", branchStatus, - globalSession.getXid()); - break; - } else { - SessionHelper.endCommitFailed(globalSession,retrying); - LOGGER.error("Finally, failed to commit SAGA global[{}]", globalSession.getXid()); - return false; - } - default: - if (!retrying) { - globalSession.queueToRetryCommit(); - } else { - LOGGER.error("Failed to commit SAGA global[{}], will retry later.", globalSession.getXid()); - } - return false; - } - } catch (Exception ex) { - LOGGER.error("Failed to commit global[" + globalSession.getXid() + "]", ex); - - if (!retrying) { - globalSession.queueToRetryRollback(); - } - throw new TransactionException(ex); - } - return true; - } - - @Override - public boolean doGlobalRollback(GlobalSession globalSession, boolean retrying) throws TransactionException { - try { - BranchStatus branchStatus = branchRollback(globalSession, SessionHelper.newBranch(BranchType.SAGA, - globalSession.getXid(), -1, getSagaResourceId(globalSession), globalSession.getStatus().name())); - - switch (branchStatus) { - case PhaseTwo_Rollbacked: - SessionHelper.removeAllBranch(globalSession, !retrying); - LOGGER.info("Successfully rollbacked SAGA global[{}]",globalSession.getXid()); - break; - case PhaseTwo_RollbackFailed_Unretryable: - SessionHelper.endRollbackFailed(globalSession, retrying); - LOGGER.error("Failed to rollback SAGA global[{}]", globalSession.getXid()); - return false; - case PhaseTwo_CommitFailed_Retryable: - SessionHolder.getRetryRollbackingSessionManager().removeGlobalSession(globalSession); - globalSession.queueToRetryCommit(); - LOGGER.warn("Retry by custom recover strategy [Forward] on timeout, SAGA global[{}]", globalSession.getXid()); - return false; - default: - LOGGER.error("Failed to rollback SAGA global[{}]", globalSession.getXid()); - if (!retrying) { - globalSession.queueToRetryRollback(); - } - return false; - } - } catch (Exception ex) { - LOGGER.error("Failed to rollback global[{}]", globalSession.getXid(), ex); - if (!retrying) { - globalSession.queueToRetryRollback(); - } - throw new TransactionException(ex); - } - return true; - } - - @Override - public void doGlobalReport(GlobalSession globalSession, String xid, GlobalStatus globalStatus) throws TransactionException { - if (GlobalStatus.Committed.equals(globalStatus)) { - SessionHelper.removeAllBranch(globalSession, false); - SessionHelper.endCommitted(globalSession, false); - LOGGER.info("Global[{}] committed", globalSession.getXid()); - } else if (GlobalStatus.Rollbacked.equals(globalStatus) - || GlobalStatus.Finished.equals(globalStatus)) { - SessionHelper.removeAllBranch(globalSession, false); - SessionHelper.endRollbacked(globalSession, false); - LOGGER.info("Global[{}] rollbacked", globalSession.getXid()); - } else { - globalSession.changeGlobalStatus(globalStatus); - LOGGER.info("Global[{}] reporting is successfully done. status[{}]", globalSession.getXid(), globalSession.getStatus()); - - if (GlobalStatus.RollbackRetrying.equals(globalStatus) - || GlobalStatus.TimeoutRollbackRetrying.equals(globalStatus) - || GlobalStatus.UnKnown.equals(globalStatus)) { - globalSession.queueToRetryRollback(); - LOGGER.info("Global[{}] will retry rollback", globalSession.getXid()); - } else if (GlobalStatus.CommitRetrying.equals(globalStatus)) { - globalSession.queueToRetryCommit(); - LOGGER.info("Global[{}] will retry commit", globalSession.getXid()); - } - } - } - - /** - * get saga ResourceId - * - * @param globalSession the globalSession - * @return sagaResourceId - */ - private String getSagaResourceId(GlobalSession globalSession) { - return globalSession.getApplicationId() + "#" + globalSession.getTransactionServiceGroup(); - } -} diff --git a/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/transaction/tcc/TccCore.java b/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/transaction/tcc/TccCore.java deleted file mode 100644 index e0171aa5..00000000 --- a/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/transaction/tcc/TccCore.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright 1999-2019 Seata.io Group. - * - * Licensed 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 io.seata.server.transaction.tcc; - -import io.seata.core.model.BranchType; -import io.seata.core.rpc.RemotingServer; -import io.seata.server.coordinator.AbstractCore; - -/** - * The type tcc core. - * - * @author ph3636 - */ -public class TccCore extends AbstractCore { - - public TccCore(RemotingServer remotingServer) { - super(remotingServer); - } - - @Override - public BranchType getHandleBranchType() { - return BranchType.TCC; - } -} diff --git a/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/transaction/xa/XACore.java b/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/transaction/xa/XACore.java deleted file mode 100644 index de4620d4..00000000 --- a/ruoyi-visual/ruoyi-seata-server/src/main/java/io/seata/server/transaction/xa/XACore.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright 1999-2019 Seata.io Group. - * - * Licensed 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 io.seata.server.transaction.xa; - -import io.seata.core.exception.TransactionException; -import io.seata.core.model.BranchStatus; -import io.seata.core.model.BranchType; -import io.seata.core.rpc.RemotingServer; -import io.seata.server.coordinator.AbstractCore; - -/** - * The type XA core. - * - * @author sharajava - */ -public class XACore extends AbstractCore { - - public XACore(RemotingServer remotingServer) { - super(remotingServer); - } - - @Override - public BranchType getHandleBranchType() { - return BranchType.XA; - } - - @Override - public void branchReport(BranchType branchType, String xid, long branchId, BranchStatus status, - String applicationData) throws TransactionException { - super.branchReport(branchType, xid, branchId, status, applicationData); - if (BranchStatus.PhaseOne_Failed == status) { - - } - } -} diff --git a/ruoyi-visual/ruoyi-seata-server/src/main/resources/META-INF/native-image/io.seata/server/reflect-config.json b/ruoyi-visual/ruoyi-seata-server/src/main/resources/META-INF/native-image/io.seata/server/reflect-config.json deleted file mode 100644 index 9d762dfb..00000000 --- a/ruoyi-visual/ruoyi-seata-server/src/main/resources/META-INF/native-image/io.seata/server/reflect-config.json +++ /dev/null @@ -1,362 +0,0 @@ -[ - { - "condition": { - "typeReachable": "io.seata.core.rpc.RegisterCheckAuthHandler" - }, - "name": "io.seata.server.auth.DefaultCheckAuthHandler", - "methods": [ - { - "name": "", - "parameterTypes": [] - } - ] - }, - { - "condition": { - "typeReachable": "io.seata.core.store.db.DataSourceProvider" - }, - "name": "io.seata.server.store.DbcpDataSourceProvider", - "methods": [ - { - "name": "", - "parameterTypes": [] - } - ] - }, - { - "condition": { - "typeReachable": "io.seata.core.store.db.DataSourceProvider" - }, - "name": "io.seata.server.store.DruidDataSourceProvider", - "methods": [ - { - "name": "", - "parameterTypes": [] - } - ] - }, - { - "condition": { - "typeReachable": "io.seata.core.store.db.DataSourceProvider" - }, - "name": "io.seata.server.store.HikariDataSourceProvider", - "methods": [ - { - "name": "", - "parameterTypes": [] - } - ] - }, - { - "condition": { - "typeReachable": "io.seata.core.store.DistributedLocker" - }, - "name": "io.seata.server.storage.redis.lock.RedisDistributedLocker", - "methods": [ - { - "name": "", - "parameterTypes": [] - } - ] - }, - { - "condition": { - "typeReachable": "io.seata.core.store.DistributedLocker" - }, - "name": "io.seata.server.storage.db.lock.DataBaseDistributedLocker", - "methods": [ - { - "name": "", - "parameterTypes": [] - } - ] - }, - { - "condition": { - "typeReachable": "io.seata.server.coordinator.AbstractCore" - }, - "name": "io.seata.server.transaction.at.ATCore", - "methods": [ - { - "name": "", - "parameterTypes": [ - "io.seata.core.rpc.RemotingServer" - ] - } - ] - }, - { - "condition": { - "typeReachable": "io.seata.server.coordinator.AbstractCore" - }, - "name": "io.seata.server.transaction.tcc.TccCore", - "methods": [ - { - "name": "", - "parameterTypes": [ - "io.seata.core.rpc.RemotingServer" - ] - } - ] - }, - { - "condition": { - "typeReachable": "io.seata.server.coordinator.AbstractCore" - }, - "name": "io.seata.server.transaction.saga.SagaCore", - "methods": [ - { - "name": "", - "parameterTypes": [ - "io.seata.core.rpc.RemotingServer" - ] - } - ] - }, - { - "condition": { - "typeReachable": "io.seata.server.coordinator.AbstractCore" - }, - "name": "io.seata.server.transaction.xa.XACore", - "methods": [ - { - "name": "", - "parameterTypes": [ - "io.seata.core.rpc.RemotingServer" - ] - } - ] - }, - { - "condition": { - "typeReachable": "io.seata.server.lock.LockManager" - }, - "name": "io.seata.server.storage.db.lock.DataBaseLockManager", - "methods": [ - { - "name": "", - "parameterTypes": [] - } - ] - }, - { - "condition": { - "typeReachable": "io.seata.server.lock.LockManager" - }, - "name": "io.seata.server.storage.file.lock.FileLockManager", - "methods": [ - { - "name": "", - "parameterTypes": [] - } - ] - }, - { - "condition": { - "typeReachable": "io.seata.server.lock.LockManager" - }, - "name": "io.seata.server.storage.redis.lock.RedisLockManager", - "methods": [ - { - "name": "", - "parameterTypes": [] - } - ] - }, - { - "condition": { - "typeReachable": "io.seata.server.session.SessionManager" - }, - "name": "io.seata.server.storage.file.session.FileSessionManager", - "methods": [ - { - "name": "", - "parameterTypes": [ - "java.lang.String", - "java.lang.String" - ] - } - ] - }, - { - "condition": { - "typeReachable": "io.seata.server.session.SessionManager" - }, - "name": "io.seata.server.storage.db.session.DataBaseSessionManager", - "methods": [ - { - "name": "", - "parameterTypes": [] - }, - { - "name": "", - "parameterTypes": [ - "java.lang.String" - ] - } - ] - }, - { - "condition": { - "typeReachable": "io.seata.server.session.SessionManager" - }, - "name": "io.seata.server.storage.redis.session.RedisSessionManager", - "methods": [ - { - "name": "", - "parameterTypes": [] - }, - { - "name": "", - "parameterTypes": [ - "java.lang.String" - ] - } - ] - }, - { - "condition": { - "typeReachable": "com.google.inject.internal.TypeConverterBindingProcessor" - }, - "name": "java.lang.Integer", - "methods": [ - { - "name": "parseInteger", - "parameterTypes": [ - "java.lang.String" - ] - } - ] - }, - { - "condition": { - "typeReachable": "com.google.inject.internal.TypeConverterBindingProcessor" - }, - "name": "java.lang.Long", - "methods": [ - { - "name": "parseLong", - "parameterTypes": [ - "java.lang.String" - ] - } - ] - }, - { - "condition": { - "typeReachable": "com.google.inject.internal.TypeConverterBindingProcessor" - }, - "name": "java.lang.Boolean", - "methods": [ - { - "name": "parseBoolean", - "parameterTypes": [ - "java.lang.String" - ] - } - ] - }, - { - "condition": { - "typeReachable": "com.google.inject.internal.TypeConverterBindingProcessor" - }, - "name": "java.lang.Byte", - "methods": [ - { - "name": "parseByte", - "parameterTypes": [ - "java.lang.String" - ] - } - ] - }, - { - "condition": { - "typeReachable": "com.google.inject.internal.TypeConverterBindingProcessor" - }, - "name": "java.lang.Short", - "methods": [ - { - "name": "parseShort", - "parameterTypes": [ - "java.lang.String" - ] - } - ] - }, - { - "condition": { - "typeReachable": "com.google.inject.internal.TypeConverterBindingProcessor" - }, - "name": "java.lang.Float", - "methods": [ - { - "name": "parseFloat", - "parameterTypes": [ - "java.lang.String" - ] - } - ] - }, - { - "condition": { - "typeReachable": "com.google.inject.internal.TypeConverterBindingProcessor" - }, - "name": "java.lang.Double", - "methods": [ - { - "name": "parseDouble", - "parameterTypes": [ - "java.lang.String" - ] - } - ] - }, - { - "condition": { - "typeReachable": "io.netty.channel.socket.nio.SelectorProviderUtil" - }, - "name": "java.nio.channels.spi.SelectorProvider", - "methods": [ - { - "name": "openServerSocketChannel", - "parameterTypes": [ - "java.net.ProtocolFamily" - ] - } - ] - }, - { - "condition": { - "typeReachable": "io.netty.channel.DefaultChannelConfig" - }, - "name": "io.netty.buffer.ByteBufAllocator" - }, - { - "condition": { - "typeReachable": "io.netty.channel.DefaultChannelConfig" - }, - "name": "io.netty.buffer.ByteBufUtil" - }, - { - "condition": { - "typeReachable": "io.netty.util.ResourceLeakDetector" - }, - "name": "io.netty.buffer.AbstractByteBufAllocator", - "allDeclaredMethods": true - }, - { - "condition": { - "typeReachable": "io.netty.util.ResourceLeakDetector" - }, - "name": "io.netty.buffer.AdvancedLeakAwareByteBuf", - "allDeclaredMethods": true - }, - { - "condition": { - "typeReachable": "io.netty.util.ResourceLeakDetector" - }, - "name": "io.netty.util.ReferenceCountUtil", - "allDeclaredMethods": true - } -] \ No newline at end of file diff --git a/ruoyi-visual/ruoyi-seata-server/src/main/resources/META-INF/native-image/io.seata/server/resource-config.json b/ruoyi-visual/ruoyi-seata-server/src/main/resources/META-INF/native-image/io.seata/server/resource-config.json deleted file mode 100644 index 73b72ff3..00000000 --- a/ruoyi-visual/ruoyi-seata-server/src/main/resources/META-INF/native-image/io.seata/server/resource-config.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "resources": { - "includes": [ - { - "pattern": "\\Qlogback\/\\E.*" - }, - { - "pattern": "\\Qlua\/redislocker\/redislock.lua\\E" - }, - { - "pattern": "\\Qapplication.yml\\E" - }, - { - "pattern": "\\Qbanner.txt\\E" - }, - { - "pattern": "\\Qlogback-spring.xml\\E" - } - ] - } -} \ No newline at end of file diff --git a/ruoyi-visual/ruoyi-seata-server/src/main/resources/META-INF/services/io.seata.core.rpc.RegisterCheckAuthHandler b/ruoyi-visual/ruoyi-seata-server/src/main/resources/META-INF/services/io.seata.core.rpc.RegisterCheckAuthHandler deleted file mode 100644 index 1a54728b..00000000 --- a/ruoyi-visual/ruoyi-seata-server/src/main/resources/META-INF/services/io.seata.core.rpc.RegisterCheckAuthHandler +++ /dev/null @@ -1 +0,0 @@ -io.seata.server.auth.DefaultCheckAuthHandler \ No newline at end of file diff --git a/ruoyi-visual/ruoyi-seata-server/src/main/resources/META-INF/services/io.seata.core.store.DistributedLocker b/ruoyi-visual/ruoyi-seata-server/src/main/resources/META-INF/services/io.seata.core.store.DistributedLocker deleted file mode 100644 index 874e8b91..00000000 --- a/ruoyi-visual/ruoyi-seata-server/src/main/resources/META-INF/services/io.seata.core.store.DistributedLocker +++ /dev/null @@ -1,2 +0,0 @@ -io.seata.server.storage.redis.lock.RedisDistributedLocker -io.seata.server.storage.db.lock.DataBaseDistributedLocker \ No newline at end of file diff --git a/ruoyi-visual/ruoyi-seata-server/src/main/resources/META-INF/services/io.seata.core.store.db.DataSourceProvider b/ruoyi-visual/ruoyi-seata-server/src/main/resources/META-INF/services/io.seata.core.store.db.DataSourceProvider deleted file mode 100644 index ac04a85e..00000000 --- a/ruoyi-visual/ruoyi-seata-server/src/main/resources/META-INF/services/io.seata.core.store.db.DataSourceProvider +++ /dev/null @@ -1,3 +0,0 @@ -io.seata.server.store.DbcpDataSourceProvider -io.seata.server.store.DruidDataSourceProvider -io.seata.server.store.HikariDataSourceProvider \ No newline at end of file diff --git a/ruoyi-visual/ruoyi-seata-server/src/main/resources/META-INF/services/io.seata.server.coordinator.AbstractCore b/ruoyi-visual/ruoyi-seata-server/src/main/resources/META-INF/services/io.seata.server.coordinator.AbstractCore deleted file mode 100644 index a80662b0..00000000 --- a/ruoyi-visual/ruoyi-seata-server/src/main/resources/META-INF/services/io.seata.server.coordinator.AbstractCore +++ /dev/null @@ -1,4 +0,0 @@ -io.seata.server.transaction.at.ATCore -io.seata.server.transaction.tcc.TccCore -io.seata.server.transaction.saga.SagaCore -io.seata.server.transaction.xa.XACore \ No newline at end of file diff --git a/ruoyi-visual/ruoyi-seata-server/src/main/resources/META-INF/services/io.seata.server.lock.LockManager b/ruoyi-visual/ruoyi-seata-server/src/main/resources/META-INF/services/io.seata.server.lock.LockManager deleted file mode 100644 index bca40c85..00000000 --- a/ruoyi-visual/ruoyi-seata-server/src/main/resources/META-INF/services/io.seata.server.lock.LockManager +++ /dev/null @@ -1,3 +0,0 @@ -io.seata.server.storage.db.lock.DataBaseLockManager -io.seata.server.storage.file.lock.FileLockManager -io.seata.server.storage.redis.lock.RedisLockManager \ No newline at end of file diff --git a/ruoyi-visual/ruoyi-seata-server/src/main/resources/META-INF/services/io.seata.server.session.SessionManager b/ruoyi-visual/ruoyi-seata-server/src/main/resources/META-INF/services/io.seata.server.session.SessionManager deleted file mode 100644 index f2e82316..00000000 --- a/ruoyi-visual/ruoyi-seata-server/src/main/resources/META-INF/services/io.seata.server.session.SessionManager +++ /dev/null @@ -1,3 +0,0 @@ -io.seata.server.storage.file.session.FileSessionManager -io.seata.server.storage.db.session.DataBaseSessionManager -io.seata.server.storage.redis.session.RedisSessionManager \ No newline at end of file diff --git a/ruoyi-visual/ruoyi-seata-server/src/main/resources/META-INF/spring-configuration-metadata.json b/ruoyi-visual/ruoyi-seata-server/src/main/resources/META-INF/spring-configuration-metadata.json deleted file mode 100644 index 05449177..00000000 --- a/ruoyi-visual/ruoyi-seata-server/src/main/resources/META-INF/spring-configuration-metadata.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "groups": [], - "properties": [ - { - "name": "logging.extend.kafka-appender.bootstrap-servers", - "type": "java.lang.String", - "defaultValue": "localhost:9092" - }, - { - "name": "logging.extend.kafka-appender.topic", - "type": "java.lang.String", - "defaultValue": "logback_to_logstash" - }, - { - "name": "logging.extend.logstash-appender.destination", - "type": "java.lang.String", - "defaultValue": "localhost:4560" - } - ], - "hints": [ - ] -} \ No newline at end of file diff --git a/ruoyi-visual/ruoyi-seata-server/src/main/resources/META-INF/spring.factories b/ruoyi-visual/ruoyi-seata-server/src/main/resources/META-INF/spring.factories deleted file mode 100644 index 3384008b..00000000 --- a/ruoyi-visual/ruoyi-seata-server/src/main/resources/META-INF/spring.factories +++ /dev/null @@ -1,4 +0,0 @@ -org.springframework.context.ApplicationListener=\ -io.seata.server.spring.listener.ServerApplicationListener -org.springframework.context.ApplicationContextInitializer=\ -io.seata.server.spring.listener.SeataPropertiesLoader \ No newline at end of file diff --git a/ruoyi-visual/ruoyi-seata-server/src/main/resources/README-zh.md b/ruoyi-visual/ruoyi-seata-server/src/main/resources/README-zh.md deleted file mode 100644 index 05d1620e..00000000 --- a/ruoyi-visual/ruoyi-seata-server/src/main/resources/README-zh.md +++ /dev/null @@ -1,32 +0,0 @@ -# 脚本说明 - -## [client](https://github.com/seata/seata/tree/develop/script/client) - -> 存放用于客户端的配置和SQL - -- at: AT模式下的 `undo_log` 建表语句 -- conf: 客户端的配置文件 -- saga: SAGA 模式下所需表的建表语句 -- spring: SpringBoot 应用支持的配置文件 - -## [server](https://github.com/seata/seata/tree/develop/script/server) - -> 存放server侧所需SQL和部署脚本 - -- db: server 侧的保存模式为 `db` 时所需表的建表语句 -- docker-compose: server 侧通过 docker-compose 部署的脚本 -- helm: server 侧通过 Helm 部署的脚本 -- kubernetes: server 侧通过 Kubernetes 部署的脚本 - -## [config-center](https://github.com/seata/seata/tree/develop/script/config-center) - -> 用于存放各种配置中心的初始化脚本,执行时都会读取 `config.txt`配置文件,并写入配置中心 - -- nacos: 用于向 Nacos 中添加配置 -- zk: 用于向 Zookeeper 中添加配置,脚本依赖 Zookeeper 的相关脚本,需要手动下载;ZooKeeper相关的配置可以写在 `zk-params.txt` 中,也可以在执行的时候输入 -- apollo: 向 Apollo 中添加配置,Apollo 的地址端口等可以写在 `apollo-params.txt`,也可以在执行的时候输入 -- etcd3: 用于向 Etcd3 中添加配置 -- consul: 用于向 consul 中添加配置 - -## 打包 -./mvnw -Prelease-seata -Dmaven.test.skip=true clean install -U diff --git a/ruoyi-visual/ruoyi-seata-server/src/main/resources/README.md b/ruoyi-visual/ruoyi-seata-server/src/main/resources/README.md deleted file mode 100644 index ddabd559..00000000 --- a/ruoyi-visual/ruoyi-seata-server/src/main/resources/README.md +++ /dev/null @@ -1,33 +0,0 @@ -# Script Description - -## [client](https://github.com/seata/seata/tree/develop/script/client) - -> Store configuration and SQL for client side - -- at: Script of create table `undo_log` for AT mode. -- conf: Configuration which client need. -- saga: Script of create table in SAGA mode -- spring: Configuration for Spring Boot - -## [server](https://github.com/seata/seata/tree/develop/script/server) - -> Store SQL and deploy script for server side - -- db: Create table script for server when store mode is `db` -- docker-compose: Script for deploy server by docker-compose -- helm: Script for deploy server by Helm -- kubernetes: Script for deploy server by Kubernetes - -## [config-center](https://github.com/seata/seata/tree/develop/script/config-center) - -> Store initialize script for configuration center, will use `config.txt` as configuration when initial - -- nacos: Initialize script for Nacos -- zk: Initialize script for ZooKeeper, the script need related script in Zookeeper, you need download yourself. You can modify `zk-params.txt` to change the ZooKeeper server configuration, or input when execute also -- apollo: Initialize script for Apollo. You can modify `apollo-params.txt` to change the Apollo server configuration, or input when execute also -- etcd3: Initialize script for Etcd3 -- consul: Initialize script for consul - -## build packege -./mvnw -Prelease-seata -Dmaven.test.skip=true clean install -U - diff --git a/ruoyi-visual/ruoyi-seata-server/src/main/resources/redislocker/redislock.lua b/ruoyi-visual/ruoyi-seata-server/src/main/resources/redislocker/redislock.lua deleted file mode 100644 index b004408c..00000000 --- a/ruoyi-visual/ruoyi-seata-server/src/main/resources/redislocker/redislock.lua +++ /dev/null @@ -1,52 +0,0 @@ --- --- User: tianyu.li --- Date: 2021/1/19 --- --- init data -local array = {}; local result; local keySize = ARGV[1]; local argSize = ARGV[2]; --- Loop through all keys to see if they can be used , when a key is not available, exit -for i= 1, keySize do - -- search lock xid - result = redis.call('HGET',KEYS[i],'xid'); - -- if lock xid is nil - if (not result) - -- set 'no' mean There is need to store lock information - then array[i]='no' - else - if (result ~= ARGV[3]) - then - -- return fail - return result - else - -- set 'yes' mean There is not need to store lock information - array[i]= 'yes' - end - end -end --- Loop through array -for i =1, keySize do - -- if is no ,The lock information is stored - if(array[i] == 'no') - then - -- set xid - redis.call('HSET',KEYS[i],'xid',ARGV[3]); - -- set transactionId - redis.call('HSET',KEYS[i],'transactionId',ARGV[(i-1)*6+4]); - -- set branchId - redis.call('HSET',KEYS[i],'branchId',ARGV[(i-1)*6+5]); - -- set resourceId - redis.call('HSET',KEYS[i],'resourceId',ARGV[(i-1)*6+6]); - -- set tableName - redis.call('HSET',KEYS[i],'tableName',ARGV[(i-1)*6+7]); - -- set rowKey - redis.call('HSET',KEYS[i],'rowKey',ARGV[(i-1)*6+8]); - -- set pk - redis.call('HSET',KEYS[i],'pk',ARGV[(i-1)*6+9]); - -- exit if - end --- exit for -end --- set SEATA_GLOBAL_LOCK -redis.call('HSET',KEYS[(keySize+1)],KEYS[(keySize+2)],ARGV[(argSize+0)]); --- return success -return ARGV[3] diff --git a/ruoyi-visual/ruoyi-sentinel-dashboard/pom.xml b/ruoyi-visual/ruoyi-sentinel-dashboard/pom.xml index 9ad640d3..3b064aa4 100644 --- a/ruoyi-visual/ruoyi-sentinel-dashboard/pom.xml +++ b/ruoyi-visual/ruoyi-sentinel-dashboard/pom.xml @@ -80,21 +80,12 @@ org.springframework.boot spring-boot-starter-web - - spring-boot-starter-tomcat - org.springframework.boot - * org.apache.logging.log4j - - - org.springframework.boot - spring-boot-starter-undertow - diff --git a/ruoyi-visual/ruoyi-sentinel-dashboard/src/main/java/com/alibaba/csp/sentinel/dashboard/filter/ActuatorAuthFilter.java b/ruoyi-visual/ruoyi-sentinel-dashboard/src/main/java/com/alibaba/csp/sentinel/dashboard/filter/ActuatorAuthFilter.java new file mode 100644 index 00000000..715af041 --- /dev/null +++ b/ruoyi-visual/ruoyi-sentinel-dashboard/src/main/java/com/alibaba/csp/sentinel/dashboard/filter/ActuatorAuthFilter.java @@ -0,0 +1,63 @@ +package com.alibaba.csp.sentinel.dashboard.filter; + +import javax.servlet.*; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.util.Base64; + +public class ActuatorAuthFilter implements Filter { + + private final String username; + private final String password; + + public ActuatorAuthFilter(String username, String password) { + this.username = username; + this.password = password; + } + + @Override + public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { + HttpServletRequest request = (HttpServletRequest) servletRequest; + HttpServletResponse response = (HttpServletResponse) servletResponse; + + // 获取 Authorization 头 + String authHeader = request.getHeader("Authorization"); + + if (authHeader == null || !authHeader.startsWith("Basic ")) { + // 如果没有提供 Authorization 或者格式不对,则返回 401 + response.setHeader("WWW-Authenticate", "Basic realm=\"realm\""); + response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Unauthorized"); + return; + } + + // 解码 Base64 编码的用户名和密码 + String base64Credentials = authHeader.substring("Basic ".length()); + byte[] credDecoded = Base64.getDecoder().decode(base64Credentials); + String credentials = new String(credDecoded, StandardCharsets.UTF_8); + String[] split = credentials.split(":"); + if (split.length != 2) { + response.setHeader("WWW-Authenticate", "Basic realm=\"realm\""); + response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Unauthorized"); + return; + } + // 验证用户名和密码 + if (!username.equals(split[0]) && password.equals(split[1])) { + response.setHeader("WWW-Authenticate", "Basic realm=\"realm\""); + response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Unauthorized"); + return; + } + // 如果认证成功,继续处理请求 + filterChain.doFilter(request, response); + } + + @Override + public void init(FilterConfig filterConfig) { + } + + @Override + public void destroy() { + } + +} diff --git a/ruoyi-visual/ruoyi-sentinel-dashboard/src/main/java/com/alibaba/csp/sentinel/dashboard/filter/SecurityConfig.java b/ruoyi-visual/ruoyi-sentinel-dashboard/src/main/java/com/alibaba/csp/sentinel/dashboard/filter/SecurityConfig.java new file mode 100644 index 00000000..2bed7dbd --- /dev/null +++ b/ruoyi-visual/ruoyi-sentinel-dashboard/src/main/java/com/alibaba/csp/sentinel/dashboard/filter/SecurityConfig.java @@ -0,0 +1,29 @@ +package com.alibaba.csp.sentinel.dashboard.filter; + +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.web.servlet.FilterRegistrationBean; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +/** + * 权限安全配置 + * + * @author Lion Li + */ +@Configuration +public class SecurityConfig { + + @Value("${spring.cloud.nacos.discovery.metadata.username}") + private String username; + @Value("${spring.cloud.nacos.discovery.metadata.userpassword}") + private String password; + + @Bean + public FilterRegistrationBean actuatorFilterRegistrationBean() { + FilterRegistrationBean registrationBean = new FilterRegistrationBean<>(); + registrationBean.setFilter(new ActuatorAuthFilter(username, password)); + registrationBean.addUrlPatterns("/actuator", "/actuator/**"); + return registrationBean; + } + +} diff --git a/ruoyi-visual/ruoyi-snailjob-server/src/main/java/com/aizuda/snailjob/server/starter/config/ActuatorAuthFilter.java b/ruoyi-visual/ruoyi-snailjob-server/src/main/java/com/aizuda/snailjob/server/starter/config/ActuatorAuthFilter.java new file mode 100644 index 00000000..799b8ab5 --- /dev/null +++ b/ruoyi-visual/ruoyi-snailjob-server/src/main/java/com/aizuda/snailjob/server/starter/config/ActuatorAuthFilter.java @@ -0,0 +1,64 @@ +package com.aizuda.snailjob.server.starter.config; + +import jakarta.servlet.*; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; + +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.util.Base64; + +public class ActuatorAuthFilter implements Filter { + + private final String username; + private final String password; + + public ActuatorAuthFilter(String username, String password) { + this.username = username; + this.password = password; + } + + @Override + public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { + HttpServletRequest request = (HttpServletRequest) servletRequest; + HttpServletResponse response = (HttpServletResponse) servletResponse; + + // 获取 Authorization 头 + String authHeader = request.getHeader("Authorization"); + + if (authHeader == null || !authHeader.startsWith("Basic ")) { + // 如果没有提供 Authorization 或者格式不对,则返回 401 + response.setHeader("WWW-Authenticate", "Basic realm=\"realm\""); + response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Unauthorized"); + return; + } + + // 解码 Base64 编码的用户名和密码 + String base64Credentials = authHeader.substring("Basic ".length()); + byte[] credDecoded = Base64.getDecoder().decode(base64Credentials); + String credentials = new String(credDecoded, StandardCharsets.UTF_8); + String[] split = credentials.split(":"); + if (split.length != 2) { + response.setHeader("WWW-Authenticate", "Basic realm=\"realm\""); + response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Unauthorized"); + return; + } + // 验证用户名和密码 + if (!username.equals(split[0]) && password.equals(split[1])) { + response.setHeader("WWW-Authenticate", "Basic realm=\"realm\""); + response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Unauthorized"); + return; + } + // 如果认证成功,继续处理请求 + filterChain.doFilter(request, response); + } + + @Override + public void init(FilterConfig filterConfig) { + } + + @Override + public void destroy() { + } + +} diff --git a/ruoyi-visual/ruoyi-snailjob-server/src/main/java/com/aizuda/snailjob/server/starter/config/SecurityConfig.java b/ruoyi-visual/ruoyi-snailjob-server/src/main/java/com/aizuda/snailjob/server/starter/config/SecurityConfig.java new file mode 100644 index 00000000..7b8f5640 --- /dev/null +++ b/ruoyi-visual/ruoyi-snailjob-server/src/main/java/com/aizuda/snailjob/server/starter/config/SecurityConfig.java @@ -0,0 +1,29 @@ +package com.aizuda.snailjob.server.starter.config; + +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.web.servlet.FilterRegistrationBean; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +/** + * 权限安全配置 + * + * @author Lion Li + */ +@Configuration +public class SecurityConfig { + + @Value("${spring.cloud.nacos.discovery.metadata.username}") + private String username; + @Value("${spring.cloud.nacos.discovery.metadata.userpassword}") + private String password; + + @Bean + public FilterRegistrationBean actuatorFilterRegistrationBean() { + FilterRegistrationBean registrationBean = new FilterRegistrationBean<>(); + registrationBean.setFilter(new ActuatorAuthFilter(username, password)); + registrationBean.addUrlPatterns("/actuator", "/actuator/**"); + return registrationBean; + } + +} diff --git a/ruoyi-visual/ruoyi-snailjob-server/src/main/resources/application.yml b/ruoyi-visual/ruoyi-snailjob-server/src/main/resources/application.yml index 69295f3a..4ce70334 100644 --- a/ruoyi-visual/ruoyi-snailjob-server/src/main/resources/application.yml +++ b/ruoyi-visual/ruoyi-snailjob-server/src/main/resources/application.yml @@ -50,9 +50,6 @@ spring: # 注册组 group: @nacos.discovery.group@ namespace: ${spring.profiles.active} - metadata: - # 解决 er 服务有 context-path 无法监控问题 - management.context-path: ${server.servlet.context-path}/actuator config: # 配置组 group: @nacos.config.group@ diff --git a/sql/oracle/oracle_ry_job.sql b/sql/oracle/oracle_ry_job.sql index 8a620410..d2e17c1f 100644 --- a/sql/oracle/oracle_ry_job.sql +++ b/sql/oracle/oracle_ry_job.sql @@ -2,7 +2,7 @@ SnailJob Database Transfer Tool Source Server Type : MySQL Target Server Type : Oracle - Date: 2024-05-14 23:36:38 + Date: 2024-07-06 12:49:36 */ @@ -136,7 +136,7 @@ CREATE INDEX idx_sj_notify_recipient_01 ON sj_notify_recipient (namespace_id); COMMENT ON COLUMN sj_notify_recipient.id IS '主键'; COMMENT ON COLUMN sj_notify_recipient.namespace_id IS '命名空间id'; COMMENT ON COLUMN sj_notify_recipient.recipient_name IS '接收人名称'; -COMMENT ON COLUMN sj_notify_recipient.notify_type IS '通知类型 1、钉钉 2、邮件 3、企业微信 4 飞书'; +COMMENT ON COLUMN sj_notify_recipient.notify_type IS '通知类型 1、钉钉 2、邮件 3、企业微信 4 飞书 5 webhook'; COMMENT ON COLUMN sj_notify_recipient.notify_attribute IS '配置属性'; COMMENT ON COLUMN sj_notify_recipient.description IS '描述'; COMMENT ON COLUMN sj_notify_recipient.create_dt IS '创建时间'; @@ -296,8 +296,8 @@ CREATE TABLE sj_retry_task_log_message ALTER TABLE sj_retry_task_log_message ADD CONSTRAINT pk_sj_retry_task_log_message PRIMARY KEY (id); -CREATE INDEX idx_sj_retry_task_log_message_01 ON sj_retry_task_log_message (namespace_id, group_name, unique_id); -CREATE INDEX idx_sj_retry_task_log_message_02 ON sj_retry_task_log_message (create_dt); +CREATE INDEX idx_sj_rt_log_message_01 ON sj_retry_task_log_message (namespace_id, group_name, unique_id); +CREATE INDEX idx_sj_rt_log_message_02 ON sj_retry_task_log_message (create_dt); COMMENT ON COLUMN sj_retry_task_log_message.id IS '主键'; COMMENT ON COLUMN sj_retry_task_log_message.namespace_id IS '命名空间id'; @@ -389,8 +389,7 @@ COMMENT ON TABLE sj_server_node IS '服务器节点'; -- sj_distributed_lock CREATE TABLE sj_distributed_lock ( - id number GENERATED ALWAYS AS IDENTITY, - name varchar2(64) NULL, + name varchar2(64) NOT NULL, lock_until timestamp(3) DEFAULT CURRENT_TIMESTAMP(3) NOT NULL, locked_at timestamp(3) DEFAULT CURRENT_TIMESTAMP(3) NOT NULL, locked_by varchar2(255) NULL, @@ -399,9 +398,8 @@ CREATE TABLE sj_distributed_lock ); ALTER TABLE sj_distributed_lock - ADD CONSTRAINT pk_sj_distributed_lock PRIMARY KEY (id); + ADD CONSTRAINT pk_sj_distributed_lock PRIMARY KEY (name); -COMMENT ON COLUMN sj_distributed_lock.id IS '主键'; COMMENT ON COLUMN sj_distributed_lock.name IS '锁名称'; COMMENT ON COLUMN sj_distributed_lock.lock_until IS '锁定时长'; COMMENT ON COLUMN sj_distributed_lock.locked_at IS '锁定时间'; @@ -449,7 +447,7 @@ CREATE TABLE sj_system_user_permission ALTER TABLE sj_system_user_permission ADD CONSTRAINT pk_sj_system_user_permission PRIMARY KEY (id); -CREATE UNIQUE INDEX uk_sj_system_user_permission_01 ON sj_system_user_permission (namespace_id, group_name, system_user_id); +CREATE UNIQUE INDEX uk_sj_su_permission_01 ON sj_system_user_permission (namespace_id, group_name, system_user_id); COMMENT ON COLUMN sj_system_user_permission.id IS '主键'; COMMENT ON COLUMN sj_system_user_permission.group_name IS '组名称'; @@ -598,7 +596,11 @@ CREATE TABLE sj_job_task parent_id number DEFAULT 0 NOT NULL, task_status smallint DEFAULT 0 NOT NULL, retry_count number DEFAULT 0 NOT NULL, + mr_stage smallint DEFAULT NULL NULL, + leaf smallint DEFAULT '1' NOT NULL, + task_name varchar2(255) DEFAULT '' NULL, client_info varchar2(128) DEFAULT NULL NULL, + wf_context clob DEFAULT NULL NULL, result_message clob NULL, args_str clob DEFAULT NULL NULL, args_type smallint DEFAULT 1 NOT NULL, @@ -622,7 +624,11 @@ COMMENT ON COLUMN sj_job_task.task_batch_id IS '调度任务id'; COMMENT ON COLUMN sj_job_task.parent_id IS '父执行器id'; COMMENT ON COLUMN sj_job_task.task_status IS '执行的状态 0、失败 1、成功'; COMMENT ON COLUMN sj_job_task.retry_count IS '重试次数'; +COMMENT ON COLUMN sj_job_task.mr_stage IS '动态分片所处阶段 1:map 2:reduce 3:mergeReduce'; +COMMENT ON COLUMN sj_job_task.leaf IS '叶子节点'; +COMMENT ON COLUMN sj_job_task.task_name IS '任务名称'; COMMENT ON COLUMN sj_job_task.client_info IS '客户端地址 clientId#ip:port'; +COMMENT ON COLUMN sj_job_task.wf_context IS '工作流全局上下文'; COMMENT ON COLUMN sj_job_task.result_message IS '执行结果'; COMMENT ON COLUMN sj_job_task.args_str IS '执行方法参数'; COMMENT ON COLUMN sj_job_task.args_type IS '参数类型 '; @@ -773,6 +779,7 @@ CREATE TABLE sj_workflow executor_timeout number DEFAULT 0 NOT NULL, description varchar2(256) DEFAULT '' NULL, flow_info clob DEFAULT NULL NULL, + wf_context clob DEFAULT NULL NULL, bucket_index number DEFAULT 0 NOT NULL, version number NOT NULL, ext_attrs varchar2(256) DEFAULT '' NULL, @@ -799,6 +806,7 @@ COMMENT ON COLUMN sj_workflow.block_strategy IS '阻塞策略 1、丢弃 2、覆 COMMENT ON COLUMN sj_workflow.executor_timeout IS '任务执行超时时间,单位秒'; COMMENT ON COLUMN sj_workflow.description IS '描述'; COMMENT ON COLUMN sj_workflow.flow_info IS '流程信息'; +COMMENT ON COLUMN sj_workflow.wf_context IS '上下文'; COMMENT ON COLUMN sj_workflow.bucket_index IS 'bucket'; COMMENT ON COLUMN sj_workflow.version IS '版本号'; COMMENT ON COLUMN sj_workflow.ext_attrs IS '扩展字段'; @@ -864,8 +872,10 @@ CREATE TABLE sj_workflow_task_batch task_batch_status smallint DEFAULT 0 NOT NULL, operation_reason smallint DEFAULT 0 NOT NULL, flow_info clob DEFAULT NULL NULL, + wf_context clob DEFAULT NULL NULL, execution_at number DEFAULT 0 NOT NULL, ext_attrs varchar2(256) DEFAULT '' NULL, + version number DEFAULT 1 NOT NULL, deleted smallint DEFAULT 0 NOT NULL, create_dt date DEFAULT CURRENT_TIMESTAMP NOT NULL, update_dt date DEFAULT CURRENT_TIMESTAMP NOT NULL @@ -885,8 +895,10 @@ COMMENT ON COLUMN sj_workflow_task_batch.workflow_id IS '工作流任务id'; COMMENT ON COLUMN sj_workflow_task_batch.task_batch_status IS '任务批次状态 0、失败 1、成功'; COMMENT ON COLUMN sj_workflow_task_batch.operation_reason IS '操作原因'; COMMENT ON COLUMN sj_workflow_task_batch.flow_info IS '流程信息'; +COMMENT ON COLUMN sj_workflow_task_batch.wf_context IS '全局上下文'; COMMENT ON COLUMN sj_workflow_task_batch.execution_at IS '任务执行时间'; COMMENT ON COLUMN sj_workflow_task_batch.ext_attrs IS '扩展字段'; +COMMENT ON COLUMN sj_workflow_task_batch.version IS '版本号'; COMMENT ON COLUMN sj_workflow_task_batch.deleted IS '逻辑删除 1、删除'; COMMENT ON COLUMN sj_workflow_task_batch.create_dt IS '创建时间'; COMMENT ON COLUMN sj_workflow_task_batch.update_dt IS '修改时间'; diff --git a/sql/postgres/postgres_ry_job.sql b/sql/postgres/postgres_ry_job.sql index 30a871e7..3bed8a27 100644 --- a/sql/postgres/postgres_ry_job.sql +++ b/sql/postgres/postgres_ry_job.sql @@ -2,7 +2,7 @@ SnailJob Database Transfer Tool Source Server Type : MySQL Target Server Type : PostgreSQL - Date: 2024-05-13 22:49:34 + Date: 2024-07-06 11:45:40 */ @@ -124,7 +124,7 @@ CREATE INDEX idx_sj_notify_recipient_01 ON sj_notify_recipient (namespace_id); COMMENT ON COLUMN sj_notify_recipient.id IS '主键'; COMMENT ON COLUMN sj_notify_recipient.namespace_id IS '命名空间id'; COMMENT ON COLUMN sj_notify_recipient.recipient_name IS '接收人名称'; -COMMENT ON COLUMN sj_notify_recipient.notify_type IS '通知类型 1、钉钉 2、邮件 3、企业微信 4 飞书'; +COMMENT ON COLUMN sj_notify_recipient.notify_type IS '通知类型 1、钉钉 2、邮件 3、企业微信 4 飞书 5 webhook'; COMMENT ON COLUMN sj_notify_recipient.notify_attribute IS '配置属性'; COMMENT ON COLUMN sj_notify_recipient.description IS '描述'; COMMENT ON COLUMN sj_notify_recipient.create_dt IS '创建时间'; @@ -359,8 +359,7 @@ COMMENT ON TABLE sj_server_node IS '服务器节点'; -- sj_distributed_lock CREATE TABLE sj_distributed_lock ( - id bigserial PRIMARY KEY, - name varchar(64) NOT NULL, + name varchar(64) PRIMARY KEY, lock_until timestamp(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3), locked_at timestamp(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3), locked_by varchar(255) NOT NULL, @@ -368,7 +367,6 @@ CREATE TABLE sj_distributed_lock update_dt timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ); -COMMENT ON COLUMN sj_distributed_lock.id IS '主键'; COMMENT ON COLUMN sj_distributed_lock.name IS '锁名称'; COMMENT ON COLUMN sj_distributed_lock.lock_until IS '锁定时长'; COMMENT ON COLUMN sj_distributed_lock.locked_at IS '锁定时间'; @@ -550,7 +548,11 @@ CREATE TABLE sj_job_task parent_id bigint NOT NULL DEFAULT 0, task_status smallint NOT NULL DEFAULT 0, retry_count int NOT NULL DEFAULT 0, + mr_stage smallint NULL DEFAULT NULL, + leaf smallint NOT NULL DEFAULT '1', + task_name varchar(255) NOT NULL DEFAULT '', client_info varchar(128) NULL DEFAULT NULL, + wf_context text NULL DEFAULT NULL, result_message text NOT NULL, args_str text NULL DEFAULT NULL, args_type smallint NOT NULL DEFAULT 1, @@ -571,7 +573,11 @@ COMMENT ON COLUMN sj_job_task.task_batch_id IS '调度任务id'; COMMENT ON COLUMN sj_job_task.parent_id IS '父执行器id'; COMMENT ON COLUMN sj_job_task.task_status IS '执行的状态 0、失败 1、成功'; COMMENT ON COLUMN sj_job_task.retry_count IS '重试次数'; +COMMENT ON COLUMN sj_job_task.mr_stage IS '动态分片所处阶段 1:map 2:reduce 3:mergeReduce'; +COMMENT ON COLUMN sj_job_task.leaf IS '叶子节点'; +COMMENT ON COLUMN sj_job_task.task_name IS '任务名称'; COMMENT ON COLUMN sj_job_task.client_info IS '客户端地址 clientId#ip:port'; +COMMENT ON COLUMN sj_job_task.wf_context IS '工作流全局上下文'; COMMENT ON COLUMN sj_job_task.result_message IS '执行结果'; COMMENT ON COLUMN sj_job_task.args_str IS '执行方法参数'; COMMENT ON COLUMN sj_job_task.args_type IS '参数类型 '; @@ -713,6 +719,7 @@ CREATE TABLE sj_workflow executor_timeout int NOT NULL DEFAULT 0, description varchar(256) NOT NULL DEFAULT '', flow_info text NULL DEFAULT NULL, + wf_context text NULL DEFAULT NULL, bucket_index int NOT NULL DEFAULT 0, version int NOT NULL, ext_attrs varchar(256) NULL DEFAULT '', @@ -736,6 +743,7 @@ COMMENT ON COLUMN sj_workflow.block_strategy IS '阻塞策略 1、丢弃 2、覆 COMMENT ON COLUMN sj_workflow.executor_timeout IS '任务执行超时时间,单位秒'; COMMENT ON COLUMN sj_workflow.description IS '描述'; COMMENT ON COLUMN sj_workflow.flow_info IS '流程信息'; +COMMENT ON COLUMN sj_workflow.wf_context IS '上下文'; COMMENT ON COLUMN sj_workflow.bucket_index IS 'bucket'; COMMENT ON COLUMN sj_workflow.version IS '版本号'; COMMENT ON COLUMN sj_workflow.ext_attrs IS '扩展字段'; @@ -798,8 +806,10 @@ CREATE TABLE sj_workflow_task_batch task_batch_status smallint NOT NULL DEFAULT 0, operation_reason smallint NOT NULL DEFAULT 0, flow_info text NULL DEFAULT NULL, + wf_context text NULL DEFAULT NULL, execution_at bigint NOT NULL DEFAULT 0, ext_attrs varchar(256) NULL DEFAULT '', + version int NOT NULL DEFAULT 1, deleted smallint NOT NULL DEFAULT 0, create_dt timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, update_dt timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP @@ -816,8 +826,10 @@ COMMENT ON COLUMN sj_workflow_task_batch.workflow_id IS '工作流任务id'; COMMENT ON COLUMN sj_workflow_task_batch.task_batch_status IS '任务批次状态 0、失败 1、成功'; COMMENT ON COLUMN sj_workflow_task_batch.operation_reason IS '操作原因'; COMMENT ON COLUMN sj_workflow_task_batch.flow_info IS '流程信息'; +COMMENT ON COLUMN sj_workflow_task_batch.wf_context IS '全局上下文'; COMMENT ON COLUMN sj_workflow_task_batch.execution_at IS '任务执行时间'; COMMENT ON COLUMN sj_workflow_task_batch.ext_attrs IS '扩展字段'; +COMMENT ON COLUMN sj_workflow_task_batch.version IS '版本号'; COMMENT ON COLUMN sj_workflow_task_batch.deleted IS '逻辑删除 1、删除'; COMMENT ON COLUMN sj_workflow_task_batch.create_dt IS '创建时间'; COMMENT ON COLUMN sj_workflow_task_batch.update_dt IS '修改时间'; diff --git a/sql/ry-job.sql b/sql/ry-job.sql index ce93e11d..c3aa7601 100644 --- a/sql/ry-job.sql +++ b/sql/ry-job.sql @@ -68,7 +68,7 @@ CREATE TABLE `sj_notify_recipient` `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键', `namespace_id` varchar(64) NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a' COMMENT '命名空间id', `recipient_name` varchar(64) NOT NULL COMMENT '接收人名称', - `notify_type` tinyint(4) NOT NULL DEFAULT 0 COMMENT '通知类型 1、钉钉 2、邮件 3、企业微信 4 飞书', + `notify_type` tinyint(4) NOT NULL DEFAULT 0 COMMENT '通知类型 1、钉钉 2、邮件 3、企业微信 4 飞书 5 webhook', `notify_attribute` varchar(512) NOT NULL COMMENT '配置属性', `description` varchar(256) NOT NULL DEFAULT '' COMMENT '描述', `create_dt` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', @@ -222,15 +222,13 @@ CREATE TABLE `sj_server_node` CREATE TABLE `sj_distributed_lock` ( - `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键', `name` varchar(64) NOT NULL COMMENT '锁名称', `lock_until` timestamp(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3) COMMENT '锁定时长', `locked_at` timestamp(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '锁定时间', `locked_by` varchar(255) NOT NULL COMMENT '锁定者', `create_dt` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', `update_dt` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '修改时间', - PRIMARY KEY (`id`), - UNIQUE KEY `uk_name` (`name`) + PRIMARY KEY (`name`) ) ENGINE = InnoDB AUTO_INCREMENT = 0 DEFAULT CHARSET = utf8mb4 COMMENT ='锁定表'; @@ -345,12 +343,16 @@ CREATE TABLE `sj_job_task` `job_id` bigint(20) NOT NULL COMMENT '任务信息id', `task_batch_id` bigint(20) NOT NULL COMMENT '调度任务id', `parent_id` bigint(20) NOT NULL DEFAULT 0 COMMENT '父执行器id', - `task_status` tinyint(4) NOT NULL DEFAULT 0 COMMENT '执行的状态 0、失败 1、成功', + `task_status` tinyint NOT NULL DEFAULT 0 COMMENT '执行的状态 0、失败 1、成功', `retry_count` int(11) NOT NULL DEFAULT 0 COMMENT '重试次数', + `mr_stage` tinyint DEFAULT NULL COMMENT '动态分片所处阶段 1:map 2:reduce 3:mergeReduce', + `leaf` tinyint NOT NULL DEFAULT '1' COMMENT '叶子节点', + `task_name` varchar(255) NOT NULL DEFAULT '' COMMENT '任务名称', `client_info` varchar(128) DEFAULT NULL COMMENT '客户端地址 clientId#ip:port', + `wf_context` text DEFAULT NULL COMMENT '工作流全局上下文', `result_message` text NOT NULL COMMENT '执行结果', `args_str` text DEFAULT NULL COMMENT '执行方法参数', - `args_type` tinyint(4) NOT NULL DEFAULT 1 COMMENT '参数类型 ', + `args_type` tinyint NOT NULL DEFAULT 1 COMMENT '参数类型 ', `ext_attrs` varchar(256) NULL DEFAULT '' COMMENT '扩展字段', `create_dt` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', `update_dt` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间', @@ -447,6 +449,7 @@ CREATE TABLE `sj_workflow` `executor_timeout` int(11) NOT NULL DEFAULT 0 COMMENT '任务执行超时时间,单位秒', `description` varchar(256) NOT NULL DEFAULT '' COMMENT '描述', `flow_info` text DEFAULT NULL COMMENT '流程信息', + `wf_context` text DEFAULT NULL COMMENT '上下文', `bucket_index` int(11) NOT NULL DEFAULT 0 COMMENT 'bucket', `version` int(11) NOT NULL COMMENT '版本号', `ext_attrs` varchar(256) NULL DEFAULT '' COMMENT '扩展字段', @@ -495,8 +498,10 @@ CREATE TABLE `sj_workflow_task_batch` `task_batch_status` tinyint(4) NOT NULL DEFAULT 0 COMMENT '任务批次状态 0、失败 1、成功', `operation_reason` tinyint(4) NOT NULL DEFAULT 0 COMMENT '操作原因', `flow_info` text DEFAULT NULL COMMENT '流程信息', + `wf_context` text DEFAULT NULL COMMENT '全局上下文', `execution_at` bigint(13) NOT NULL DEFAULT 0 COMMENT '任务执行时间', `ext_attrs` varchar(256) NULL DEFAULT '' COMMENT '扩展字段', + `version` int(11) NOT NULL DEFAULT 1 COMMENT '版本号', `deleted` tinyint(4) NOT NULL DEFAULT 0 COMMENT '逻辑删除 1、删除', `create_dt` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', `update_dt` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间',