刘光辉
119 分钟以前 06f314545ac3514d7ce28939920866ae8188d31c
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
87
88
89
90
91
92
93
94
95
package jnpf.limsService.provider;
 
import com.alibaba.druid.pool.DruidDataSource;
import com.baomidou.dynamic.datasource.DynamicRoutingDataSource;
import org.springframework.core.env.Environment;
import org.springframework.jdbc.datasource.AbstractDataSource;
 
import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.SQLException;
 
/** Holds a lazy, bounded pool without becoming a candidate for business DataSource injection. */
public class LimsElnReadonlyPool implements AutoCloseable {
    private final Environment environment;
    private final DataSource businessDataSource;
    private DruidDataSource pool;
    private boolean closed;
    private final DataSource source = new AbstractDataSource() {
        @Override
        public Connection getConnection() throws SQLException {
            return pool().getConnection();
        }
 
        @Override
        public Connection getConnection(String username, String password) throws SQLException {
            throw new SQLException("Source credentials cannot be overridden", "08001");
        }
    };
 
    public LimsElnReadonlyPool(Environment environment, DataSource businessDataSource) {
        this.environment = environment;
        this.businessDataSource = businessDataSource;
    }
 
    public DataSource dataSource() {
        return source;
    }
 
    private synchronized DruidDataSource pool() throws SQLException {
        if (closed) throw new SQLException("Source pool is closed", "08001");
        if (pool != null) return pool;
        String url = setting("url");
        String username = setting("username");
        String password = setting("password");
        java.util.Properties connectionProperties = new java.util.Properties();
        if (url == null && username == null && password == null) {
            // Always use the configured primary, never a request-scoped dynamic datasource selection.
            DataSource primary = businessDataSource instanceof DynamicRoutingDataSource
                    ? ((DynamicRoutingDataSource) businessDataSource).getDataSource(null) : businessDataSource;
            DruidDataSource business;
            try { business = primary.unwrap(DruidDataSource.class); }
            catch (SQLException e) { throw new SQLException("Primary source connection settings are unavailable", "08001"); }
            if (business == null) throw new SQLException("Primary source connection settings are unavailable", "08001");
            url = business.getUrl();
            username = business.getUsername();
            password = business.getPassword();
            connectionProperties.putAll(business.getConnectProperties());
        }
        if (url == null || !url.startsWith("jdbc:postgresql://") || username == null || password == null) {
            throw new SQLException("ELN source read-only connection is not configured", "08001");
        }
        DruidDataSource candidate = new DruidDataSource();
        candidate.setName("eln-source-readonly");
        candidate.setUrl(url);
        candidate.setUsername(username);
        candidate.setPassword(password);
        candidate.setConnectProperties(connectionProperties);
        candidate.setDriverClassName("org.postgresql.Driver");
        candidate.setInitialSize(0);
        candidate.setMinIdle(0);
        candidate.setMaxActive(3);
        candidate.setMaxWait(2000);
        candidate.setConnectionErrorRetryAttempts(0);
        candidate.setBreakAfterAcquireFailure(true);
        candidate.setConnectTimeout(2000);
        candidate.setSocketTimeout(7000);
        candidate.setDefaultReadOnly(true);
        candidate.setTestOnBorrow(true);
        candidate.setValidationQuery("SELECT 1");
        candidate.setValidationQueryTimeout(2);
        pool = candidate;
        return pool;
    }
 
    private String setting(String name) {
        String value = environment.getProperty("lims.eln-source.readonly." + name);
        return value == null || value.trim().isEmpty() || value.contains("${") ? null : value;
    }
 
    @Override
    public synchronized void close() {
        closed = true;
        if (pool != null) pool.close();
    }
}