thingsboard-client-demo/src/main/java/com/tuoheng/status/machine/service/DrcMachineService.java

192 lines
6.0 KiB
Java
Raw Normal View History

2025-12-16 13:56:36 +08:00
package com.tuoheng.status.machine.service;
import com.tuoheng.status.machine.events.DrcEvent;
import com.tuoheng.status.machine.redis.RedisStateStore;
import com.tuoheng.status.machine.status.DrcState;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.statemachine.StateMachine;
import org.springframework.statemachine.config.StateMachineFactory;
import org.springframework.stereotype.Component;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/**
* DRC状态机管理器
* 负责管理多个机巢的DRC状态机实例
*/
@Component
public class DrcMachineService {
@Autowired
StateMachineFactory<DrcState, DrcEvent> drcStateMachineFactory;
@Autowired
private RedisStateStore redisStateStore;
/**
* 存储所有机巢的DRC状态机实例
* Key: 机巢ID (airportSn)
* Value: 状态机实例
*/
private final Map<String, StateMachine<DrcState, DrcEvent>> stateMachineMap = new ConcurrentHashMap<>();
/**
* 获取或创建状态机
* 如果状态机不存在则创建新的状态机实例
*
* @param airportSn 机巢序列号
* @return 状态机实例
*/
public StateMachine<DrcState, DrcEvent> getOrCreateStateMachine(String airportSn) {
return stateMachineMap.computeIfAbsent(airportSn, id -> {
StateMachine<DrcState, DrcEvent> stateMachine = drcStateMachineFactory.getStateMachine(id);
// 服务器重启后,状态机初始化为 UNKNOWN 状态
// 不从 Redis 恢复旧状态,等待第一次心跳同步真实状态
// 这样可以避免服务器重启期间丢失心跳导致的状态不一致问题
stateMachine.start();
System.out.println(String.format("创建并启动DRC状态机: %s, 初始状态: UNKNOWN (等待心跳同步)", id));
return stateMachine;
});
}
/**
* 获取状态机不创建
*
* @param airportSn 机巢序列号
* @return 状态机实例如果不存在返回null
*/
public StateMachine<DrcState, DrcEvent> getStateMachine(String airportSn) {
return stateMachineMap.get(airportSn);
}
/**
* 获取状态机的当前状态
*
* @param airportSn 机巢序列号
* @return 当前状态如果状态机不存在返回null
*/
public DrcState getCurrentState(String airportSn) {
StateMachine<DrcState, DrcEvent> stateMachine = stateMachineMap.get(airportSn);
if (stateMachine == null) {
System.out.println("DRC状态机不存在: " + airportSn);
return null;
}
return stateMachine.getState().getId();
}
/**
* 获取状态机的所有当前状态包括子状态
*
* @param airportSn 机巢序列号
* @return 当前状态集合的字符串表示
*/
public String getCurrentStates(String airportSn) {
StateMachine<DrcState, DrcEvent> stateMachine = stateMachineMap.get(airportSn);
if (stateMachine == null) {
return "状态机不存在";
}
StringBuilder states = new StringBuilder();
stateMachine.getState().getIds().forEach(state -> {
if (states.length() > 0) {
states.append(" -> ");
}
states.append(state);
});
return states.toString();
}
/**
* 发送事件到状态机
*
* @param airportSn 机巢序列号
* @param event 事件
* @return 是否发送成功
*/
public boolean sendEvent(String airportSn, DrcEvent event) {
StateMachine<DrcState, DrcEvent> stateMachine = getOrCreateStateMachine(airportSn);
boolean result = stateMachine.sendEvent(event);
if (result) {
// 持久化最新状态
redisStateStore.saveDrcState(airportSn, stateMachine.getState().getId());
System.out.println(String.format("DRC事件发送成功 - 机巢: %s, 事件: %s, 当前状态: %s",
airportSn, event, getCurrentStates(airportSn)));
} else {
System.out.println(String.format("DRC事件发送失败 - 机巢: %s, 事件: %s, 当前状态: %s",
airportSn, event, getCurrentStates(airportSn)));
}
return result;
}
/**
* 移除状态机
*
* @param airportSn 机巢序列号
*/
public void removeStateMachine(String airportSn) {
StateMachine<DrcState, DrcEvent> stateMachine = stateMachineMap.remove(airportSn);
if (stateMachine != null) {
stateMachine.stop();
System.out.println("停止并移除DRC状态机: " + airportSn);
}
}
/**
* 检查状态机是否存在
*
* @param airportSn 机巢序列号
* @return 是否存在
*/
public boolean hasStateMachine(String airportSn) {
return stateMachineMap.containsKey(airportSn);
}
/**
* 获取所有状态机的数量
*
* @return 状态机数量
*/
public int getStateMachineCount() {
return stateMachineMap.size();
}
/**
* 获取所有机巢ID
*
* @return 机巢ID集合
*/
public java.util.Set<String> getAllAirportIds() {
return stateMachineMap.keySet();
}
/**
* 检查状态机是否处于指定状态
*
* @param airportSn 机巢序列号
* @param state 要检查的状态
* @return 是否处于指定状态
*/
public boolean isInState(String airportSn, DrcState state) {
StateMachine<DrcState, DrcEvent> stateMachine = stateMachineMap.get(airportSn);
if (stateMachine == null) {
return false;
}
return stateMachine.getState().getIds().contains(state);
}
/**
* 重启状态机
*
* @param airportSn 机巢序列号
*/
public void restartStateMachine(String airportSn) {
removeStateMachine(airportSn);
getOrCreateStateMachine(airportSn);
System.out.println("重启DRC状态机: " + airportSn);
}
}