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.AdapterRegistryException; 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 必须在这里转交:不转交就会落到本类的默认实现,从而拿实时持久化间隔去重算汇总,
* 来源自己声明的汇总节奏就被忽略了。
*
* @param channel 检测柜通道身份
* @return 汇总记录的读取间隔,单位毫秒
* @throws AdapterRegistryException 该通道所属的实例未启用,或实例未提供测试数据观测契约
*/
@Override
public long aggregateIntervalMillis(ChannelIdentity channel)
{
return registry.executeTestData(channel.adapterCode(), adapter -> adapter.aggregateIntervalMillis(channel));
}
/**
* 按通道所属来源实例取设备计划方案,只用于实时展示。
*
* @param channel 检测柜通道身份
* @return 设备计划方案;设备未提供时为空
* @throws AdapterRegistryException 该通道所属的实例未启用,或实例未提供测试数据观测契约
*/
@Override
public TestPlan testPlan(ChannelIdentity channel)
{
return registry.executeTestData(channel.adapterCode(), adapter -> adapter.testPlan(channel));
}
/**
* 按通道所属来源实例读取接收水位,用于把开始接收与继续接收切在这一时刻之后。
*
* @param channel 检测柜通道身份
* @return 通道当前接收水位;来源不按设备数据行接收时为空
* @throws AdapterRegistryException 该通道所属的实例未启用,或实例未提供测试数据观测契约
*/
@Override
public SampleWatermark currentWatermark(ChannelIdentity channel)
{
return registry.executeTestData(channel.adapterCode(), adapter -> adapter.currentWatermark(channel));
}
/**
* 按通道所属来源实例读取严格晚于水位的数据行,同秒多行各自成立、不按秒合并。
*
* @param channel 检测柜通道身份
* @param watermark 上次取得的水位;为空表示尚未取水位,此时返回空列表而不并入设备历史
* @return 水位之后的设备数据行,按设备时间与协议序号升序
* @throws AdapterRegistryException 该通道所属的实例未启用,或实例未提供测试数据观测契约
*/
@Override
public List