diff --git a/MULTI_PLATFORM_ARCHITECTURE.md b/MULTI_PLATFORM_ARCHITECTURE.md new file mode 100644 index 0000000..7d91375 --- /dev/null +++ b/MULTI_PLATFORM_ARCHITECTURE.md @@ -0,0 +1,279 @@ +# 多平台机巢状态机架构说明 + +## 架构概述 + +本系统采用**策略模式 + 工厂模式**实现多平台支持,允许DJI、AUTEL、YUNEEC等不同无人机平台共存并独立运行。 + +## 核心设计 + +### 1. 平台类型枚举 (PlatformType) +``` +- DJI (大疆) +- AUTEL (道通) +- YUNEEC (昊翔) +``` + +### 2. 平台策略接口 + +#### AirportPlatformStrategy +定义机巢平台需要实现的所有Guard、Action和Listener: +- Guards: CanOnlineGuard, CanOfflineGuard, IsDebugModeGuard等 +- Actions: OnlineAction, OfflineAction, OpenDebugModeAction等 +- Listener: 状态变化监听器 + +#### CoverPlatformStrategy +定义舱门平台需要实现的所有Guard、Action和Listener: +- Guards: CanOpenGuard, CanCloseGuard, IsOpenedGuard等 +- Actions: OpenAction, CloseAction, OpenedAction等 +- Listener: 状态变化监听器 + +### 3. 平台策略工厂 (PlatformStrategyFactory) + +**核心功能:** +- 根据机巢SN从数据库查询平台类型 +- 返回对应平台的策略实现 +- 自动注册所有平台策略实现 + +**关键方法:** +```java +AirportPlatformStrategy getAirportStrategy(String airportSn) +CoverPlatformStrategy getCoverStrategy(String airportSn) +PlatformType getPlatformType(String airportSn) +``` + +### 4. 数据库映射 (AirportPlatformRepository) + +**存储结构:** +``` +机巢SN -> 平台类型 +airport-001 -> DJI +airport-002 -> AUTEL +airport-003 -> DJI +airport-004 -> YUNEEC +``` + +**说明:** 当前使用内存Map模拟数据库,实际使用时替换为真实数据库查询。 + +### 5. 默认Listener实现 + +#### DefaultAirportListener +提供机巢状态变化的基础监听功能: +- 状态进入/退出日志 +- 状态转换日志 +- 事件未接受日志 +- 状态机启动/停止日志 + +#### DefaultCoverListener +提供舱门状态变化的基础监听功能(同上) + +**特点:** 各平台可以继承默认Listener并定制自己的逻辑。 + +## 目录结构 + +``` +com.tuoheng.status.airport +├── platform +│ ├── PlatformType.java # 平台类型枚举 +│ ├── strategy # 策略接口 +│ │ ├── PlatformAction.java +│ │ ├── PlatformGuard.java +│ │ ├── PlatformListener.java +│ │ ├── AirportPlatformStrategy.java +│ │ └── CoverPlatformStrategy.java +│ ├── factory +│ │ └── PlatformStrategyFactory.java # 平台策略工厂 +│ ├── repository +│ │ └── AirportPlatformRepository.java # 数据库映射 +│ └── impl # 平台实现 +│ └── dji # DJI平台实现 +│ ├── DjiAirportPlatformStrategy.java +│ ├── DjiCoverPlatformStrategy.java +│ ├── action +│ │ ├── airport # 机巢Action +│ │ │ ├── DjiOnlineAction.java +│ │ │ ├── DjiOfflineAction.java +│ │ │ ├── DjiOpenDebugModeAction.java +│ │ │ ├── DjiCloseDebugModeAction.java +│ │ │ ├── DjiRebootAction.java +│ │ │ └── DjiRebootCompletedAction.java +│ │ └── cover # 舱门Action +│ │ ├── DjiOpenCoverAction.java +│ │ ├── DjiCoverOpenedAction.java +│ │ ├── DjiCloseCoverAction.java +│ │ ├── DjiCoverClosedAction.java +│ │ ├── DjiCoverErrorAction.java +│ │ └── DjiCoverResetAction.java +│ └── guard +│ ├── airport # 机巢Guard +│ │ ├── DjiCanOnlineGuard.java +│ │ ├── DjiCanOfflineGuard.java +│ │ ├── DjiIsDebugModeGuard.java +│ │ ├── DjiIsNotDebugModeGuard.java +│ │ ├── DjiCanCloseDebugModeGuard.java +│ │ └── DjiIsRebootCompletedGuard.java +│ └── cover # 舱门Guard +│ ├── DjiCanOpenCoverGuard.java +│ ├── DjiCanCloseCoverGuard.java +│ ├── DjiIsCoverOpenedGuard.java +│ └── DjiIsCoverClosedGuard.java +├── listener +│ ├── DefaultAirportListener.java # 默认机巢监听器 +│ └── DefaultCoverListener.java # 默认舱门监听器 +├── config +│ ├── AirportMachineConfig.java # 机巢状态机配置(多平台) +│ └── CoverMachineConfig.java # 舱门状态机配置(多平台) +├── service +│ ├── AirportMachineService.java # 机巢状态机服务 +│ └── CoverMachineService.java # 舱门状态机服务 +├── manager +│ └── AirportSystemManager.java # 系统管理器(协调器) +└── demo + ├── AirportSystemDemo.java # 单平台演示 + └── MultiPlatformDemo.java # 多平台演示 +``` + +## 工作流程 + +### 1. 状态机创建流程 + +``` +用户调用 -> AirportSystemManager.airportOnline(airportSn) + ↓ +AirportMachineService.sendEvent(airportSn, AIRPORT_ONLINE) + ↓ +AirportMachineService.getOrCreateStateMachine(airportSn) + ↓ +AirportMachineConfig.stateMachineFactory.getStateMachine(airportSn) + ↓ +PlatformStrategyFactory.getAirportStrategy(airportSn) + ↓ +AirportPlatformRepository.getPlatformType(airportSn) # 查询数据库 + ↓ +返回对应平台的Strategy (如: DjiAirportPlatformStrategy) + ↓ +使用Strategy中的Guard、Action、Listener构建状态机 + ↓ +状态机创建完成并启动 +``` + +### 2. 事件处理流程 + +``` +事件触发 -> StateMachine.sendEvent(event) + ↓ +检查Guard条件 (如: DjiCanOnlineGuard.evaluate()) + ↓ +Guard通过 -> 执行Action (如: DjiOnlineAction.execute()) + ↓ +状态转换 + ↓ +触发Listener回调 (如: DefaultAirportListener.stateChanged()) +``` + +## 如何添加新平台 + +### 步骤1: 在PlatformType中添加新平台 +```java +public enum PlatformType { + DJI("DJI", "大疆"), + AUTEL("AUTEL", "道通"), + YUNEEC("YUNEEC", "昊翔"), + NEW_PLATFORM("NEW", "新平台"); // 添加这行 +} +``` + +### 步骤2: 创建平台实现目录 +``` +platform/impl/newplatform/ +├── NewPlatformAirportStrategy.java +├── NewPlatformCoverStrategy.java +├── action/ +│ ├── airport/ +│ └── cover/ +└── guard/ + ├── airport/ + └── cover/ +``` + +### 步骤3: 实现AirportPlatformStrategy接口 +```java +@Component +public class NewPlatformAirportStrategy implements AirportPlatformStrategy { + @Override + public PlatformType getPlatformType() { + return PlatformType.NEW_PLATFORM; + } + + // 实现所有Guard、Action、Listener的getter方法 +} +``` + +### 步骤4: 实现CoverPlatformStrategy接口 +```java +@Component +public class NewPlatformCoverStrategy implements CoverPlatformStrategy { + @Override + public PlatformType getPlatformType() { + return PlatformType.NEW_PLATFORM; + } + + // 实现所有Guard、Action、Listener的getter方法 +} +``` + +### 步骤5: 实现所有Guard和Action +参考DJI平台的实现,创建对应的Guard和Action类。 + +### 步骤6: 在数据库中配置映射关系 +```java +repository.savePlatformMapping("airport-005", PlatformType.NEW_PLATFORM); +``` + +### 步骤7: 测试 +```java +systemManager.airportOnline("airport-005"); +``` + +## 运行演示 + +### 单平台演示 +```bash +运行: AirportSystemDemo.main() +演示内容: DJI平台的完整开舱、关舱、重启流程 +``` + +### 多平台演示 +```bash +运行: MultiPlatformDemo.main() +演示内容: +- DJI、AUTEL、YUNEEC三个平台同时运行 +- 各平台独立的状态管理 +- 动态注册新平台 +- 多平台状态汇总 +``` + +## 架构优势 + +1. **平台隔离**: 各平台的业务逻辑完全独立,互不影响 +2. **易于扩展**: 添加新平台只需实现Strategy接口,无需修改现有代码 +3. **数据库驱动**: 平台映射关系存储在数据库,支持动态配置 +4. **多平台并发**: 支持多个平台同时运行,状态机独立管理 +5. **默认实现**: 提供默认Listener,减少重复代码 +6. **类型安全**: 使用枚举和接口保证类型安全 +7. **Spring集成**: 利用Spring的依赖注入自动注册所有平台策略 + +## 注意事项 + +1. **数据库配置**: 当前使用内存Map模拟,生产环境需替换为真实数据库 +2. **平台注册**: 所有平台Strategy实现必须标注@Component注解 +3. **机巢SN**: 必须在数据库中配置机巢SN到平台类型的映射 +4. **Listener定制**: 如需定制Listener,继承DefaultListener并覆盖相应方法 +5. **线程安全**: Service层使用ConcurrentHashMap保证线程安全 + +## 未来扩展 + +1. **平台能力差异**: 可在Strategy中添加能力查询接口 +2. **动态配置**: 支持运行时动态修改平台映射关系 +3. **平台版本**: 支持同一平台的不同版本(如DJI v1, DJI v2) +4. **监控告警**: 集成监控系统,实时监控各平台状态 +5. **性能优化**: 状态机缓存、懒加载等优化策略 diff --git a/src/main/java/com/tuoheng/status/airport/config/AirportMachineConfig.java b/src/main/java/com/tuoheng/status/airport/config/AirportMachineConfig.java index e18070a..414ce56 100644 --- a/src/main/java/com/tuoheng/status/airport/config/AirportMachineConfig.java +++ b/src/main/java/com/tuoheng/status/airport/config/AirportMachineConfig.java @@ -1,19 +1,8 @@ package com.tuoheng.status.airport.config; -import com.tuoheng.status.airport.action.airport.OfflineAction; -import com.tuoheng.status.airport.action.airport.OnlineAction; -import com.tuoheng.status.airport.action.debug.CloseDebugModeAction; -import com.tuoheng.status.airport.action.debug.OpenDebugModeAction; -import com.tuoheng.status.airport.action.reboot.RebootAction; -import com.tuoheng.status.airport.action.reboot.RebootCompletedAction; import com.tuoheng.status.airport.events.AirportEvent; -import com.tuoheng.status.airport.guard.airport.CanOfflineGuard; -import com.tuoheng.status.airport.guard.airport.CanOnlineGuard; -import com.tuoheng.status.airport.guard.debug.CanCloseDebugModeGuard; -import com.tuoheng.status.airport.guard.debug.IsDebugModeGuard; -import com.tuoheng.status.airport.guard.debug.IsNotDebugModeGuard; -import com.tuoheng.status.airport.guard.reboot.IsRebootCompletedGuard; -import com.tuoheng.status.airport.listener.AirPortStatusListener; +import com.tuoheng.status.airport.platform.factory.PlatformStrategyFactory; +import com.tuoheng.status.airport.platform.strategy.AirportPlatformStrategy; import com.tuoheng.status.airport.status.AirportState; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; @@ -26,51 +15,14 @@ import java.util.EnumSet; import java.util.UUID; /** - * 机巢状态机配置(简化版 - 舱门状态已分离) + * 机巢状态机配置(多平台支持版本) + * 通过PlatformStrategyFactory动态获取平台特定的Guard、Action和Listener */ @Configuration public class AirportMachineConfig { @Autowired - AirPortStatusListener airPortStatusListener; - - // ==================== Actions ==================== - @Autowired - OnlineAction onlineAction; - - @Autowired - OfflineAction offlineAction; - - @Autowired - OpenDebugModeAction openDebugModeAction; - - @Autowired - CloseDebugModeAction closeDebugModeAction; - - @Autowired - RebootAction rebootAction; - - @Autowired - RebootCompletedAction rebootCompletedAction; - - // ==================== Guards ==================== - @Autowired - CanOnlineGuard canOnlineGuard; - - @Autowired - CanOfflineGuard canOfflineGuard; - - @Autowired - IsDebugModeGuard isDebugModeGuard; - - @Autowired - IsNotDebugModeGuard isNotDebugModeGuard; - - @Autowired - CanCloseDebugModeGuard canCloseDebugModeGuard; - - @Autowired - IsRebootCompletedGuard isRebootCompletedGuard; + private PlatformStrategyFactory platformStrategyFactory; @Bean(name = "airportStateMachineFactory") public StateMachineFactory stateMachineFactory() throws Exception { @@ -83,16 +35,19 @@ public class AirportMachineConfig { @Override public StateMachine getStateMachine(String machineId) { try { + // 根据机巢SN获取平台策略 + AirportPlatformStrategy strategy = platformStrategyFactory.getAirportStrategy(machineId); + StateMachineBuilder.Builder builder = StateMachineBuilder.builder(); - configureStateMachine(builder); + configureStateMachine(builder, strategy); configureStates(builder); - configureTransitions(builder); + configureTransitions(builder, strategy); StateMachine stateMachine = builder.build(); stateMachine.getExtendedState().getVariables().put("machineId", machineId); return stateMachine; } catch (Exception e) { - throw new RuntimeException("Failed to create state machine", e); + throw new RuntimeException("Failed to create state machine for: " + machineId, e); } } @@ -103,11 +58,13 @@ public class AirportMachineConfig { }; } - private void configureStateMachine(StateMachineBuilder.Builder builder) throws Exception { + private void configureStateMachine( + StateMachineBuilder.Builder builder, + AirportPlatformStrategy strategy) throws Exception { builder.configureConfiguration() .withConfiguration() .autoStartup(true) - .listener(airPortStatusListener); + .listener(strategy.getListener()); } private void configureStates(StateMachineBuilder.Builder builder) throws Exception { @@ -129,15 +86,17 @@ public class AirportMachineConfig { )); } - private void configureTransitions(StateMachineBuilder.Builder builder) throws Exception { + private void configureTransitions( + StateMachineBuilder.Builder builder, + AirportPlatformStrategy strategy) throws Exception { builder.configureTransitions() // OFFLINE -> ONLINE(STANDBY) .withExternal() .source(AirportState.OFFLINE) .target(AirportState.ONLINE) .event(AirportEvent.AIRPORT_ONLINE) - .action(onlineAction) - .guard(canOnlineGuard) + .action(strategy.getOnlineAction()) + .guard(strategy.getCanOnlineGuard()) .and() // ONLINE -> OFFLINE @@ -145,8 +104,8 @@ public class AirportMachineConfig { .source(AirportState.ONLINE) .target(AirportState.OFFLINE) .event(AirportEvent.AIRPORT_OFFLINE) - .action(offlineAction) - .guard(canOfflineGuard) + .action(strategy.getOfflineAction()) + .guard(strategy.getCanOfflineGuard()) .and() // STANDBY -> DEBUG_MODE @@ -154,8 +113,8 @@ public class AirportMachineConfig { .source(AirportState.STANDBY) .target(AirportState.DEBUG_MODE) .event(AirportEvent.DEBUG_MODE_OPEN) - .action(openDebugModeAction) - .guard(isNotDebugModeGuard) + .action(strategy.getOpenDebugModeAction()) + .guard(strategy.getIsNotDebugModeGuard()) .and() // DEBUG_MODE -> STANDBY @@ -163,8 +122,8 @@ public class AirportMachineConfig { .source(AirportState.DEBUG_MODE) .target(AirportState.STANDBY) .event(AirportEvent.DEBUG_MODE_CLOSE) - .action(closeDebugModeAction) - .guard(canCloseDebugModeGuard) + .action(strategy.getCloseDebugModeAction()) + .guard(strategy.getCanCloseDebugModeGuard()) .and() // DEBUG_MODE -> REBOOTING @@ -172,8 +131,8 @@ public class AirportMachineConfig { .source(AirportState.DEBUG_MODE) .target(AirportState.REBOOTING) .event(AirportEvent.AIRPORT_REBOOT) - .action(rebootAction) - .guard(isDebugModeGuard) + .action(strategy.getRebootAction()) + .guard(strategy.getIsDebugModeGuard()) .and() // REBOOTING -> ONLINE(STANDBY) @@ -181,7 +140,7 @@ public class AirportMachineConfig { .source(AirportState.REBOOTING) .target(AirportState.ONLINE) .event(AirportEvent.REBOOT_COMPLETED) - .action(rebootCompletedAction) - .guard(isRebootCompletedGuard); + .action(strategy.getRebootCompletedAction()) + .guard(strategy.getIsRebootCompletedGuard()); } } diff --git a/src/main/java/com/tuoheng/status/airport/config/CoverMachineConfig.java b/src/main/java/com/tuoheng/status/airport/config/CoverMachineConfig.java index b0d86a1..0e56eff 100644 --- a/src/main/java/com/tuoheng/status/airport/config/CoverMachineConfig.java +++ b/src/main/java/com/tuoheng/status/airport/config/CoverMachineConfig.java @@ -1,7 +1,10 @@ package com.tuoheng.status.airport.config; import com.tuoheng.status.airport.events.CoverEvent; +import com.tuoheng.status.airport.platform.factory.PlatformStrategyFactory; +import com.tuoheng.status.airport.platform.strategy.CoverPlatformStrategy; import com.tuoheng.status.airport.status.CoverState; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.statemachine.StateMachine; @@ -12,11 +15,15 @@ import java.util.EnumSet; import java.util.UUID; /** - * 舱门状态机配置 + * 舱门状态机配置(多平台支持版本) + * 通过PlatformStrategyFactory动态获取平台特定的Guard、Action和Listener */ @Configuration public class CoverMachineConfig { + @Autowired + private PlatformStrategyFactory platformStrategyFactory; + @Bean public StateMachineFactory coverStateMachineFactory() throws Exception { return new StateMachineFactory() { @@ -28,16 +35,19 @@ public class CoverMachineConfig { @Override public StateMachine getStateMachine(String machineId) { try { + // 根据机巢SN获取平台策略 + CoverPlatformStrategy strategy = platformStrategyFactory.getCoverStrategy(machineId); + StateMachineBuilder.Builder builder = StateMachineBuilder.builder(); - configureCoverStateMachine(builder); + configureCoverStateMachine(builder, strategy); configureCoverStates(builder); - configureCoverTransitions(builder); + configureCoverTransitions(builder, strategy); StateMachine stateMachine = builder.build(); stateMachine.getExtendedState().getVariables().put("machineId", machineId); return stateMachine; } catch (Exception e) { - throw new RuntimeException("Failed to create cover state machine", e); + throw new RuntimeException("Failed to create cover state machine for: " + machineId, e); } } @@ -48,10 +58,13 @@ public class CoverMachineConfig { }; } - private void configureCoverStateMachine(StateMachineBuilder.Builder builder) throws Exception { + private void configureCoverStateMachine( + StateMachineBuilder.Builder builder, + CoverPlatformStrategy strategy) throws Exception { builder.configureConfiguration() .withConfiguration() - .autoStartup(true); + .autoStartup(true) + .listener(strategy.getListener()); } private void configureCoverStates(StateMachineBuilder.Builder builder) throws Exception { @@ -61,13 +74,17 @@ public class CoverMachineConfig { .states(EnumSet.allOf(CoverState.class)); } - private void configureCoverTransitions(StateMachineBuilder.Builder builder) throws Exception { + private void configureCoverTransitions( + StateMachineBuilder.Builder builder, + CoverPlatformStrategy strategy) throws Exception { builder.configureTransitions() // CLOSED -> OPENING .withExternal() .source(CoverState.CLOSED) .target(CoverState.OPENING) .event(CoverEvent.OPEN) + .action(strategy.getOpenAction()) + .guard(strategy.getCanOpenGuard()) .and() // OPENING -> OPENED @@ -75,6 +92,8 @@ public class CoverMachineConfig { .source(CoverState.OPENING) .target(CoverState.OPENED) .event(CoverEvent.OPENED) + .action(strategy.getOpenedAction()) + .guard(strategy.getIsOpenedGuard()) .and() // OPENED -> CLOSING @@ -82,6 +101,8 @@ public class CoverMachineConfig { .source(CoverState.OPENED) .target(CoverState.CLOSING) .event(CoverEvent.CLOSE) + .action(strategy.getCloseAction()) + .guard(strategy.getCanCloseGuard()) .and() // CLOSING -> CLOSED @@ -89,6 +110,8 @@ public class CoverMachineConfig { .source(CoverState.CLOSING) .target(CoverState.CLOSED) .event(CoverEvent.CLOSED) + .action(strategy.getClosedAction()) + .guard(strategy.getIsClosedGuard()) .and() // ERROR handling @@ -96,18 +119,21 @@ public class CoverMachineConfig { .source(CoverState.OPENING) .target(CoverState.ERROR) .event(CoverEvent.ERROR) + .action(strategy.getErrorAction()) .and() .withExternal() .source(CoverState.CLOSING) .target(CoverState.ERROR) .event(CoverEvent.ERROR) + .action(strategy.getErrorAction()) .and() // RESET from ERROR .withExternal() .source(CoverState.ERROR) .target(CoverState.CLOSED) - .event(CoverEvent.RESET); + .event(CoverEvent.RESET) + .action(strategy.getResetAction()); } } diff --git a/src/main/java/com/tuoheng/status/airport/demo/MultiPlatformDemo.java b/src/main/java/com/tuoheng/status/airport/demo/MultiPlatformDemo.java new file mode 100644 index 0000000..d716097 --- /dev/null +++ b/src/main/java/com/tuoheng/status/airport/demo/MultiPlatformDemo.java @@ -0,0 +1,169 @@ +package com.tuoheng.status.airport.demo; + +import com.tuoheng.status.airport.manager.AirportSystemManager; +import com.tuoheng.status.airport.platform.PlatformType; +import com.tuoheng.status.airport.platform.factory.PlatformStrategyFactory; +import com.tuoheng.status.airport.platform.repository.AirportPlatformRepository; +import org.springframework.context.annotation.AnnotationConfigApplicationContext; + +/** + * 多平台演示程序 + * 演示DJI、AUTEL、YUNEEC等多个平台同时运行的场景 + */ +public class MultiPlatformDemo { + + public static void main(String[] args) throws InterruptedException { + + // 创建 Spring 上下文 + AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(); + + // 扫描所有组件 + context.scan("com.tuoheng.status.airport"); + context.refresh(); + + // 获取必要的Bean + AirportSystemManager systemManager = context.getBean(AirportSystemManager.class); + PlatformStrategyFactory strategyFactory = context.getBean(PlatformStrategyFactory.class); + AirportPlatformRepository repository = context.getBean(AirportPlatformRepository.class); + + System.out.println("\n========== 多平台机巢系统演示开始 ==========\n"); + + // ==================== 场景1: 多平台机巢上线 ==================== + System.out.println("【场景1】多平台机巢上线"); + System.out.println("----------------------------------------"); + + String djiAirport = "airport-001"; // DJI平台 + String autelAirport = "airport-002"; // AUTEL平台 + String djiAirport2 = "airport-003"; // DJI平台 + + System.out.println("1. DJI机巢上线: " + djiAirport); + System.out.println(" 平台类型: " + strategyFactory.getPlatformType(djiAirport).getName()); + systemManager.airportOnline(djiAirport); + System.out.println(" " + systemManager.getFullStatus(djiAirport)); + System.out.println(); + Thread.sleep(500); + + System.out.println("2. AUTEL机巢上线: " + autelAirport); + System.out.println(" 平台类型: " + strategyFactory.getPlatformType(autelAirport).getName()); + systemManager.airportOnline(autelAirport); + System.out.println(" " + systemManager.getFullStatus(autelAirport)); + System.out.println(); + Thread.sleep(500); + + System.out.println("3. 另一个DJI机巢上线: " + djiAirport2); + System.out.println(" 平台类型: " + strategyFactory.getPlatformType(djiAirport2).getName()); + systemManager.airportOnline(djiAirport2); + System.out.println(" " + systemManager.getFullStatus(djiAirport2)); + System.out.println(); + Thread.sleep(500); + + // ==================== 场景2: DJI平台开舱流程 ==================== + System.out.println("【场景2】DJI平台开舱流程"); + System.out.println("----------------------------------------"); + + System.out.println("4. DJI机巢开启调试模式: " + djiAirport); + systemManager.openDebugMode(djiAirport); + System.out.println(" " + systemManager.getFullStatus(djiAirport)); + System.out.println(); + Thread.sleep(500); + + System.out.println("5. DJI机巢开舱: " + djiAirport); + systemManager.openCover(djiAirport); + System.out.println(" " + systemManager.getFullStatus(djiAirport)); + System.out.println(); + Thread.sleep(500); + + System.out.println("6. DJI机巢舱门打开完成: " + djiAirport); + systemManager.coverOpened(djiAirport); + System.out.println(" " + systemManager.getFullStatus(djiAirport)); + System.out.println(); + Thread.sleep(500); + + // ==================== 场景3: AUTEL平台开舱流程(同时进行) ==================== + System.out.println("【场景3】AUTEL平台开舱流程(与DJI平台并行)"); + System.out.println("----------------------------------------"); + + System.out.println("7. AUTEL机巢开启调试模式: " + autelAirport); + systemManager.openDebugMode(autelAirport); + System.out.println(" " + systemManager.getFullStatus(autelAirport)); + System.out.println(); + Thread.sleep(500); + + System.out.println("8. AUTEL机巢开舱: " + autelAirport); + systemManager.openCover(autelAirport); + System.out.println(" " + systemManager.getFullStatus(autelAirport)); + System.out.println(); + Thread.sleep(500); + + // ==================== 场景4: 查看所有机巢状态 ==================== + System.out.println("【场景4】查看所有机巢当前状态"); + System.out.println("----------------------------------------"); + System.out.println("DJI机巢-001: " + systemManager.getFullStatus(djiAirport)); + System.out.println("AUTEL机巢-002: " + systemManager.getFullStatus(autelAirport)); + System.out.println("DJI机巢-003: " + systemManager.getFullStatus(djiAirport2)); + System.out.println(); + Thread.sleep(500); + + // ==================== 场景5: DJI机巢关舱 ==================== + System.out.println("【场景5】DJI机巢关舱流程"); + System.out.println("----------------------------------------"); + + System.out.println("9. DJI机巢关舱: " + djiAirport); + systemManager.closeCover(djiAirport); + System.out.println(" " + systemManager.getFullStatus(djiAirport)); + System.out.println(); + Thread.sleep(500); + + System.out.println("10. DJI机巢舱门关闭完成: " + djiAirport); + systemManager.coverClosed(djiAirport); + System.out.println(" " + systemManager.getFullStatus(djiAirport)); + System.out.println(); + Thread.sleep(500); + + // ==================== 场景6: 动态注册新平台机巢 ==================== + System.out.println("【场景6】动态注册新平台机巢"); + System.out.println("----------------------------------------"); + + String yuneecAirport = "airport-004"; + System.out.println("11. 注册YUNEEC平台机巢: " + yuneecAirport); + System.out.println(" 平台类型: " + strategyFactory.getPlatformType(yuneecAirport).getName()); + systemManager.airportOnline(yuneecAirport); + System.out.println(" " + systemManager.getFullStatus(yuneecAirport)); + System.out.println(); + + // ==================== 场景7: 最终状态汇总 ==================== + System.out.println("【场景7】所有机巢最终状态汇总"); + System.out.println("----------------------------------------"); + System.out.println(String.format("%-20s %-15s %s", "机巢SN", "平台类型", "状态")); + System.out.println("------------------------------------------------------------"); + System.out.println(String.format("%-20s %-15s %s", + djiAirport, + strategyFactory.getPlatformType(djiAirport).getName(), + systemManager.getFullStatus(djiAirport))); + System.out.println(String.format("%-20s %-15s %s", + autelAirport, + strategyFactory.getPlatformType(autelAirport).getName(), + systemManager.getFullStatus(autelAirport))); + System.out.println(String.format("%-20s %-15s %s", + djiAirport2, + strategyFactory.getPlatformType(djiAirport2).getName(), + systemManager.getFullStatus(djiAirport2))); + System.out.println(String.format("%-20s %-15s %s", + yuneecAirport, + strategyFactory.getPlatformType(yuneecAirport).getName(), + systemManager.getFullStatus(yuneecAirport))); + System.out.println(); + + System.out.println("\n========== 多平台机巢系统演示结束 ==========\n"); + + System.out.println("✅ 多平台架构优势:"); + System.out.println(" 1. 支持多个无人机平台(DJI、AUTEL、YUNEEC等)"); + System.out.println(" 2. 各平台独立实现Guard、Action和Listener"); + System.out.println(" 3. 通过数据库配置平台映射关系"); + System.out.println(" 4. 多个平台可以同时运行,互不干扰"); + System.out.println(" 5. 易于扩展新平台,只需实现对应的Strategy接口"); + System.out.println(" 6. 默认Listener提供基础功能,各平台可定制"); + + context.close(); + } +} diff --git a/src/main/java/com/tuoheng/status/airport/listener/AirPortStatusListener.java b/src/main/java/com/tuoheng/status/airport/listener/AirPortStatusListener.java deleted file mode 100644 index 4cff578..0000000 --- a/src/main/java/com/tuoheng/status/airport/listener/AirPortStatusListener.java +++ /dev/null @@ -1,77 +0,0 @@ -package com.tuoheng.status.airport.listener; - -import com.tuoheng.status.airport.events.AirportEvent; -import com.tuoheng.status.airport.status.AirportState; -import com.tuoheng.status.statemachine.events.Event; -import com.tuoheng.status.statemachine.status.Status; -import org.springframework.messaging.Message; -import org.springframework.statemachine.StateContext; -import org.springframework.statemachine.StateMachine; -import org.springframework.statemachine.listener.StateMachineListener; -import org.springframework.statemachine.state.State; -import org.springframework.statemachine.transition.Transition; -import org.springframework.stereotype.Component; - -@Component -public class AirPortStatusListener implements StateMachineListener { - - @Override - public void stateChanged(State state, State state1) { - - } - - @Override - public void stateEntered(State state) { - - } - - @Override - public void stateExited(State state) { - - } - - @Override - public void eventNotAccepted(Message message) { - - } - - @Override - public void transition(Transition transition) { - - } - - @Override - public void transitionStarted(Transition transition) { - - } - - @Override - public void transitionEnded(Transition transition) { - - } - - @Override - public void stateMachineStarted(StateMachine stateMachine) { - - } - - @Override - public void stateMachineStopped(StateMachine stateMachine) { - - } - - @Override - public void stateMachineError(StateMachine stateMachine, Exception e) { - - } - - @Override - public void extendedStateChanged(Object o, Object o1) { - - } - - @Override - public void stateContext(StateContext stateContext) { - - } -} diff --git a/src/main/java/com/tuoheng/status/airport/listener/DefaultAirportListener.java b/src/main/java/com/tuoheng/status/airport/listener/DefaultAirportListener.java new file mode 100644 index 0000000..a315e6d --- /dev/null +++ b/src/main/java/com/tuoheng/status/airport/listener/DefaultAirportListener.java @@ -0,0 +1,97 @@ +package com.tuoheng.status.airport.listener; + +import com.tuoheng.status.airport.events.AirportEvent; +import com.tuoheng.status.airport.platform.strategy.PlatformListener; +import com.tuoheng.status.airport.status.AirportState; +import org.springframework.messaging.Message; +import org.springframework.statemachine.StateContext; +import org.springframework.statemachine.StateMachine; +import org.springframework.statemachine.state.State; +import org.springframework.statemachine.transition.Transition; +import org.springframework.stereotype.Component; + +/** + * 默认机巢状态监听器 + * 提供基础的状态变化监听功能,各平台可以继承并定制 + */ +@Component +public class DefaultAirportListener implements PlatformListener { + + @Override + public String getName() { + return "DefaultAirportListener"; + } + + @Override + public void stateChanged(State from, State to) { + if (from != null && to != null) { + System.out.println(String.format("[%s] 状态变化: %s -> %s", + getName(), from.getId(), to.getId())); + } + } + + @Override + public void stateEntered(State state) { + System.out.println(String.format("[%s] 进入状态: %s", getName(), state.getId())); + } + + @Override + public void stateExited(State state) { + System.out.println(String.format("[%s] 退出状态: %s", getName(), state.getId())); + } + + @Override + public void eventNotAccepted(Message event) { + System.out.println(String.format("[%s] 事件未被接受: %s", getName(), event.getPayload())); + } + + @Override + public void transition(Transition transition) { + // 默认不处理 + } + + @Override + public void transitionStarted(Transition transition) { + if (transition.getSource() != null && transition.getTarget() != null) { + System.out.println(String.format("[%s] 转换开始: %s -> %s", + getName(), transition.getSource().getId(), transition.getTarget().getId())); + } + } + + @Override + public void transitionEnded(Transition transition) { + if (transition.getSource() != null && transition.getTarget() != null) { + System.out.println(String.format("[%s] 转换结束: %s -> %s", + getName(), transition.getSource().getId(), transition.getTarget().getId())); + } + } + + @Override + public void stateMachineStarted(StateMachine stateMachine) { + String machineId = (String) stateMachine.getExtendedState().getVariables().get("machineId"); + System.out.println(String.format("[%s] 状态机启动: %s", getName(), machineId)); + } + + @Override + public void stateMachineStopped(StateMachine stateMachine) { + String machineId = (String) stateMachine.getExtendedState().getVariables().get("machineId"); + System.out.println(String.format("[%s] 状态机停止: %s", getName(), machineId)); + } + + @Override + public void stateMachineError(StateMachine stateMachine, Exception exception) { + String machineId = (String) stateMachine.getExtendedState().getVariables().get("machineId"); + System.err.println(String.format("[%s] 状态机错误: %s, 异常: %s", + getName(), machineId, exception.getMessage())); + } + + @Override + public void extendedStateChanged(Object key, Object value) { + System.out.println(String.format("[%s] 扩展状态变化: %s = %s", getName(), key, value)); + } + + @Override + public void stateContext(StateContext stateContext) { + // 默认不处理 + } +} diff --git a/src/main/java/com/tuoheng/status/airport/listener/DefaultCoverListener.java b/src/main/java/com/tuoheng/status/airport/listener/DefaultCoverListener.java new file mode 100644 index 0000000..68b2dc7 --- /dev/null +++ b/src/main/java/com/tuoheng/status/airport/listener/DefaultCoverListener.java @@ -0,0 +1,97 @@ +package com.tuoheng.status.airport.listener; + +import com.tuoheng.status.airport.events.CoverEvent; +import com.tuoheng.status.airport.platform.strategy.PlatformListener; +import com.tuoheng.status.airport.status.CoverState; +import org.springframework.messaging.Message; +import org.springframework.statemachine.StateContext; +import org.springframework.statemachine.StateMachine; +import org.springframework.statemachine.state.State; +import org.springframework.statemachine.transition.Transition; +import org.springframework.stereotype.Component; + +/** + * 默认舱门状态监听器 + * 提供基础的状态变化监听功能,各平台可以继承并定制 + */ +@Component +public class DefaultCoverListener implements PlatformListener { + + @Override + public String getName() { + return "DefaultCoverListener"; + } + + @Override + public void stateChanged(State from, State to) { + if (from != null && to != null) { + System.out.println(String.format("[%s] 状态变化: %s -> %s", + getName(), from.getId(), to.getId())); + } + } + + @Override + public void stateEntered(State state) { + System.out.println(String.format("[%s] 进入状态: %s", getName(), state.getId())); + } + + @Override + public void stateExited(State state) { + System.out.println(String.format("[%s] 退出状态: %s", getName(), state.getId())); + } + + @Override + public void eventNotAccepted(Message event) { + System.out.println(String.format("[%s] 事件未被接受: %s", getName(), event.getPayload())); + } + + @Override + public void transition(Transition transition) { + // 默认不处理 + } + + @Override + public void transitionStarted(Transition transition) { + if (transition.getSource() != null && transition.getTarget() != null) { + System.out.println(String.format("[%s] 转换开始: %s -> %s", + getName(), transition.getSource().getId(), transition.getTarget().getId())); + } + } + + @Override + public void transitionEnded(Transition transition) { + if (transition.getSource() != null && transition.getTarget() != null) { + System.out.println(String.format("[%s] 转换结束: %s -> %s", + getName(), transition.getSource().getId(), transition.getTarget().getId())); + } + } + + @Override + public void stateMachineStarted(StateMachine stateMachine) { + String machineId = (String) stateMachine.getExtendedState().getVariables().get("machineId"); + System.out.println(String.format("[%s] 状态机启动: %s", getName(), machineId)); + } + + @Override + public void stateMachineStopped(StateMachine stateMachine) { + String machineId = (String) stateMachine.getExtendedState().getVariables().get("machineId"); + System.out.println(String.format("[%s] 状态机停止: %s", getName(), machineId)); + } + + @Override + public void stateMachineError(StateMachine stateMachine, Exception exception) { + String machineId = (String) stateMachine.getExtendedState().getVariables().get("machineId"); + System.err.println(String.format("[%s] 状态机错误: %s, 异常: %s", + getName(), machineId, exception.getMessage())); + } + + @Override + public void extendedStateChanged(Object key, Object value) { + System.out.println(String.format("[%s] 扩展状态变化: %s = %s", getName(), key, value)); + } + + @Override + public void stateContext(StateContext stateContext) { + // 默认不处理 + } +} diff --git a/src/main/java/com/tuoheng/status/airport/manager/AirportSystemManager.java b/src/main/java/com/tuoheng/status/airport/manager/AirportSystemManager.java index 07cd1a1..ccb4d45 100644 --- a/src/main/java/com/tuoheng/status/airport/manager/AirportSystemManager.java +++ b/src/main/java/com/tuoheng/status/airport/manager/AirportSystemManager.java @@ -17,41 +17,41 @@ import org.springframework.stereotype.Component; public class AirportSystemManager { @Autowired - private AirportMachineService airportManager; + private AirportMachineService airportService; @Autowired - private CoverMachineService coverManager; + private CoverMachineService coverService; /** * 机巢上线 */ public boolean airportOnline(String airportSn) { - return airportManager.sendEvent(airportSn, AirportEvent.AIRPORT_ONLINE); + return airportService.sendEvent(airportSn, AirportEvent.AIRPORT_ONLINE); } /** * 机巢离线 */ public boolean airportOffline(String airportSn) { - return airportManager.sendEvent(airportSn, AirportEvent.AIRPORT_OFFLINE); + return airportService.sendEvent(airportSn, AirportEvent.AIRPORT_OFFLINE); } /** * 开启调试模式 */ public boolean openDebugMode(String airportSn) { - if (!airportManager.isInState(airportSn, AirportState.ONLINE)) { + if (!airportService.isInState(airportSn, AirportState.ONLINE)) { System.out.println("机巢未在线,无法开启调试模式"); return false; } - return airportManager.sendEvent(airportSn, AirportEvent.DEBUG_MODE_OPEN); + return airportService.sendEvent(airportSn, AirportEvent.DEBUG_MODE_OPEN); } /** * 关闭调试模式 */ public boolean closeDebugMode(String airportSn) { - return airportManager.sendEvent(airportSn, AirportEvent.DEBUG_MODE_CLOSE); + return airportService.sendEvent(airportSn, AirportEvent.DEBUG_MODE_CLOSE); } /** @@ -59,26 +59,26 @@ public class AirportSystemManager { */ public boolean openCover(String airportSn) { // 检查机巢是否在调试模式 - if (!airportManager.isInState(airportSn, AirportState.DEBUG_MODE)) { + if (!airportService.isInState(airportSn, AirportState.DEBUG_MODE)) { System.out.println("必须在调试模式下才能开舱"); return false; } // 检查舱门是否已经打开 - if (coverManager.isInState(airportSn, CoverState.OPENED)) { + if (coverService.isInState(airportSn, CoverState.OPENED)) { System.out.println("舱门已经打开"); return false; } // 发送开舱指令到舱门状态机 - return coverManager.sendEvent(airportSn, CoverEvent.OPEN); + return coverService.sendEvent(airportSn, CoverEvent.OPEN); } /** * 舱门打开完成 */ public boolean coverOpened(String airportSn) { - return coverManager.sendEvent(airportSn, CoverEvent.OPENED); + return coverService.sendEvent(airportSn, CoverEvent.OPENED); } /** @@ -86,58 +86,58 @@ public class AirportSystemManager { */ public boolean closeCover(String airportSn) { // 检查机巢是否在调试模式 - if (!airportManager.isInState(airportSn, AirportState.DEBUG_MODE)) { + if (!airportService.isInState(airportSn, AirportState.DEBUG_MODE)) { System.out.println("必须在调试模式下才能关舱"); return false; } // 检查舱门是否已经关闭 - if (coverManager.isInState(airportSn, CoverState.CLOSED)) { + if (coverService.isInState(airportSn, CoverState.CLOSED)) { System.out.println("舱门已经关闭"); return false; } // 发送关舱指令到舱门状态机 - return coverManager.sendEvent(airportSn, CoverEvent.CLOSE); + return coverService.sendEvent(airportSn, CoverEvent.CLOSE); } /** * 舱门关闭完成 */ public boolean coverClosed(String airportSn) { - return coverManager.sendEvent(airportSn, CoverEvent.CLOSED); + return coverService.sendEvent(airportSn, CoverEvent.CLOSED); } /** * 机巢重启 */ public boolean rebootAirport(String airportSn) { - if (!airportManager.isInState(airportSn, AirportState.DEBUG_MODE)) { + if (!airportService.isInState(airportSn, AirportState.DEBUG_MODE)) { System.out.println("必须在调试模式下才能重启"); return false; } - return airportManager.sendEvent(airportSn, AirportEvent.AIRPORT_REBOOT); + return airportService.sendEvent(airportSn, AirportEvent.AIRPORT_REBOOT); } /** * 重启完成 */ public boolean rebootCompleted(String airportSn) { - return airportManager.sendEvent(airportSn, AirportEvent.REBOOT_COMPLETED); + return airportService.sendEvent(airportSn, AirportEvent.REBOOT_COMPLETED); } /** * 获取机巢状态 */ public AirportState getAirportState(String airportSn) { - return airportManager.getCurrentState(airportSn); + return airportService.getCurrentState(airportSn); } /** * 获取舱门状态 */ public CoverState getCoverState(String airportSn) { - return coverManager.getCurrentState(airportSn); + return coverService.getCurrentState(airportSn); } /** diff --git a/src/main/java/com/tuoheng/status/airport/platform/PlatformType.java b/src/main/java/com/tuoheng/status/airport/platform/PlatformType.java new file mode 100644 index 0000000..5941ae4 --- /dev/null +++ b/src/main/java/com/tuoheng/status/airport/platform/PlatformType.java @@ -0,0 +1,49 @@ +package com.tuoheng.status.airport.platform; + +/** + * 无人机平台类型枚举 + */ +public enum PlatformType { + /** + * 大疆平台 + */ + DJI("DJI", "大疆"), + + /** + * 道通平台 + */ + AUTEL("AUTEL", "道通"), + + /** + * 昊翔平台 + */ + YUNEEC("YUNEEC", "昊翔"); + + private final String code; + private final String name; + + PlatformType(String code, String name) { + this.code = code; + this.name = name; + } + + public String getCode() { + return code; + } + + public String getName() { + return name; + } + + /** + * 根据code获取平台类型 + */ + public static PlatformType fromCode(String code) { + for (PlatformType type : values()) { + if (type.code.equalsIgnoreCase(code)) { + return type; + } + } + throw new IllegalArgumentException("Unknown platform code: " + code); + } +} diff --git a/src/main/java/com/tuoheng/status/airport/platform/factory/PlatformStrategyFactory.java b/src/main/java/com/tuoheng/status/airport/platform/factory/PlatformStrategyFactory.java new file mode 100644 index 0000000..80949c4 --- /dev/null +++ b/src/main/java/com/tuoheng/status/airport/platform/factory/PlatformStrategyFactory.java @@ -0,0 +1,143 @@ +package com.tuoheng.status.airport.platform.factory; + +import com.tuoheng.status.airport.platform.PlatformType; +import com.tuoheng.status.airport.platform.repository.AirportPlatformRepository; +import com.tuoheng.status.airport.platform.strategy.AirportPlatformStrategy; +import com.tuoheng.status.airport.platform.strategy.CoverPlatformStrategy; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +/** + * 平台策略工厂 + * 根据机巢SN从数据库查询平台类型,返回对应的平台策略 + */ +@Component +public class PlatformStrategyFactory { + + @Autowired + private AirportPlatformRepository airportPlatformRepository; + + /** + * 存储所有机巢平台策略实现 + * Key: PlatformType + * Value: AirportPlatformStrategy实现 + */ + private final Map airportStrategyMap = new ConcurrentHashMap<>(); + + /** + * 存储所有舱门平台策略实现 + * Key: PlatformType + * Value: CoverPlatformStrategy实现 + */ + private final Map coverStrategyMap = new ConcurrentHashMap<>(); + + /** + * 注册所有平台策略 + * Spring会自动注入所有实现了AirportPlatformStrategy和CoverPlatformStrategy的Bean + */ + @Autowired + public void registerStrategies( + List airportStrategies, + List coverStrategies) { + + // 注册机巢策略 + for (AirportPlatformStrategy strategy : airportStrategies) { + airportStrategyMap.put(strategy.getPlatformType(), strategy); + System.out.println(String.format("注册机巢平台策略: %s -> %s", + strategy.getPlatformType().getName(), strategy.getClass().getSimpleName())); + } + + // 注册舱门策略 + for (CoverPlatformStrategy strategy : coverStrategies) { + coverStrategyMap.put(strategy.getPlatformType(), strategy); + System.out.println(String.format("注册舱门平台策略: %s -> %s", + strategy.getPlatformType().getName(), strategy.getClass().getSimpleName())); + } + } + + /** + * 根据机巢SN获取机巢平台策略 + * + * @param airportSn 机巢序列号 + * @return 机巢平台策略 + * @throws IllegalArgumentException 如果机巢未注册或平台策略不存在 + */ + public AirportPlatformStrategy getAirportStrategy(String airportSn) { + // 从数据库查询平台类型 + PlatformType platformType = airportPlatformRepository.getPlatformType(airportSn); + + if (platformType == null) { + throw new IllegalArgumentException( + String.format("机巢未注册或平台类型未配置: %s", airportSn)); + } + + AirportPlatformStrategy strategy = airportStrategyMap.get(platformType); + + if (strategy == null) { + throw new IllegalArgumentException( + String.format("未找到平台策略: %s (机巢: %s)", platformType.getName(), airportSn)); + } + + return strategy; + } + + /** + * 根据机巢SN获取舱门平台策略 + * + * @param airportSn 机巢序列号 + * @return 舱门平台策略 + * @throws IllegalArgumentException 如果机巢未注册或平台策略不存在 + */ + public CoverPlatformStrategy getCoverStrategy(String airportSn) { + // 从数据库查询平台类型 + PlatformType platformType = airportPlatformRepository.getPlatformType(airportSn); + + if (platformType == null) { + throw new IllegalArgumentException( + String.format("机巢未注册或平台类型未配置: %s", airportSn)); + } + + CoverPlatformStrategy strategy = coverStrategyMap.get(platformType); + + if (strategy == null) { + throw new IllegalArgumentException( + String.format("未找到平台策略: %s (机巢: %s)", platformType.getName(), airportSn)); + } + + return strategy; + } + + /** + * 根据平台类型获取机巢平台策略 + * + * @param platformType 平台类型 + * @return 机巢平台策略 + */ + public AirportPlatformStrategy getAirportStrategyByType(PlatformType platformType) { + return airportStrategyMap.get(platformType); + } + + /** + * 根据平台类型获取舱门平台策略 + * + * @param platformType 平台类型 + * @return 舱门平台策略 + */ + public CoverPlatformStrategy getCoverStrategyByType(PlatformType platformType) { + return coverStrategyMap.get(platformType); + } + + /** + * 获取机巢的平台类型 + * + * @param airportSn 机巢序列号 + * @return 平台类型 + */ + public PlatformType getPlatformType(String airportSn) { + return airportPlatformRepository.getPlatformType(airportSn); + } +} diff --git a/src/main/java/com/tuoheng/status/airport/platform/impl/dji/DjiAirportPlatformStrategy.java b/src/main/java/com/tuoheng/status/airport/platform/impl/dji/DjiAirportPlatformStrategy.java new file mode 100644 index 0000000..cd3686d --- /dev/null +++ b/src/main/java/com/tuoheng/status/airport/platform/impl/dji/DjiAirportPlatformStrategy.java @@ -0,0 +1,142 @@ +package com.tuoheng.status.airport.platform.impl.dji; + +import com.tuoheng.status.airport.events.AirportEvent; +import com.tuoheng.status.airport.listener.DefaultAirportListener; +import com.tuoheng.status.airport.platform.PlatformType; +import com.tuoheng.status.airport.platform.impl.dji.action.airport.*; +import com.tuoheng.status.airport.platform.impl.dji.guard.airport.*; +import com.tuoheng.status.airport.platform.strategy.AirportPlatformStrategy; +import com.tuoheng.status.airport.platform.strategy.PlatformAction; +import com.tuoheng.status.airport.platform.strategy.PlatformGuard; +import com.tuoheng.status.airport.platform.strategy.PlatformListener; +import com.tuoheng.status.airport.status.AirportState; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +/** + * DJI平台机巢策略实现 + */ +@Component +public class DjiAirportPlatformStrategy implements AirportPlatformStrategy { + + @Autowired + private DjiCanOnlineGuard canOnlineGuard; + + @Autowired + private DjiCanOfflineGuard canOfflineGuard; + + @Autowired + private DjiIsDebugModeGuard isDebugModeGuard; + + @Autowired + private DjiIsNotDebugModeGuard isNotDebugModeGuard; + + @Autowired + private DjiCanCloseDebugModeGuard canCloseDebugModeGuard; + + @Autowired + private DjiIsRebootCompletedGuard isRebootCompletedGuard; + + @Autowired + private DjiOnlineAction onlineAction; + + @Autowired + private DjiOfflineAction offlineAction; + + @Autowired + private DjiOpenDebugModeAction openDebugModeAction; + + @Autowired + private DjiCloseDebugModeAction closeDebugModeAction; + + @Autowired + private DjiRebootAction rebootAction; + + @Autowired + private DjiRebootCompletedAction rebootCompletedAction; + + /** + * DJI平台的Listener实例(单例,所有DJI机巢共享) + */ + private final PlatformListener djiListener = new DefaultAirportListener() { + @Override + public String getName() { + return "DjiAirportListener"; + } + }; + + @Override + public PlatformType getPlatformType() { + return PlatformType.DJI; + } + + @Override + public PlatformGuard getCanOnlineGuard() { + return canOnlineGuard; + } + + @Override + public PlatformGuard getCanOfflineGuard() { + return canOfflineGuard; + } + + @Override + public PlatformGuard getIsDebugModeGuard() { + return isDebugModeGuard; + } + + @Override + public PlatformGuard getIsNotDebugModeGuard() { + return isNotDebugModeGuard; + } + + @Override + public PlatformGuard getCanCloseDebugModeGuard() { + return canCloseDebugModeGuard; + } + + @Override + public PlatformGuard getIsRebootCompletedGuard() { + return isRebootCompletedGuard; + } + + @Override + public PlatformAction getOnlineAction() { + return onlineAction; + } + + @Override + public PlatformAction getOfflineAction() { + return offlineAction; + } + + @Override + public PlatformAction getOpenDebugModeAction() { + return openDebugModeAction; + } + + @Override + public PlatformAction getCloseDebugModeAction() { + return closeDebugModeAction; + } + + @Override + public PlatformAction getRebootAction() { + return rebootAction; + } + + @Override + public PlatformAction getRebootCompletedAction() { + return rebootCompletedAction; + } + + @Override + public PlatformListener getListener() { + // 返回DJI平台的Listener单例 + // 所有DJI机巢共享这个Listener实例 + return djiListener; + } +} diff --git a/src/main/java/com/tuoheng/status/airport/platform/impl/dji/DjiCoverPlatformStrategy.java b/src/main/java/com/tuoheng/status/airport/platform/impl/dji/DjiCoverPlatformStrategy.java new file mode 100644 index 0000000..b8d0318 --- /dev/null +++ b/src/main/java/com/tuoheng/status/airport/platform/impl/dji/DjiCoverPlatformStrategy.java @@ -0,0 +1,123 @@ +package com.tuoheng.status.airport.platform.impl.dji; + +import com.tuoheng.status.airport.events.CoverEvent; +import com.tuoheng.status.airport.listener.DefaultCoverListener; +import com.tuoheng.status.airport.platform.PlatformType; +import com.tuoheng.status.airport.platform.impl.dji.action.cover.*; +import com.tuoheng.status.airport.platform.impl.dji.guard.cover.*; +import com.tuoheng.status.airport.platform.strategy.CoverPlatformStrategy; +import com.tuoheng.status.airport.platform.strategy.PlatformAction; +import com.tuoheng.status.airport.platform.strategy.PlatformGuard; +import com.tuoheng.status.airport.platform.strategy.PlatformListener; +import com.tuoheng.status.airport.status.CoverState; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +/** + * DJI平台舱门策略实现 + */ +@Component +public class DjiCoverPlatformStrategy implements CoverPlatformStrategy { + + @Autowired + private DjiCanOpenCoverGuard canOpenGuard; + + @Autowired + private DjiCanCloseCoverGuard canCloseGuard; + + @Autowired + private DjiIsCoverOpenedGuard isOpenedGuard; + + @Autowired + private DjiIsCoverClosedGuard isClosedGuard; + + @Autowired + private DjiOpenCoverAction openAction; + + @Autowired + private DjiCoverOpenedAction openedAction; + + @Autowired + private DjiCloseCoverAction closeAction; + + @Autowired + private DjiCoverClosedAction closedAction; + + @Autowired + private DjiCoverErrorAction errorAction; + + @Autowired + private DjiCoverResetAction resetAction; + + /** + * DJI平台的舱门Listener实例(单例,所有DJI机巢共享) + */ + private final PlatformListener djiCoverListener = new com.tuoheng.status.airport.listener.DefaultCoverListener() { + @Override + public String getName() { + return "DjiCoverListener"; + } + }; + + @Override + public PlatformType getPlatformType() { + return PlatformType.DJI; + } + + @Override + public PlatformGuard getCanOpenGuard() { + return canOpenGuard; + } + + @Override + public PlatformGuard getCanCloseGuard() { + return canCloseGuard; + } + + @Override + public PlatformGuard getIsOpenedGuard() { + return isOpenedGuard; + } + + @Override + public PlatformGuard getIsClosedGuard() { + return isClosedGuard; + } + + @Override + public PlatformAction getOpenAction() { + return openAction; + } + + @Override + public PlatformAction getOpenedAction() { + return openedAction; + } + + @Override + public PlatformAction getCloseAction() { + return closeAction; + } + + @Override + public PlatformAction getClosedAction() { + return closedAction; + } + + @Override + public PlatformAction getErrorAction() { + return errorAction; + } + + @Override + public PlatformAction getResetAction() { + return resetAction; + } + + @Override + public PlatformListener getListener() { + // 返回DJI平台的舱门Listener单例 + // 所有DJI机巢共享这个Listener实例 + return djiCoverListener; + } +} diff --git a/src/main/java/com/tuoheng/status/airport/platform/impl/dji/action/airport/DjiCloseDebugModeAction.java b/src/main/java/com/tuoheng/status/airport/platform/impl/dji/action/airport/DjiCloseDebugModeAction.java new file mode 100644 index 0000000..21e5c56 --- /dev/null +++ b/src/main/java/com/tuoheng/status/airport/platform/impl/dji/action/airport/DjiCloseDebugModeAction.java @@ -0,0 +1,22 @@ +package com.tuoheng.status.airport.platform.impl.dji.action.airport; + +import com.tuoheng.status.airport.events.AirportEvent; +import com.tuoheng.status.airport.platform.strategy.PlatformAction; +import com.tuoheng.status.airport.status.AirportState; +import org.springframework.statemachine.StateContext; +import org.springframework.stereotype.Component; + +@Component +public class DjiCloseDebugModeAction implements PlatformAction { + + @Override + public String getName() { + return "DjiCloseDebugModeAction"; + } + + @Override + public void execute(StateContext context) { + String machineId = (String) context.getExtendedState().getVariables().get("machineId"); + System.out.println(String.format("[DJI] 关闭调试模式: %s", machineId)); + } +} diff --git a/src/main/java/com/tuoheng/status/airport/platform/impl/dji/action/airport/DjiOfflineAction.java b/src/main/java/com/tuoheng/status/airport/platform/impl/dji/action/airport/DjiOfflineAction.java new file mode 100644 index 0000000..e0aa5c8 --- /dev/null +++ b/src/main/java/com/tuoheng/status/airport/platform/impl/dji/action/airport/DjiOfflineAction.java @@ -0,0 +1,22 @@ +package com.tuoheng.status.airport.platform.impl.dji.action.airport; + +import com.tuoheng.status.airport.events.AirportEvent; +import com.tuoheng.status.airport.platform.strategy.PlatformAction; +import com.tuoheng.status.airport.status.AirportState; +import org.springframework.statemachine.StateContext; +import org.springframework.stereotype.Component; + +@Component +public class DjiOfflineAction implements PlatformAction { + + @Override + public String getName() { + return "DjiOfflineAction"; + } + + @Override + public void execute(StateContext context) { + String machineId = (String) context.getExtendedState().getVariables().get("machineId"); + System.out.println(String.format("[DJI] 机巢离线: %s", machineId)); + } +} diff --git a/src/main/java/com/tuoheng/status/airport/platform/impl/dji/action/airport/DjiOnlineAction.java b/src/main/java/com/tuoheng/status/airport/platform/impl/dji/action/airport/DjiOnlineAction.java new file mode 100644 index 0000000..f3ecb69 --- /dev/null +++ b/src/main/java/com/tuoheng/status/airport/platform/impl/dji/action/airport/DjiOnlineAction.java @@ -0,0 +1,24 @@ +package com.tuoheng.status.airport.platform.impl.dji.action.airport; + +import com.tuoheng.status.airport.events.AirportEvent; +import com.tuoheng.status.airport.platform.strategy.PlatformAction; +import com.tuoheng.status.airport.status.AirportState; +import org.springframework.statemachine.StateContext; +import org.springframework.stereotype.Component; + +@Component +public class DjiOnlineAction implements PlatformAction { + + @Override + public String getName() { + return "DjiOnlineAction"; + } + + @Override + public void execute(StateContext context) { + String machineId = (String) context.getExtendedState().getVariables().get("machineId"); + System.out.println(String.format("[DJI] 机巢上线: %s", machineId)); + // DJI平台特定的上线逻辑 + // 例如:初始化DJI SDK连接、注册设备等 + } +} diff --git a/src/main/java/com/tuoheng/status/airport/platform/impl/dji/action/airport/DjiOpenDebugModeAction.java b/src/main/java/com/tuoheng/status/airport/platform/impl/dji/action/airport/DjiOpenDebugModeAction.java new file mode 100644 index 0000000..2677be9 --- /dev/null +++ b/src/main/java/com/tuoheng/status/airport/platform/impl/dji/action/airport/DjiOpenDebugModeAction.java @@ -0,0 +1,22 @@ +package com.tuoheng.status.airport.platform.impl.dji.action.airport; + +import com.tuoheng.status.airport.events.AirportEvent; +import com.tuoheng.status.airport.platform.strategy.PlatformAction; +import com.tuoheng.status.airport.status.AirportState; +import org.springframework.statemachine.StateContext; +import org.springframework.stereotype.Component; + +@Component +public class DjiOpenDebugModeAction implements PlatformAction { + + @Override + public String getName() { + return "DjiOpenDebugModeAction"; + } + + @Override + public void execute(StateContext context) { + String machineId = (String) context.getExtendedState().getVariables().get("machineId"); + System.out.println(String.format("[DJI] 开启调试模式: %s", machineId)); + } +} diff --git a/src/main/java/com/tuoheng/status/airport/platform/impl/dji/action/airport/DjiRebootAction.java b/src/main/java/com/tuoheng/status/airport/platform/impl/dji/action/airport/DjiRebootAction.java new file mode 100644 index 0000000..c38c726 --- /dev/null +++ b/src/main/java/com/tuoheng/status/airport/platform/impl/dji/action/airport/DjiRebootAction.java @@ -0,0 +1,22 @@ +package com.tuoheng.status.airport.platform.impl.dji.action.airport; + +import com.tuoheng.status.airport.events.AirportEvent; +import com.tuoheng.status.airport.platform.strategy.PlatformAction; +import com.tuoheng.status.airport.status.AirportState; +import org.springframework.statemachine.StateContext; +import org.springframework.stereotype.Component; + +@Component +public class DjiRebootAction implements PlatformAction { + + @Override + public String getName() { + return "DjiRebootAction"; + } + + @Override + public void execute(StateContext context) { + String machineId = (String) context.getExtendedState().getVariables().get("machineId"); + System.out.println(String.format("[DJI] 机巢重启: %s", machineId)); + } +} diff --git a/src/main/java/com/tuoheng/status/airport/platform/impl/dji/action/airport/DjiRebootCompletedAction.java b/src/main/java/com/tuoheng/status/airport/platform/impl/dji/action/airport/DjiRebootCompletedAction.java new file mode 100644 index 0000000..f56ec1a --- /dev/null +++ b/src/main/java/com/tuoheng/status/airport/platform/impl/dji/action/airport/DjiRebootCompletedAction.java @@ -0,0 +1,22 @@ +package com.tuoheng.status.airport.platform.impl.dji.action.airport; + +import com.tuoheng.status.airport.events.AirportEvent; +import com.tuoheng.status.airport.platform.strategy.PlatformAction; +import com.tuoheng.status.airport.status.AirportState; +import org.springframework.statemachine.StateContext; +import org.springframework.stereotype.Component; + +@Component +public class DjiRebootCompletedAction implements PlatformAction { + + @Override + public String getName() { + return "DjiRebootCompletedAction"; + } + + @Override + public void execute(StateContext context) { + String machineId = (String) context.getExtendedState().getVariables().get("machineId"); + System.out.println(String.format("[DJI] 重启完成: %s", machineId)); + } +} diff --git a/src/main/java/com/tuoheng/status/airport/platform/impl/dji/action/cover/DjiCloseCoverAction.java b/src/main/java/com/tuoheng/status/airport/platform/impl/dji/action/cover/DjiCloseCoverAction.java new file mode 100644 index 0000000..28c3693 --- /dev/null +++ b/src/main/java/com/tuoheng/status/airport/platform/impl/dji/action/cover/DjiCloseCoverAction.java @@ -0,0 +1,22 @@ +package com.tuoheng.status.airport.platform.impl.dji.action.cover; + +import com.tuoheng.status.airport.events.CoverEvent; +import com.tuoheng.status.airport.platform.strategy.PlatformAction; +import com.tuoheng.status.airport.status.CoverState; +import org.springframework.statemachine.StateContext; +import org.springframework.stereotype.Component; + +@Component +public class DjiCloseCoverAction implements PlatformAction { + + @Override + public String getName() { + return "DjiCloseCoverAction"; + } + + @Override + public void execute(StateContext context) { + String machineId = (String) context.getExtendedState().getVariables().get("machineId"); + System.out.println(String.format("[DJI] 开始关舱: %s", machineId)); + } +} diff --git a/src/main/java/com/tuoheng/status/airport/platform/impl/dji/action/cover/DjiCoverClosedAction.java b/src/main/java/com/tuoheng/status/airport/platform/impl/dji/action/cover/DjiCoverClosedAction.java new file mode 100644 index 0000000..6e832c7 --- /dev/null +++ b/src/main/java/com/tuoheng/status/airport/platform/impl/dji/action/cover/DjiCoverClosedAction.java @@ -0,0 +1,22 @@ +package com.tuoheng.status.airport.platform.impl.dji.action.cover; + +import com.tuoheng.status.airport.events.CoverEvent; +import com.tuoheng.status.airport.platform.strategy.PlatformAction; +import com.tuoheng.status.airport.status.CoverState; +import org.springframework.statemachine.StateContext; +import org.springframework.stereotype.Component; + +@Component +public class DjiCoverClosedAction implements PlatformAction { + + @Override + public String getName() { + return "DjiCoverClosedAction"; + } + + @Override + public void execute(StateContext context) { + String machineId = (String) context.getExtendedState().getVariables().get("machineId"); + System.out.println(String.format("[DJI] 舱门已关闭: %s", machineId)); + } +} diff --git a/src/main/java/com/tuoheng/status/airport/platform/impl/dji/action/cover/DjiCoverErrorAction.java b/src/main/java/com/tuoheng/status/airport/platform/impl/dji/action/cover/DjiCoverErrorAction.java new file mode 100644 index 0000000..3de1c98 --- /dev/null +++ b/src/main/java/com/tuoheng/status/airport/platform/impl/dji/action/cover/DjiCoverErrorAction.java @@ -0,0 +1,22 @@ +package com.tuoheng.status.airport.platform.impl.dji.action.cover; + +import com.tuoheng.status.airport.events.CoverEvent; +import com.tuoheng.status.airport.platform.strategy.PlatformAction; +import com.tuoheng.status.airport.status.CoverState; +import org.springframework.statemachine.StateContext; +import org.springframework.stereotype.Component; + +@Component +public class DjiCoverErrorAction implements PlatformAction { + + @Override + public String getName() { + return "DjiCoverErrorAction"; + } + + @Override + public void execute(StateContext context) { + String machineId = (String) context.getExtendedState().getVariables().get("machineId"); + System.out.println(String.format("[DJI] 舱门错误: %s", machineId)); + } +} diff --git a/src/main/java/com/tuoheng/status/airport/platform/impl/dji/action/cover/DjiCoverOpenedAction.java b/src/main/java/com/tuoheng/status/airport/platform/impl/dji/action/cover/DjiCoverOpenedAction.java new file mode 100644 index 0000000..0c26e9e --- /dev/null +++ b/src/main/java/com/tuoheng/status/airport/platform/impl/dji/action/cover/DjiCoverOpenedAction.java @@ -0,0 +1,22 @@ +package com.tuoheng.status.airport.platform.impl.dji.action.cover; + +import com.tuoheng.status.airport.events.CoverEvent; +import com.tuoheng.status.airport.platform.strategy.PlatformAction; +import com.tuoheng.status.airport.status.CoverState; +import org.springframework.statemachine.StateContext; +import org.springframework.stereotype.Component; + +@Component +public class DjiCoverOpenedAction implements PlatformAction { + + @Override + public String getName() { + return "DjiCoverOpenedAction"; + } + + @Override + public void execute(StateContext context) { + String machineId = (String) context.getExtendedState().getVariables().get("machineId"); + System.out.println(String.format("[DJI] 舱门已打开: %s", machineId)); + } +} diff --git a/src/main/java/com/tuoheng/status/airport/platform/impl/dji/action/cover/DjiCoverResetAction.java b/src/main/java/com/tuoheng/status/airport/platform/impl/dji/action/cover/DjiCoverResetAction.java new file mode 100644 index 0000000..330b10b --- /dev/null +++ b/src/main/java/com/tuoheng/status/airport/platform/impl/dji/action/cover/DjiCoverResetAction.java @@ -0,0 +1,22 @@ +package com.tuoheng.status.airport.platform.impl.dji.action.cover; + +import com.tuoheng.status.airport.events.CoverEvent; +import com.tuoheng.status.airport.platform.strategy.PlatformAction; +import com.tuoheng.status.airport.status.CoverState; +import org.springframework.statemachine.StateContext; +import org.springframework.stereotype.Component; + +@Component +public class DjiCoverResetAction implements PlatformAction { + + @Override + public String getName() { + return "DjiCoverResetAction"; + } + + @Override + public void execute(StateContext context) { + String machineId = (String) context.getExtendedState().getVariables().get("machineId"); + System.out.println(String.format("[DJI] 舱门重置: %s", machineId)); + } +} diff --git a/src/main/java/com/tuoheng/status/airport/platform/impl/dji/action/cover/DjiOpenCoverAction.java b/src/main/java/com/tuoheng/status/airport/platform/impl/dji/action/cover/DjiOpenCoverAction.java new file mode 100644 index 0000000..1b1236e --- /dev/null +++ b/src/main/java/com/tuoheng/status/airport/platform/impl/dji/action/cover/DjiOpenCoverAction.java @@ -0,0 +1,23 @@ +package com.tuoheng.status.airport.platform.impl.dji.action.cover; + +import com.tuoheng.status.airport.events.CoverEvent; +import com.tuoheng.status.airport.platform.strategy.PlatformAction; +import com.tuoheng.status.airport.status.CoverState; +import org.springframework.statemachine.StateContext; +import org.springframework.stereotype.Component; + +@Component +public class DjiOpenCoverAction implements PlatformAction { + + @Override + public String getName() { + return "DjiOpenCoverAction"; + } + + @Override + public void execute(StateContext context) { + String machineId = (String) context.getExtendedState().getVariables().get("machineId"); + System.out.println(String.format("[DJI] 开始开舱: %s", machineId)); + // DJI平台特定的开舱逻辑 + } +} diff --git a/src/main/java/com/tuoheng/status/airport/platform/impl/dji/guard/airport/DjiCanCloseDebugModeGuard.java b/src/main/java/com/tuoheng/status/airport/platform/impl/dji/guard/airport/DjiCanCloseDebugModeGuard.java new file mode 100644 index 0000000..024ed74 --- /dev/null +++ b/src/main/java/com/tuoheng/status/airport/platform/impl/dji/guard/airport/DjiCanCloseDebugModeGuard.java @@ -0,0 +1,22 @@ +package com.tuoheng.status.airport.platform.impl.dji.guard.airport; + +import com.tuoheng.status.airport.events.AirportEvent; +import com.tuoheng.status.airport.platform.strategy.PlatformGuard; +import com.tuoheng.status.airport.status.AirportState; +import org.springframework.statemachine.StateContext; +import org.springframework.stereotype.Component; + +@Component +public class DjiCanCloseDebugModeGuard implements PlatformGuard { + + @Override + public String getName() { + return "DjiCanCloseDebugModeGuard"; + } + + @Override + public boolean evaluate(StateContext context) { + System.out.println("[DJI] 检查是否可以关闭调试模式"); + return true; + } +} diff --git a/src/main/java/com/tuoheng/status/airport/platform/impl/dji/guard/airport/DjiCanOfflineGuard.java b/src/main/java/com/tuoheng/status/airport/platform/impl/dji/guard/airport/DjiCanOfflineGuard.java new file mode 100644 index 0000000..bfeb737 --- /dev/null +++ b/src/main/java/com/tuoheng/status/airport/platform/impl/dji/guard/airport/DjiCanOfflineGuard.java @@ -0,0 +1,22 @@ +package com.tuoheng.status.airport.platform.impl.dji.guard.airport; + +import com.tuoheng.status.airport.events.AirportEvent; +import com.tuoheng.status.airport.platform.strategy.PlatformGuard; +import com.tuoheng.status.airport.status.AirportState; +import org.springframework.statemachine.StateContext; +import org.springframework.stereotype.Component; + +@Component +public class DjiCanOfflineGuard implements PlatformGuard { + + @Override + public String getName() { + return "DjiCanOfflineGuard"; + } + + @Override + public boolean evaluate(StateContext context) { + System.out.println("[DJI] 检查机巢是否可以离线"); + return true; + } +} diff --git a/src/main/java/com/tuoheng/status/airport/platform/impl/dji/guard/airport/DjiCanOnlineGuard.java b/src/main/java/com/tuoheng/status/airport/platform/impl/dji/guard/airport/DjiCanOnlineGuard.java new file mode 100644 index 0000000..baf4bab --- /dev/null +++ b/src/main/java/com/tuoheng/status/airport/platform/impl/dji/guard/airport/DjiCanOnlineGuard.java @@ -0,0 +1,30 @@ +package com.tuoheng.status.airport.platform.impl.dji.guard.airport; + +import com.tuoheng.status.airport.events.AirportEvent; +import com.tuoheng.status.airport.platform.strategy.PlatformGuard; +import com.tuoheng.status.airport.status.AirportState; +import org.springframework.statemachine.StateContext; +import org.springframework.stereotype.Component; + +/** + * DJI平台 - 机巢上线Guard + */ +@Component +public class DjiCanOnlineGuard implements PlatformGuard { + + @Override + public String getName() { + return "DjiCanOnlineGuard"; + } + + @Override + public boolean evaluate(StateContext context) { + // DJI平台特定的上线检查逻辑 + System.out.println("[DJI] 检查机巢是否可以上线"); + // 这里可以添加DJI平台特定的检查逻辑,例如: + // - 检查DJI设备连接状态 + // - 检查DJI固件版本 + // - 检查DJI授权状态 + return true; + } +} diff --git a/src/main/java/com/tuoheng/status/airport/platform/impl/dji/guard/airport/DjiIsDebugModeGuard.java b/src/main/java/com/tuoheng/status/airport/platform/impl/dji/guard/airport/DjiIsDebugModeGuard.java new file mode 100644 index 0000000..6a6b721 --- /dev/null +++ b/src/main/java/com/tuoheng/status/airport/platform/impl/dji/guard/airport/DjiIsDebugModeGuard.java @@ -0,0 +1,22 @@ +package com.tuoheng.status.airport.platform.impl.dji.guard.airport; + +import com.tuoheng.status.airport.events.AirportEvent; +import com.tuoheng.status.airport.platform.strategy.PlatformGuard; +import com.tuoheng.status.airport.status.AirportState; +import org.springframework.statemachine.StateContext; +import org.springframework.stereotype.Component; + +@Component +public class DjiIsDebugModeGuard implements PlatformGuard { + + @Override + public String getName() { + return "DjiIsDebugModeGuard"; + } + + @Override + public boolean evaluate(StateContext context) { + System.out.println("[DJI] 检查是否处于调试模式"); + return true; + } +} diff --git a/src/main/java/com/tuoheng/status/airport/platform/impl/dji/guard/airport/DjiIsNotDebugModeGuard.java b/src/main/java/com/tuoheng/status/airport/platform/impl/dji/guard/airport/DjiIsNotDebugModeGuard.java new file mode 100644 index 0000000..d57f25a --- /dev/null +++ b/src/main/java/com/tuoheng/status/airport/platform/impl/dji/guard/airport/DjiIsNotDebugModeGuard.java @@ -0,0 +1,22 @@ +package com.tuoheng.status.airport.platform.impl.dji.guard.airport; + +import com.tuoheng.status.airport.events.AirportEvent; +import com.tuoheng.status.airport.platform.strategy.PlatformGuard; +import com.tuoheng.status.airport.status.AirportState; +import org.springframework.statemachine.StateContext; +import org.springframework.stereotype.Component; + +@Component +public class DjiIsNotDebugModeGuard implements PlatformGuard { + + @Override + public String getName() { + return "DjiIsNotDebugModeGuard"; + } + + @Override + public boolean evaluate(StateContext context) { + System.out.println("[DJI] 检查是否不在调试模式"); + return true; + } +} diff --git a/src/main/java/com/tuoheng/status/airport/platform/impl/dji/guard/airport/DjiIsRebootCompletedGuard.java b/src/main/java/com/tuoheng/status/airport/platform/impl/dji/guard/airport/DjiIsRebootCompletedGuard.java new file mode 100644 index 0000000..f9cd241 --- /dev/null +++ b/src/main/java/com/tuoheng/status/airport/platform/impl/dji/guard/airport/DjiIsRebootCompletedGuard.java @@ -0,0 +1,22 @@ +package com.tuoheng.status.airport.platform.impl.dji.guard.airport; + +import com.tuoheng.status.airport.events.AirportEvent; +import com.tuoheng.status.airport.platform.strategy.PlatformGuard; +import com.tuoheng.status.airport.status.AirportState; +import org.springframework.statemachine.StateContext; +import org.springframework.stereotype.Component; + +@Component +public class DjiIsRebootCompletedGuard implements PlatformGuard { + + @Override + public String getName() { + return "DjiIsRebootCompletedGuard"; + } + + @Override + public boolean evaluate(StateContext context) { + System.out.println("[DJI] 检查重启是否完成"); + return true; + } +} diff --git a/src/main/java/com/tuoheng/status/airport/platform/impl/dji/guard/cover/DjiCanCloseCoverGuard.java b/src/main/java/com/tuoheng/status/airport/platform/impl/dji/guard/cover/DjiCanCloseCoverGuard.java new file mode 100644 index 0000000..a97e92d --- /dev/null +++ b/src/main/java/com/tuoheng/status/airport/platform/impl/dji/guard/cover/DjiCanCloseCoverGuard.java @@ -0,0 +1,22 @@ +package com.tuoheng.status.airport.platform.impl.dji.guard.cover; + +import com.tuoheng.status.airport.events.CoverEvent; +import com.tuoheng.status.airport.platform.strategy.PlatformGuard; +import com.tuoheng.status.airport.status.CoverState; +import org.springframework.statemachine.StateContext; +import org.springframework.stereotype.Component; + +@Component +public class DjiCanCloseCoverGuard implements PlatformGuard { + + @Override + public String getName() { + return "DjiCanCloseCoverGuard"; + } + + @Override + public boolean evaluate(StateContext context) { + System.out.println("[DJI] 检查舱门是否可以关闭"); + return true; + } +} diff --git a/src/main/java/com/tuoheng/status/airport/platform/impl/dji/guard/cover/DjiCanOpenCoverGuard.java b/src/main/java/com/tuoheng/status/airport/platform/impl/dji/guard/cover/DjiCanOpenCoverGuard.java new file mode 100644 index 0000000..c98de91 --- /dev/null +++ b/src/main/java/com/tuoheng/status/airport/platform/impl/dji/guard/cover/DjiCanOpenCoverGuard.java @@ -0,0 +1,22 @@ +package com.tuoheng.status.airport.platform.impl.dji.guard.cover; + +import com.tuoheng.status.airport.events.CoverEvent; +import com.tuoheng.status.airport.platform.strategy.PlatformGuard; +import com.tuoheng.status.airport.status.CoverState; +import org.springframework.statemachine.StateContext; +import org.springframework.stereotype.Component; + +@Component +public class DjiCanOpenCoverGuard implements PlatformGuard { + + @Override + public String getName() { + return "DjiCanOpenCoverGuard"; + } + + @Override + public boolean evaluate(StateContext context) { + System.out.println("[DJI] 检查舱门是否可以打开"); + return true; + } +} diff --git a/src/main/java/com/tuoheng/status/airport/platform/impl/dji/guard/cover/DjiIsCoverClosedGuard.java b/src/main/java/com/tuoheng/status/airport/platform/impl/dji/guard/cover/DjiIsCoverClosedGuard.java new file mode 100644 index 0000000..fb80606 --- /dev/null +++ b/src/main/java/com/tuoheng/status/airport/platform/impl/dji/guard/cover/DjiIsCoverClosedGuard.java @@ -0,0 +1,22 @@ +package com.tuoheng.status.airport.platform.impl.dji.guard.cover; + +import com.tuoheng.status.airport.events.CoverEvent; +import com.tuoheng.status.airport.platform.strategy.PlatformGuard; +import com.tuoheng.status.airport.status.CoverState; +import org.springframework.statemachine.StateContext; +import org.springframework.stereotype.Component; + +@Component +public class DjiIsCoverClosedGuard implements PlatformGuard { + + @Override + public String getName() { + return "DjiIsCoverClosedGuard"; + } + + @Override + public boolean evaluate(StateContext context) { + System.out.println("[DJI] 检查舱门是否已关闭"); + return true; + } +} diff --git a/src/main/java/com/tuoheng/status/airport/platform/impl/dji/guard/cover/DjiIsCoverOpenedGuard.java b/src/main/java/com/tuoheng/status/airport/platform/impl/dji/guard/cover/DjiIsCoverOpenedGuard.java new file mode 100644 index 0000000..cf28d1d --- /dev/null +++ b/src/main/java/com/tuoheng/status/airport/platform/impl/dji/guard/cover/DjiIsCoverOpenedGuard.java @@ -0,0 +1,22 @@ +package com.tuoheng.status.airport.platform.impl.dji.guard.cover; + +import com.tuoheng.status.airport.events.CoverEvent; +import com.tuoheng.status.airport.platform.strategy.PlatformGuard; +import com.tuoheng.status.airport.status.CoverState; +import org.springframework.statemachine.StateContext; +import org.springframework.stereotype.Component; + +@Component +public class DjiIsCoverOpenedGuard implements PlatformGuard { + + @Override + public String getName() { + return "DjiIsCoverOpenedGuard"; + } + + @Override + public boolean evaluate(StateContext context) { + System.out.println("[DJI] 检查舱门是否已打开"); + return true; + } +} diff --git a/src/main/java/com/tuoheng/status/airport/platform/repository/AirportPlatformRepository.java b/src/main/java/com/tuoheng/status/airport/platform/repository/AirportPlatformRepository.java new file mode 100644 index 0000000..a896585 --- /dev/null +++ b/src/main/java/com/tuoheng/status/airport/platform/repository/AirportPlatformRepository.java @@ -0,0 +1,74 @@ +package com.tuoheng.status.airport.platform.repository; + +import com.tuoheng.status.airport.platform.PlatformType; +import org.springframework.stereotype.Repository; + +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +/** + * 机巢平台映射仓储 + * 模拟数据库查询,存储机巢SN到平台类型的映射关系 + */ +@Repository +public class AirportPlatformRepository { + + /** + * 模拟数据库存储 + * Key: 机巢SN + * Value: 平台类型 + */ + private final Map airportPlatformMap = new ConcurrentHashMap<>(); + + /** + * 初始化一些测试数据 + */ + public AirportPlatformRepository() { + // 模拟数据库中的数据 + airportPlatformMap.put("airport-001", PlatformType.DJI); + airportPlatformMap.put("airport-002", PlatformType.DJI); + airportPlatformMap.put("airport-003", PlatformType.DJI); + airportPlatformMap.put("airport-004", PlatformType.DJI); + } + + /** + * 根据机巢SN查询平台类型 + * + * @param airportSn 机巢序列号 + * @return 平台类型,如果不存在返回null + */ + public PlatformType getPlatformType(String airportSn) { + return airportPlatformMap.get(airportSn); + } + + /** + * 保存机巢平台映射关系 + * + * @param airportSn 机巢序列号 + * @param platformType 平台类型 + */ + public void savePlatformMapping(String airportSn, PlatformType platformType) { + airportPlatformMap.put(airportSn, platformType); + System.out.println(String.format("保存平台映射: %s -> %s", airportSn, platformType.getName())); + } + + /** + * 删除机巢平台映射关系 + * + * @param airportSn 机巢序列号 + */ + public void deletePlatformMapping(String airportSn) { + airportPlatformMap.remove(airportSn); + System.out.println(String.format("删除平台映射: %s", airportSn)); + } + + /** + * 检查机巢是否已注册 + * + * @param airportSn 机巢序列号 + * @return 是否已注册 + */ + public boolean exists(String airportSn) { + return airportPlatformMap.containsKey(airportSn); + } +} diff --git a/src/main/java/com/tuoheng/status/airport/platform/strategy/AirportPlatformStrategy.java b/src/main/java/com/tuoheng/status/airport/platform/strategy/AirportPlatformStrategy.java new file mode 100644 index 0000000..860c43e --- /dev/null +++ b/src/main/java/com/tuoheng/status/airport/platform/strategy/AirportPlatformStrategy.java @@ -0,0 +1,53 @@ +package com.tuoheng.status.airport.platform.strategy; + +import com.tuoheng.status.airport.events.AirportEvent; +import com.tuoheng.status.airport.platform.PlatformType; +import com.tuoheng.status.airport.status.AirportState; + +/** + * 机巢平台策略接口 + * 定义各平台需要实现的Guard、Action和Listener + */ +public interface AirportPlatformStrategy { + + /** + * 获取平台类型 + */ + PlatformType getPlatformType(); + + // ==================== Guards ==================== + + PlatformGuard getCanOnlineGuard(); + + PlatformGuard getCanOfflineGuard(); + + PlatformGuard getIsDebugModeGuard(); + + PlatformGuard getIsNotDebugModeGuard(); + + PlatformGuard getCanCloseDebugModeGuard(); + + PlatformGuard getIsRebootCompletedGuard(); + + // ==================== Actions ==================== + + PlatformAction getOnlineAction(); + + PlatformAction getOfflineAction(); + + PlatformAction getOpenDebugModeAction(); + + PlatformAction getCloseDebugModeAction(); + + PlatformAction getRebootAction(); + + PlatformAction getRebootCompletedAction(); + + // ==================== Listener ==================== + + /** + * 获取平台Listener + * 每个平台有一个Listener实例,所有该平台的机巢共享 + */ + PlatformListener getListener(); +} diff --git a/src/main/java/com/tuoheng/status/airport/platform/strategy/CoverPlatformStrategy.java b/src/main/java/com/tuoheng/status/airport/platform/strategy/CoverPlatformStrategy.java new file mode 100644 index 0000000..7db562e --- /dev/null +++ b/src/main/java/com/tuoheng/status/airport/platform/strategy/CoverPlatformStrategy.java @@ -0,0 +1,49 @@ +package com.tuoheng.status.airport.platform.strategy; + +import com.tuoheng.status.airport.events.CoverEvent; +import com.tuoheng.status.airport.platform.PlatformType; +import com.tuoheng.status.airport.status.CoverState; + +/** + * 舱门平台策略接口 + * 定义各平台需要实现的Guard、Action和Listener + */ +public interface CoverPlatformStrategy { + + /** + * 获取平台类型 + */ + PlatformType getPlatformType(); + + // ==================== Guards ==================== + + PlatformGuard getCanOpenGuard(); + + PlatformGuard getCanCloseGuard(); + + PlatformGuard getIsOpenedGuard(); + + PlatformGuard getIsClosedGuard(); + + // ==================== Actions ==================== + + PlatformAction getOpenAction(); + + PlatformAction getOpenedAction(); + + PlatformAction getCloseAction(); + + PlatformAction getClosedAction(); + + PlatformAction getErrorAction(); + + PlatformAction getResetAction(); + + // ==================== Listener ==================== + + /** + * 获取平台Listener + * 每个平台有一个Listener实例,所有该平台的机巢共享 + */ + PlatformListener getListener(); +} diff --git a/src/main/java/com/tuoheng/status/airport/platform/strategy/PlatformAction.java b/src/main/java/com/tuoheng/status/airport/platform/strategy/PlatformAction.java new file mode 100644 index 0000000..5756757 --- /dev/null +++ b/src/main/java/com/tuoheng/status/airport/platform/strategy/PlatformAction.java @@ -0,0 +1,22 @@ +package com.tuoheng.status.airport.platform.strategy; + +import org.springframework.statemachine.StateContext; +import org.springframework.statemachine.action.Action; + +/** + * 平台Action接口 + * 各平台实现自己的Action逻辑 + */ +public interface PlatformAction extends Action { + + /** + * 获取Action名称 + */ + String getName(); + + /** + * 执行Action + */ + @Override + void execute(StateContext context); +} diff --git a/src/main/java/com/tuoheng/status/airport/platform/strategy/PlatformGuard.java b/src/main/java/com/tuoheng/status/airport/platform/strategy/PlatformGuard.java new file mode 100644 index 0000000..e367391 --- /dev/null +++ b/src/main/java/com/tuoheng/status/airport/platform/strategy/PlatformGuard.java @@ -0,0 +1,22 @@ +package com.tuoheng.status.airport.platform.strategy; + +import org.springframework.statemachine.StateContext; +import org.springframework.statemachine.guard.Guard; + +/** + * 平台Guard接口 + * 各平台实现自己的Guard逻辑 + */ +public interface PlatformGuard extends Guard { + + /** + * 获取Guard名称 + */ + String getName(); + + /** + * 评估Guard条件 + */ + @Override + boolean evaluate(StateContext context); +} diff --git a/src/main/java/com/tuoheng/status/airport/platform/strategy/PlatformListener.java b/src/main/java/com/tuoheng/status/airport/platform/strategy/PlatformListener.java new file mode 100644 index 0000000..359fcbd --- /dev/null +++ b/src/main/java/com/tuoheng/status/airport/platform/strategy/PlatformListener.java @@ -0,0 +1,15 @@ +package com.tuoheng.status.airport.platform.strategy; + +import org.springframework.statemachine.listener.StateMachineListener; + +/** + * 平台Listener接口 + * 各平台可以定制自己的Listener逻辑 + */ +public interface PlatformListener extends StateMachineListener { + + /** + * 获取Listener名称 + */ + String getName(); +}