package com.battery.device.api.registry; import java.util.HashMap; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.Objects; import java.util.concurrent.locks.ReentrantLock; import java.util.function.Function; import com.battery.device.api.DeviceAdapter; import com.battery.device.api.TestDataObservationAdapter; /** 管理启用设备适配器的运行时实例及其会话生命周期。 */ public final class DeviceAdapterRegistry implements AutoCloseable { private final Map factories = new HashMap<>(); private final Map adapters = new HashMap<>(); public DeviceAdapterRegistry(List factories) { Objects.requireNonNull(factories, "factories").forEach(factory -> { String type = normalizeType(factory.adapterType()); if (this.factories.put(type, factory) != null) throw new IllegalArgumentException("Duplicate device adapter factory: " + type); }); } /** 按数据库或代码配置注册、替换或移除运行时实例。 */ public void synchronize(AdapterInstanceConfig config) { Objects.requireNonNull(config, "config"); if (!config.enabled()) { remove(config.adapterCode()); return; } synchronized (this) { RegisteredAdapter current = adapters.get(config.adapterCode()); if (current != null && current.config.equals(config)) return; if (!factories.containsKey(normalizeType(config.adapterType()))) throw new AdapterRegistryException("Unsupported device adapter type: " + config.adapterType()); } DeviceAdapterFactory factory = factories.get(normalizeType(config.adapterType())); register(config, factory.create(config)); } /** * 注册已构造的运行时实例。代码装配实例与数据库配置实例共用同一份实例表, * 使发现与取数按同一适配器编码解析,避免同编码出现两个实例。 */ public void register(AdapterInstanceConfig config, DeviceAdapter adapter) { Objects.requireNonNull(config, "config"); Objects.requireNonNull(adapter, "adapter"); if (!config.enabled()) { remove(config.adapterCode()); return; } RegisteredAdapter previous; synchronized (this) { previous = adapters.put(config.adapterCode(), new RegisteredAdapter(config, adapter)); } closeWhenIdle(previous); } /** 在实例级串行边界内执行一次适配器操作;未注册时给出可识别失败。 */ public T execute(String adapterCode, Function operation) { Objects.requireNonNull(operation, "operation"); RegisteredAdapter registered = acquire(adapterCode); try { return operation.apply(registered.adapter); } finally { registered.operationLock.unlock(); } } /** * 在实例级串行边界内按测试数据观测契约执行。 * 实例缺失或未提供该契约时明确失败,不回退到其他实例。 */ public T executeTestData(String adapterCode, Function operation) { Objects.requireNonNull(operation, "operation"); RegisteredAdapter registered = acquire(adapterCode); try { if (!(registered.adapter instanceof TestDataObservationAdapter observation)) throw new AdapterRegistryException( "Device adapter does not expose test data observation: " + adapterCode); return operation.apply(observation); } finally { registered.operationLock.unlock(); } } /** 取用实例并持有其串行锁;调用方必须在 finally 中释放。 */ private RegisteredAdapter acquire(String adapterCode) { RegisteredAdapter registered; synchronized (this) { registered = adapters.get(adapterCode); if (registered == null) throw new AdapterRegistryException("Device adapter is not enabled: " + adapterCode); registered.operationLock.lock(); } return registered; } /** 返回指定编码的适配器实例当前是否已注册。 */ public synchronized boolean contains(String adapterCode) { return adapters.containsKey(adapterCode); } /** 关闭全部已注册实例并清空实例表;逐个等待在途操作结束。 */ @Override public void close() { List registered; synchronized (this) { registered = List.copyOf(adapters.values()); adapters.clear(); } registered.forEach(this::closeWhenIdle); } private void remove(String adapterCode) { RegisteredAdapter previous; synchronized (this) { previous = adapters.remove(adapterCode); } closeWhenIdle(previous); } private void closeWhenIdle(RegisteredAdapter registered) { if (registered == null) return; registered.operationLock.lock(); try { registered.adapter.close(); } finally { registered.operationLock.unlock(); } } private static String normalizeType(String value) { return Objects.requireNonNull(value, "adapterType").trim().toUpperCase(Locale.ROOT); } private static final class RegisteredAdapter { private final AdapterInstanceConfig config; private final DeviceAdapter adapter; private final ReentrantLock operationLock = new ReentrantLock(true); private RegisteredAdapter(AdapterInstanceConfig config, DeviceAdapter adapter) { this.config = config; this.adapter = adapter; } } }