Delete URL Filter related codes committed previously

This commit is contained in:
DigitalSonic
2018-05-05 23:25:49 +08:00
parent ed3861395c
commit 2b3c50c8b3
9 changed files with 0 additions and 633 deletions
@@ -1,70 +0,0 @@
package com.alibaba.druid.filter.url;
import com.alibaba.druid.filter.FilterChain;
import com.alibaba.druid.filter.FilterChainImpl;
import com.alibaba.druid.proxy.jdbc.ConnectionProxy;
import com.alibaba.druid.proxy.jdbc.ConnectionProxyImpl;
import com.alibaba.druid.proxy.jdbc.DataSourceProxy;
import com.alibaba.druid.support.logging.Log;
import com.alibaba.druid.support.logging.LogFactory;
import java.sql.Connection;
import java.sql.Driver;
import java.sql.SQLException;
import java.util.Properties;
/**
* FilterChain to create new connection with placeholder in URL
*
* @author DigitalSonic
*/
public class ConnectionConnectFilterChainImpl extends FilterChainImpl {
private final static Log LOG = LogFactory.getLog(ConnectionConnectFilterChainImpl.class);
public ConnectionConnectFilterChainImpl(FilterChain filterChain) {
this(filterChain.getDataSource(), filterChain.getPos());
}
public ConnectionConnectFilterChainImpl(DataSourceProxy dataSource, int pos) {
super(dataSource, pos);
}
@Override
public ConnectionProxy connection_connect(Properties info) throws SQLException {
if (this.pos < getFilterSize()) {
return getFilters().get(pos++).connection_connect(this, info);
}
DataSourceProxy dataSource = getDataSource();
Driver driver = dataSource.getRawDriver();
String url = dataSource.getRawJdbcUrl();
url = processUrl(url);
Connection nativeConnection = driver.connect(url, info);
if (nativeConnection == null) {
return null;
}
return new ConnectionProxyImpl(dataSource, nativeConnection, info, dataSource.createConnectionId());
}
protected String processUrl(String url) {
if (url == null || (url != null &&
(url.indexOf("${") == -1 || url.indexOf("}") == -1))) {
return url;
}
String processedUrl = url;
String placeHolder = url.substring(url.indexOf("${") + 2, url.indexOf("}"));
String value = HostAndPortHolder.getInstance().get(placeHolder);
if (value != null) {
LOG.info("PlaceHolder ${" + placeHolder + "} is found in url, it will be replace by " + value);
processedUrl = url.replace("${" + placeHolder + "}", value);
} else {
LOG.info("PlaceHolder ${" + placeHolder + "} is found in url, but no value is bind.");
}
return processedUrl;
}
}
@@ -1,150 +0,0 @@
package com.alibaba.druid.filter.url;
import com.alibaba.druid.support.logging.Log;
import com.alibaba.druid.support.logging.LogFactory;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Random;
/**
* A singleton object to hold Host & Port information.
*
* @author DigitalSonic
*/
public class HostAndPortHolder {
private static final Log LOG = LogFactory.getLog(ConnectionConnectFilterChainImpl.class);
public static final String UNAVAILABLE = "UNAVAILABLE_HOST";
private static HostAndPortHolder instance = new HostAndPortHolder();
private Map<String, List<String>> holder = new HashMap<String, List<String>>();
private List<String> blacklist = new ArrayList<String>();
private Random random = new Random();
public static HostAndPortHolder getInstance() {
return instance;
}
public static void loadProperties(String file) {
Properties properties = new Properties();
if (file == null) {
return;
}
InputStream is = null;
try {
LOG.debug("Trying to load " + file + " from FileSystem.");
is = new FileInputStream(file);
} catch(FileNotFoundException e) {
LOG.debug("Trying to load " + file + " from Classpath.");
try {
is = HostAndPortHolder.class.getResourceAsStream(file);
} catch (Exception ex) {
LOG.warn("Can not load resource " + file, ex);
}
}
if (is != null) {
try {
properties.load(is);
} catch(Exception e) {
LOG.error("Exception occurred while loading " + file, e);
} finally {
if (is != null) {
try {
is.close();
} catch (Exception e) {
// ignore
}
}
}
} else {
LOG.warn("File " + file + " can't be loaded!");
}
for (Object k : properties.keySet()) {
String v = properties.getProperty((String) k);
if (v != null && v.trim().length() > 0) {
LOG.info("Loading placeholder " + k + " = [" + v + "]");
List<String> values = Arrays.asList(v.split(";"));
getInstance().putHostAndPorts((String) k, values);
}
}
}
private HostAndPortHolder() {
}
public void putHostAndPorts(String key, List<String> values) {
if (key == null || values == null || values.isEmpty()) {
return;
}
holder.put(key, values);
}
public Map<String, List<String>> getHolder() {
return holder;
}
public void clearBlacklist() {
blacklist.clear();
}
public void addBlacklist(String hostAndPort) {
blacklist.add(hostAndPort);
}
public void removeBlacklist(String hostAndPort) {
if (hostAndPort == null) {
return;
}
blacklist.remove(hostAndPort);
}
public int getBlacklistSize() {
return blacklist.size();
}
public String get(String name) {
if (name == null || !holder.containsKey(name)) {
LOG.warn("Can not find placeholder " + name + ".");
return UNAVAILABLE;
}
List<String> hostAndPorts = holder.get(name);
int idx = random.nextInt(hostAndPorts.size());
String returnValue = hostAndPorts.get(idx);
String hostAndPort = returnValue;
for (int i = 0; i < hostAndPorts.size(); i++) {
if (isAvailable(hostAndPort)) {
returnValue = hostAndPort;
break;
}
if (++idx >= hostAndPorts.size()) {
idx = 0;
}
hostAndPort = hostAndPorts.get(idx);
}
return returnValue;
}
public List<String> getAll(String name) {
if (name == null || !holder.containsKey(name)) {
return new ArrayList<String>();
}
return holder.get(name);
}
private boolean isAvailable(String hostAndPort) {
return !blacklist.contains(hostAndPort);
}
}
@@ -1,118 +0,0 @@
package com.alibaba.druid.filter.url;
import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.druid.support.logging.Log;
import com.alibaba.druid.support.logging.LogFactory;
import java.sql.Connection;
import java.sql.Driver;
import java.sql.SQLException;
import java.util.List;
import java.util.Properties;
/**
* A thread to run the validation on each host:port.
* If some host:port is failed in the validation, we can set test flags in DruidDataSource.
*
* @author DigitalSonic
*/
public class HostAndPortValidatorThread implements Runnable {
private final static Log LOG = LogFactory.getLog(HostAndPortValidatorThread.class);
private DruidDataSource dataSource;
private int sleepSeconds = 30;
private boolean modifyTestFlags = false;
private boolean oldTestOnBorrow = false;
private boolean oldTestOnReturn = false;
@Override
public void run() {
oldTestOnBorrow = dataSource.isTestOnBorrow();
oldTestOnReturn = dataSource.isTestOnReturn();
while (true) {
try {
check();
} catch(Exception e) {
LOG.error("Validation Failed!", e);
} finally {
try {
Thread.sleep(sleepSeconds * 1000);
} catch (InterruptedException e) {
// ignore
}
}
}
}
protected void check() {
String url = dataSource.getRawJdbcUrl();
if (url == null || (url != null &&
(url.indexOf("${") == -1 || url.indexOf("}") == -1))) {
return;
}
String placeHolder = url.substring(url.indexOf("${") + 2, url.indexOf("}"));
List<String> values = HostAndPortHolder.getInstance().getAll(placeHolder);
for (String v : values) {
validateConnection(dataSource, placeHolder, v);
}
if (HostAndPortHolder.getInstance().getBlacklistSize() == 0) {
resetFlagsIfNeeded();
}
}
private void validateConnection(DruidDataSource dataSource, String placeHolder, String target) {
Driver driver = dataSource.getRawDriver();
Properties info = dataSource.getConnectProperties();
String url = dataSource.getRawJdbcUrl();
Connection conn = null;
try {
LOG.debug("Validating " + target + " every " + sleepSeconds + " seconds.");
String realUrl = url.replace("${" + placeHolder + "}", target);
conn = driver.connect(realUrl, info);
dataSource.validateConnection(conn);
HostAndPortHolder.getInstance().removeBlacklist(target);
} catch (SQLException e) {
LOG.warn("Validation FAILED for " + target, e);
HostAndPortHolder.getInstance().addBlacklist(target);
modifyFlagsIfNeeded();
} finally {
if (conn != null) {
try {
conn.close();
} catch (SQLException e) {
LOG.error("Can not close connection for HostAndPort Validation.", e);
}
}
}
}
private void resetFlagsIfNeeded() {
if (modifyTestFlags) {
dataSource.setTestOnBorrow(oldTestOnBorrow);
dataSource.setTestOnReturn(oldTestOnReturn);
}
}
private void modifyFlagsIfNeeded() {
if (!modifyTestFlags) {
return;
}
if (!oldTestOnReturn || !oldTestOnBorrow) {
dataSource.setTestOnBorrow(true);
dataSource.setTestOnReturn(true);
}
}
public void setDataSource(DruidDataSource dataSource) {
this.dataSource = dataSource;
}
public void setSleepSeconds(int sleepSeconds) {
this.sleepSeconds = sleepSeconds;
}
public void setModifyTestFlags(boolean modifyTestFlags) {
this.modifyTestFlags = modifyTestFlags;
}
}
@@ -1,86 +0,0 @@
package com.alibaba.druid.filter.url;
import com.alibaba.druid.filter.FilterAdapter;
import com.alibaba.druid.filter.FilterChain;
import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.druid.proxy.jdbc.ConnectionProxy;
import com.alibaba.druid.proxy.jdbc.DataSourceProxy;
import com.alibaba.druid.support.logging.Log;
import com.alibaba.druid.support.logging.LogFactory;
import java.sql.SQLException;
import java.util.Properties;
/**
* The filter to replace the placeholder in JDBC URL.
*
* @author DigitalSonic
*/
public class JdbcUrlHostAndPortReplaceFilter extends FilterAdapter {
private final static Log LOG = LogFactory.getLog(HostAndPortValidatorThread.class);
public static final String DEFAULT_FILE = "datasource.properties";
private String file = DEFAULT_FILE;
private int healthCheckIntervalSeconds = 0;
private HostAndPortValidatorThread validatorThread;
private Thread runningValidatorThread;
private boolean isValidatorThreadStarted = false;
private boolean modifyTestFlags = false;
public void init() {
if (file == null || file.trim().length() == 0) {
file = DEFAULT_FILE;
}
HostAndPortHolder.loadProperties(file);
}
public void close() {
if (runningValidatorThread != null) {
runningValidatorThread.interrupt();
}
}
@Override
public ConnectionProxy connection_connect(FilterChain chain, Properties info) throws SQLException {
startValidationThreadIfNeeded(chain);
return super.connection_connect(new ConnectionConnectFilterChainImpl(chain), info);
}
private void startValidationThreadIfNeeded(FilterChain chain) {
if (isValidatorThreadStarted || healthCheckIntervalSeconds <= 0) {
return;
}
DataSourceProxy dataSource = chain.getDataSource();
if (dataSource instanceof DruidDataSource) {
if (validatorThread == null) {
validatorThread = new HostAndPortValidatorThread();
validatorThread.setSleepSeconds(healthCheckIntervalSeconds);
validatorThread.setModifyTestFlags(modifyTestFlags);
}
validatorThread.setDataSource((DruidDataSource) dataSource);
runningValidatorThread = new Thread(validatorThread);
runningValidatorThread.start();
isValidatorThreadStarted = true;
} else {
LOG.warn("The DataSource is not a DruidDataSource, ignore HostAndPortValidator.");
}
}
public void setFile(String file) {
this.file = file;
}
public void setHealthCheckIntervalSeconds(int healthCheckIntervalSeconds) {
this.healthCheckIntervalSeconds = healthCheckIntervalSeconds;
}
public void setValidatorThread(HostAndPortValidatorThread validatorThread) {
this.validatorThread = validatorThread;
}
public void setModifyTestFlags(boolean modifyTestFlags) {
this.modifyTestFlags = modifyTestFlags;
}
}
@@ -1,78 +0,0 @@
package com.alibaba.druid.filter.url;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import java.util.List;
import java.util.Map;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertTrue;
/**
* Test class for HostAndPortHolder
*
* @author DigitalSonic
*/
public class HostAndPortHolderTest {
@Before
public void setUp() {
HostAndPortHolder.loadProperties("/com/alibaba/druid/filter/url/datasource.properties");
}
@After
public void tearDown() {
HostAndPortHolder.getInstance().clearBlacklist();
}
@Test
public void testLoadFromFileNotExisted() {
int size = HostAndPortHolder.getInstance().getHolder().size();
HostAndPortHolder.loadProperties("FILE_NOT_FOUND");
assertEquals(size, HostAndPortHolder.getInstance().getHolder().size());
}
@Test
public void testLoadFromProperties() {
Map<String, List<String>> holder = HostAndPortHolder.getInstance().getHolder();
assertEquals(3, holder.size());
assertEquals("127.0.0.1:3066", holder.get("datasource.foo").get(0));
assertEquals("192.168.0.1:3066", holder.get("datasource.foo").get(1));
assertFalse(holder.containsKey("datasource.empty"));
}
@Test
public void testRandomGet() {
boolean[] flags = new boolean[] { false, false };
HostAndPortHolder holder = HostAndPortHolder.getInstance();
for (int i = 0; i < 10; i++) {
String v = holder.get("datasource.foo");
if (v.equals("127.0.0.1:3066")) {
flags[0] = true;
} else if (v.equals("192.168.0.1:3066")) {
flags[1] = true;
}
}
assertTrue(flags[0] && flags[1]);
}
@Test
public void testGetOne() {
HostAndPortHolder holder = HostAndPortHolder.getInstance();
String value = holder.get("datasource.foo");
assertTrue(value.equals("127.0.0.1:3066") || value.equals("192.168.0.1:3066"));
assertEquals(HostAndPortHolder.UNAVAILABLE, holder.get("UNAVAILABLE"));
}
@Test
public void testBlackList() {
HostAndPortHolder holder = HostAndPortHolder.getInstance();
holder.addBlacklist("192.168.0.1:3066");
for (int i = 0; i < 100; i++) {
assertNotEquals("192.168.0.1:3066", holder.get("datasource.foo"));
}
}
}
@@ -1,40 +0,0 @@
package com.alibaba.druid.filter.url;
import com.alibaba.druid.pool.DruidDataSource;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
/**
* Test class for HostAndPortValidatorThread
*
* @author DigitalSonic
*/
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:com/alibaba/druid/filter/url/dataSource.xml")
public class HostAndPortValidatorThreadTest {
@Autowired
private DruidDataSource dataSource;
@Test
public void testValidateFail() throws Exception {
assertEquals(0, HostAndPortHolder.getInstance().getBlacklistSize());
dataSource.setValidationQuery("select xxx from foo");
Thread.sleep(20 * 1000);
assertTrue(HostAndPortHolder.getInstance().getBlacklistSize() > 0);
assertTrue(dataSource.isTestOnBorrow());
assertTrue(dataSource.isTestOnReturn());
dataSource.setValidationQuery(null);
Thread.sleep(20 * 1000);
assertEquals(0, HostAndPortHolder.getInstance().getBlacklistSize());
assertFalse(dataSource.isTestOnBorrow());
assertFalse(dataSource.isTestOnReturn());
}
}
@@ -1,55 +0,0 @@
package com.alibaba.druid.filter.url;
import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.druid.pool.DruidPooledConnection;
import com.alibaba.druid.proxy.jdbc.ConnectionProxyImpl;
import org.apache.derby.impl.jdbc.EmbedConnection;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import java.sql.Connection;
import java.util.ArrayList;
import java.util.List;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
/**
* Test class for JdbcUrlHostAndPortReplaceFilter
*
* @author DigitalSonic
*/
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:com/alibaba/druid/filter/url/dataSource.xml")
public class JdbcUrlHostAndPortReplaceFilterTest {
@Autowired
private DruidDataSource dataSource;
@Test
public void testConnectWithDifferentPlaceholderValue() throws Exception {
int[] count = new int[] { 0,0 };
List<Connection> connectionList = new ArrayList<Connection>();
for (int i = 0; i < 10; i++) {
DruidPooledConnection conn = dataSource.getConnection();
EmbedConnection embed = ((EmbedConnection)((ConnectionProxyImpl)conn.getConnection()).getRawObject());
String connName = embed.toString();
if (connName.contains("foo")) {
count[0]++;
} else if (connName.contains("bar")) {
count[1]++;
} else {
fail("NOT foo or bar");
}
connectionList.add(conn);
}
assertTrue(count[0] > 0 && count[1] >0);
for (Connection c : connectionList) {
c.close();
}
}
}
@@ -1,32 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-2.0.xsd
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.0.xsd"
default-lazy-init="false">
<tx:annotation-driven />
<bean id="url-filter" class="com.alibaba.druid.filter.url.JdbcUrlHostAndPortReplaceFilter"
init-method="init" destroy-method="close">
<property name="file" value="/com/alibaba/druid/filter/url/datasource.properties" />
<property name="healthCheckIntervalSeconds" value="10" />
<property name="modifyTestFlags" value="true" />
</bean>
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"
init-method="init" destroy-method="close">
<property name="url" value="jdbc:derby:memory:${datasource.test};create=true" />
<property name="initialSize" value="1" />
<property name="maxActive" value="10" />
<property name="proxyFilters">
<list>
<ref bean="url-filter" />
</list>
</property>
<property name="filters" value="slf4j" />
</bean>
</beans>
@@ -1,4 +0,0 @@
datasource.foo=127.0.0.1:3066;192.168.0.1:3066
datasource.bar=198.168.1.1:3166;192.168.1.2:3166
datasource.empty
datasource.test=foo;bar