package com.battery.business.service.impl;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.springframework.context.annotation.Primary;
import org.springframework.stereotype.Service;
import com.battery.device.api.TestDataObservationAdapter;
import com.battery.device.api.model.AdapterCapabilities;
import com.battery.device.api.model.ChannelIdentity;
import com.battery.device.api.model.DetectedChannel;
import com.battery.device.api.model.DeviceObservation;
import com.battery.device.api.registry.DeviceAdapterRegistry;
/**
* 把取数请求按通道身份里的适配器编码送到它所属的来源实例。
*
*
这是持久化与实时展示路径上唯一的取数入口:同一个进程里可以注册多个来源实例,
* 每个通道的请求只送到它自己的实例;实例缺失或未提供测试数据观测契约时明确失败,
* 不回退到其他实例。发现不走这里,它按实例在 {@link DeviceDiscoveryPersistenceService} 中执行。
*
*
声明为 {@code @Primary}:来源实例可能自己也实现了观测契约(开发模拟器就是这样,
* 它同时是 Spring Bean),业务侧注入的必须是这个按编码解析的入口,而不是某台设备的实例。
*/
@Service
@Primary
public class RoutingTestDataObservationAdapter implements TestDataObservationAdapter
{
/** 聚合路由不是来源实例,这个编码只用于说明"按通道身份路由"。 */
public static final String ADAPTER_CODE = "by-source";
private final DeviceAdapterRegistry registry;
public RoutingTestDataObservationAdapter(DeviceAdapterRegistry registry)
{
this.registry = registry;
}
@Override
public String adapterCode()
{
return ADAPTER_CODE;
}
@Override
public AdapterCapabilities capabilities()
{
return AdapterCapabilities.observeOnly();
}
/** 聚合适配器不承载发现;发现按来源实例执行,避免在这条路上猜一个设备。 */
@Override
public List discoverChannels()
{
throw new UnsupportedOperationException("设备发现按来源实例执行,不在聚合适配器上执行");
}
/** 一次观测里的通道可能来自多个来源实例,逐个按各自的编码请求,不能按第一个通道决定全部。 */
@Override
public Map observe(Set channels)
{
if (channels == null || channels.isEmpty()) return Map.of();
Map result = new java.util.LinkedHashMap<>();
for (Map.Entry> group : groupBySource(channels).entrySet())
{
Set groupChannels = new java.util.LinkedHashSet<>(group.getValue());
result.putAll(registry.executeTestData(group.getKey(), adapter -> adapter.observe(groupChannels)));
}
return Map.copyOf(result);
}
private static Map> groupBySource(Set channels)
{
Map> grouped = new java.util.LinkedHashMap<>();
for (ChannelIdentity channel : channels)
grouped.computeIfAbsent(channel.adapterCode(), ignored -> new java.util.ArrayList<>()).add(channel);
return grouped;
}
@Override
public CabinetRealtime latestCabinet(ChannelIdentity channel)
{
return registry.executeTestData(channel.adapterCode(), adapter -> adapter.latestCabinet(channel));
}
@Override
public CollectorRealtime latestCollector(String adapterCode, String collectorCode)
{
// 采集器测量属于某个来源实例的辅助测量,按该实例请求;实例缺失时明确失败。
// 来源编码为空说明测试电池连检测柜绑定都没有,此时来源未知:不猜也不回退,报无法请求。
if (adapterCode == null || adapterCode.isBlank()) return null;
return registry.executeTestData(adapterCode, adapter -> adapter.latestCollector(adapterCode, collectorCode));
}
@Override
public List stepRecords(ChannelIdentity channel)
{
return registry.executeTestData(channel.adapterCode(), adapter -> adapter.stepRecords(channel));
}
@Override
public List cycleRecords(ChannelIdentity channel)
{
return registry.executeTestData(channel.adapterCode(), adapter -> adapter.cycleRecords(channel));
}
@Override
public long persistenceIntervalMillis(ChannelIdentity channel)
{
return registry.executeTestData(channel.adapterCode(), adapter -> adapter.persistenceIntervalMillis(channel));
}
@Override
public TestPlan testPlan(ChannelIdentity channel)
{
return registry.executeTestData(channel.adapterCode(), adapter -> adapter.testPlan(channel));
}
@Override
public SampleWatermark currentWatermark(ChannelIdentity channel)
{
return registry.executeTestData(channel.adapterCode(), adapter -> adapter.currentWatermark(channel));
}
@Override
public List samplesSince(ChannelIdentity channel, SampleWatermark watermark)
{
return registry.executeTestData(channel.adapterCode(), adapter -> adapter.samplesSince(channel, watermark));
}
}