| | |
| | | import java.util.List; |
| | | import java.util.Map; |
| | | import java.util.Set; |
| | | import com.battery.device.model.AdapterCapabilities; |
| | | import com.battery.device.model.ChannelIdentity; |
| | | import com.battery.device.model.DetectedChannel; |
| | | import com.battery.device.model.DeviceControlCommand; |
| | | import com.battery.device.model.HistoryAvailability; |
| | | import com.battery.device.model.HistoryPage; |
| | | import com.battery.device.model.RealtimeSnapshot; |
| | | 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.DeviceControlCommand; |
| | | import com.battery.device.api.model.RealtimeSnapshot; |
| | | import com.battery.device.api.model.DeviceObservation; |
| | | import com.battery.device.api.model.ObservationFailureReason; |
| | | |
| | | public interface DeviceAdapter extends AutoCloseable |
| | | public interface DeviceAdapter extends DeviceObservationAdapter |
| | | { |
| | | /** 返回适配器实例的稳定代码。 */ |
| | | String adapterCode(); |
| | |
| | | /** 批量查询通道实时快照,不形成最终原始采集数据。 */ |
| | | Map<ChannelIdentity, RealtimeSnapshot> inquire(Set<ChannelIdentity> channels); |
| | | |
| | | /** 查询通道当前 BTS 测试的历史数据上传进度。 */ |
| | | List<HistoryAvailability> inquireHistory(Set<ChannelIdentity> channels); |
| | | /** 返回厂商无关的观测结果;失败也以离线事实返回,不把协议异常泄漏给业务。 */ |
| | | default Map<ChannelIdentity, DeviceObservation> observe(Set<ChannelIdentity> channels) |
| | | { |
| | | if (channels == null || channels.isEmpty()) return Map.of(); |
| | | try |
| | | { |
| | | Map<ChannelIdentity, RealtimeSnapshot> snapshots = inquire(channels); |
| | | Map<ChannelIdentity, DeviceObservation> observations = new java.util.LinkedHashMap<>(); |
| | | channels.forEach(channel -> { |
| | | RealtimeSnapshot snapshot = snapshots.get(channel); |
| | | observations.put(channel, snapshot == null |
| | | ? DeviceObservation.offline(channel, "OFFLINE") : DeviceObservation.from(snapshot)); |
| | | }); |
| | | return Map.copyOf(observations); |
| | | } |
| | | catch (DeviceAdapterException exception) |
| | | { |
| | | ObservationFailureReason reason = normalizeFailureReason(exception.failureCode()); |
| | | Map<ChannelIdentity, DeviceObservation> offline = new java.util.LinkedHashMap<>(); |
| | | channels.forEach(channel -> offline.put(channel, DeviceObservation.offline(channel, reason))); |
| | | return Map.copyOf(offline); |
| | | } |
| | | } |
| | | |
| | | /** 分页下载单个通道的最终原始历史数据,每页最多 1000 条。 */ |
| | | HistoryPage downloadHistory(ChannelIdentity channel, String btsTestId, long startPosition, int limit); |
| | | /** 将适配器实现细节收敛为业务可识别的失败分类。 */ |
| | | private static ObservationFailureReason normalizeFailureReason(String failureCode) |
| | | { |
| | | if (failureCode == null || failureCode.isBlank()) return ObservationFailureReason.INVALID_RESPONSE; |
| | | return switch (failureCode.trim().toUpperCase(java.util.Locale.ROOT)) |
| | | { |
| | | case "CONNECTION_FAILED" -> ObservationFailureReason.CONNECTION_FAILED; |
| | | case "TIMEOUT" -> ObservationFailureReason.TIMEOUT; |
| | | case "DISCONNECTED" -> ObservationFailureReason.DISCONNECTED; |
| | | case "UNSUPPORTED" -> ObservationFailureReason.UNSUPPORTED; |
| | | case "MALFORMED_XML", "MISSING_FIELD", "INVALID_VALUE", "IDENTITY_MISMATCH", |
| | | "UNEXPECTED_COMMAND" -> ObservationFailureReason.PARSE_FAILED; |
| | | default -> ObservationFailureReason.TRANSPORT_FAILED; |
| | | }; |
| | | } |
| | | |
| | | |
| | | |
| | | /** 执行设备控制;只读适配器始终拒绝该调用。 */ |
| | | default void control(ChannelIdentity channel, DeviceControlCommand command) |