yeg
2026-09-05 bd50f1b756c1da2dbf92f6541407ad40f455e24a
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
package com.battery.device.api;
 
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.model.DeviceObservation;
import com.battery.device.model.ObservationFailureReason;
 
public interface DeviceAdapter extends DeviceObservationAdapter
{
    /** 返回适配器实例的稳定代码。 */
    String adapterCode();
 
    /** 返回运行时已启用的设备能力。 */
    AdapterCapabilities capabilities();
 
    /** 发现当前端点可见的检测柜通道。 */
    List<DetectedChannel> discoverChannels();
 
    /** 批量查询通道实时快照,不形成最终原始采集数据。 */
    Map<ChannelIdentity, RealtimeSnapshot> inquire(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);
        }
    }
 
    /** 将适配器实现细节收敛为业务可识别的失败分类。 */
    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;
        };
    }
 
    /** 查询通道当前 BTS 测试的历史数据上传进度。 */
    List<HistoryAvailability> inquireHistory(Set<ChannelIdentity> channels);
 
    /** 分页下载单个通道的最终原始历史数据,每页最多 1000 条。 */
    HistoryPage downloadHistory(ChannelIdentity channel, String btsTestId, long startPosition, int limit);
 
    /** 执行设备控制;只读适配器始终拒绝该调用。 */
    default void control(ChannelIdentity channel, DeviceControlCommand command)
    {
        throw new UnsupportedOperationException("Device control is not enabled for this adapter");
    }
 
    @Override
    default void close()
    {
    }
}