yeg
4 天以前 99fd4ccdf5d410e78a3785375036c34a2132ee04
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
package com.battery.device.bts;
 
import java.nio.file.Path;
import java.time.Duration;
import java.time.ZoneId;
import java.util.Map;
import com.battery.device.api.DeviceAdapter;
import com.battery.device.api.DeviceAdapterException;
import com.battery.device.api.credentials.LocalCredentials;
import com.battery.device.api.registry.AdapterInstanceConfig;
import com.battery.device.api.registry.DeviceAdapterFactory;
 
/**
 * 按存储形态 {@code NEWARE_BTS} 构造**直连新威对外接口**的只读适配器实例(ADR-0068)。
 *
 * <p>与 {@code NEWARE_MYSQL}(直连厂商库)并列:这台机器能不能远程取数,取决于它的上位机形态,
 * 而不是厂商。8.0 形态的库内没有逐点数据,所以它的逐点只能从接口的 {@code download} 取。
 *
 * <p><b>为什么口令不进数据库</b>:这里要的是那台机器的**本地管理员口令**——它和厂商库口令一样是来源凭据,
 * 因此共用同一套取值顺序(本地凭据文件 → 同名环境变量 → 同名 JVM 启动参数,见
 * {@link LocalCredentials}),{@code source_config} 里只放变量名。三者都没有时装配失败,
 * 错误信息同时点名文件路径与变量名,使"忘了放口令"是可见的失败而不是沉默的缺失。
 *
 * <p>本类不缓存实例:实例由 {@code DeviceAdapterRegistry} 持有并按实例串行执行。
 */
public final class NewareBtsAdapterFactory implements DeviceAdapterFactory
{
    /** 实例配置里承载"本机管理员账号变量名"的键。 */
    public static final String USER_ENV_OPTION = "userEnv";
    /** 实例配置里承载"本机管理员口令变量名"的键。 */
    public static final String PASSWORD_ENV_OPTION = "passwordEnv";
    public static final String DEFAULT_USER_ENV = "NEWARE_WIN_USER";
    /** 建 SMB 会话是本地进程操作,超时给短一些:卡住也没有数据可取。 */
    private static final Duration SESSION_TIMEOUT = Duration.ofSeconds(10);
    /** 读应答超时;{@code download} 一页上千行在 SMB 上会慢一些,但远不到这个量级。 */
    private static final Duration RESPONSE_TIMEOUT = Duration.ofSeconds(60);
    /** 凭据文件相对进程工作目录定位,使开发(仓库根)与交付(应用目录)用同一个位置。 */
    static final Path CREDENTIALS_FILE = LocalCredentials.DEFAULT_FILE;
 
    /** 返回本形态的适配器类型标识 {@code NEWARE_BTS}。 */
    @Override
    public String adapterType()
    {
        return NewareBtsAdapter.ADAPTER_TYPE;
    }
 
    /** 从实例配置取账号与口令来源,装配远程命名管道传输与报文编解码器。 */
    @Override
    public DeviceAdapter create(AdapterInstanceConfig config)
    {
        Map<String, String> sourceConfig = config.sourceConfig();
        String user = LocalCredentials.resolve(option(sourceConfig, USER_ENV_OPTION, DEFAULT_USER_ENV),
                CREDENTIALS_FILE.toAbsolutePath(), System.getenv(), System::getProperty);
        String password = LocalCredentials.resolve(required(sourceConfig, PASSWORD_ENV_OPTION),
                CREDENTIALS_FILE.toAbsolutePath(), System.getenv(), System::getProperty);
        NewareBtsPipeTransport transport = new NewareBtsPipeTransport(config.host(), user, password,
                SESSION_TIMEOUT, RESPONSE_TIMEOUT);
        return new NewareBtsAdapter(config.adapterCode(), transport,
                new BtsXmlCodec(config.adapterCode(), ZoneId.of(config.timezoneId())), config.capabilities());
    }
 
    private static String option(Map<String, String> sourceConfig, String key, String fallback)
    {
        String value = sourceConfig.get(key);
        return value == null || value.isBlank() ? fallback : value.trim();
    }
 
    /** 口令变量名没有缺省值:五台机器的口令实测有两种,猜一个就会连错机器。 */
    private static String required(Map<String, String> sourceConfig, String key)
    {
        String value = option(sourceConfig, key, null);
        if (value == null) throw new DeviceAdapterException("新威 BTS 实例缺少配置项 " + key
                + "(本机管理员口令的变量名):口令有两种取值,不能有缺省");
        return value;
    }
}