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();
|
}
|
}
|