This is an automated email from the ASF dual-hosted git repository. jchen21 pushed a commit to branch feature/GEODE-5861 in repository https://gitbox.apache.org/repos/asf/geode.git
commit 8811734a852d0a77e47421060b4cdfb1dface8a5 Author: Darrel Schneider <dschnei...@pivotal.io> AuthorDate: Fri Oct 12 16:50:42 2018 -0700 WIP: Adding support for creating Hikari data source Co-authored-by: Darrel Schneider <dschnei...@pivotal.io> Co-authored-by: Jianxia Chen <jc...@pivotal.io> --- .../jdbc/internal/HikariJdbcDataSource.java | 57 +++++++++++++- geode-core/build.gradle | 1 + .../internal/datasource/DataSourceFactory.java | 22 ++++++ .../internal/datasource/HikariJdbcDataSource.java | 90 ++++++++++++++++++++++ .../apache/geode/internal/jndi/JNDIInvoker.java | 68 ++++++++++------ .../cli/commands/CreateJndiBindingCommand.java | 3 +- geode-core/src/test/resources/expected-pom.xml | 6 ++ 7 files changed, 221 insertions(+), 26 deletions(-) diff --git a/geode-connectors/src/main/java/org/apache/geode/connectors/jdbc/internal/HikariJdbcDataSource.java b/geode-connectors/src/main/java/org/apache/geode/connectors/jdbc/internal/HikariJdbcDataSource.java index 2aa3555..8e70e9c 100644 --- a/geode-connectors/src/main/java/org/apache/geode/connectors/jdbc/internal/HikariJdbcDataSource.java +++ b/geode-connectors/src/main/java/org/apache/geode/connectors/jdbc/internal/HikariJdbcDataSource.java @@ -14,14 +14,20 @@ */ package org.apache.geode.connectors.jdbc.internal; +import java.io.PrintWriter; import java.sql.Connection; import java.sql.SQLException; +import java.sql.SQLFeatureNotSupportedException; +import java.util.logging.Logger; + +import javax.sql.DataSource; import com.zaxxer.hikari.HikariDataSource; import org.apache.geode.connectors.jdbc.internal.configuration.ConnectorService; +import org.apache.geode.internal.datasource.ConfiguredDataSourceProperties; -class HikariJdbcDataSource implements JdbcDataSource { +public class HikariJdbcDataSource implements DataSource, JdbcDataSource { private final HikariDataSource delegate; @@ -34,14 +40,63 @@ class HikariJdbcDataSource implements JdbcDataSource { this.delegate = ds; } + // TODO: set more config properties + public HikariJdbcDataSource(ConfiguredDataSourceProperties config) { + HikariDataSource ds = new HikariDataSource(); + ds.setJdbcUrl(config.getURL()); + ds.setUsername(config.getUser()); + ds.setPassword(config.getPassword()); +// ds.setDataSourceProperties(config.getConnectionProperties()); + this.delegate = ds; + } + @Override public Connection getConnection() throws SQLException { return this.delegate.getConnection(); } @Override + public Connection getConnection(String username, String password) throws SQLException { + return this.delegate.getConnection(username, password); + } + + @Override public void close() { this.delegate.close(); } + @Override + public <T> T unwrap(Class<T> iface) throws SQLException { + return this.delegate.unwrap(iface); + } + + @Override + public boolean isWrapperFor(Class<?> iface) throws SQLException { + return this.delegate.isWrapperFor(iface); + } + + @Override + public PrintWriter getLogWriter() throws SQLException { + return this.delegate.getLogWriter(); + } + + @Override + public void setLogWriter(PrintWriter out) throws SQLException { + this.delegate.setLogWriter(out); + } + + @Override + public void setLoginTimeout(int seconds) throws SQLException { + this.delegate.setLoginTimeout(seconds); + } + + @Override + public int getLoginTimeout() throws SQLException { + return this.delegate.getLoginTimeout(); + } + + @Override + public Logger getParentLogger() throws SQLFeatureNotSupportedException { + return this.delegate.getParentLogger(); + } } diff --git a/geode-core/build.gradle b/geode-core/build.gradle index 3975797..ac3d9c2 100755 --- a/geode-core/build.gradle +++ b/geode-core/build.gradle @@ -45,6 +45,7 @@ dependencies { antlr 'antlr:antlr:' + project.'antlr.version' // External + compile group: 'com.zaxxer', name: 'HikariCP', version: project.'HikariCP.version' compileOnly files("${System.getProperty('java.home')}/../lib/tools.jar") compile 'com.github.stephenc.findbugs:findbugs-annotations:' + project.'stephenc-findbugs.version' compile 'org.jgroups:jgroups:' + project.'jgroups.version' diff --git a/geode-core/src/main/java/org/apache/geode/internal/datasource/DataSourceFactory.java b/geode-core/src/main/java/org/apache/geode/internal/datasource/DataSourceFactory.java index 2143be5..e120cd5 100644 --- a/geode-core/src/main/java/org/apache/geode/internal/datasource/DataSourceFactory.java +++ b/geode-core/src/main/java/org/apache/geode/internal/datasource/DataSourceFactory.java @@ -53,6 +53,28 @@ public class DataSourceFactory { /** Creates a new instance of DataSourceFactory */ public DataSourceFactory() {} + public static DataSource getHikariDataSource(Map configMap) throws DataSourceCreateException { + ConfiguredDataSourceProperties configs = createDataSourceProperties(configMap); + if (configs.getURL() == null) { + logger.error("DataSourceFactory::getHikariDataSource:URL String to Database is null"); + throw new DataSourceCreateException( + "DataSourceFactory::getHikariDataSource:URL String to Database is null"); + } + try { + return new HikariJdbcDataSource(configs); + } catch (Exception ex) { + logger.error(String.format( + "DataSourceFactory::getHikariDataSource:Exception while creating GemfireBasicDataSource.Exception String=%s", + ex.getLocalizedMessage()), + ex); + throw new DataSourceCreateException( + String.format( + "DataSourceFactory::getHikariDataSource:Exception while creating GemfireBasicDataSource.Exception String=%s", + ex.getLocalizedMessage()), + ex); + } + } + /** * This function returns the Basic datasource without any pooling. * diff --git a/geode-core/src/main/java/org/apache/geode/internal/datasource/HikariJdbcDataSource.java b/geode-core/src/main/java/org/apache/geode/internal/datasource/HikariJdbcDataSource.java new file mode 100644 index 0000000..9a37945 --- /dev/null +++ b/geode-core/src/main/java/org/apache/geode/internal/datasource/HikariJdbcDataSource.java @@ -0,0 +1,90 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more contributor license + * agreements. See the NOTICE file distributed with this work for additional information regarding + * copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the License. You may obtain a + * copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ +package org.apache.geode.internal.datasource; + +import java.io.PrintWriter; +import java.sql.Connection; +import java.sql.SQLException; +import java.sql.SQLFeatureNotSupportedException; +import java.util.logging.Logger; + +import javax.sql.DataSource; + +import com.zaxxer.hikari.HikariDataSource; + +class HikariJdbcDataSource implements DataSource, AutoCloseable { + + private final HikariDataSource delegate; + + // TODO: set more config properties + HikariJdbcDataSource(ConfiguredDataSourceProperties config) { + HikariDataSource ds = new HikariDataSource(); + ds.setJdbcUrl(config.getURL()); + ds.setUsername(config.getUser()); + ds.setPassword(config.getPassword()); +// ds.setDataSourceProperties(config.getConnectionProperties()); + this.delegate = ds; + } + + @Override + public Connection getConnection() throws SQLException { + return this.delegate.getConnection(); + } + + @Override + public Connection getConnection(String username, String password) throws SQLException { + return this.delegate.getConnection(username, password); + } + + @Override + public void close() { + this.delegate.close(); + } + + @Override + public <T> T unwrap(Class<T> iface) throws SQLException { + return this.delegate.unwrap(iface); + } + + @Override + public boolean isWrapperFor(Class<?> iface) throws SQLException { + return this.delegate.isWrapperFor(iface); + } + + @Override + public PrintWriter getLogWriter() throws SQLException { + return this.delegate.getLogWriter(); + } + + @Override + public void setLogWriter(PrintWriter out) throws SQLException { + this.delegate.setLogWriter(out); + } + + @Override + public void setLoginTimeout(int seconds) throws SQLException { + this.delegate.setLoginTimeout(seconds); + } + + @Override + public int getLoginTimeout() throws SQLException { + return this.delegate.getLoginTimeout(); + } + + @Override + public Logger getParentLogger() throws SQLFeatureNotSupportedException { + return this.delegate.getParentLogger(); + } +} diff --git a/geode-core/src/main/java/org/apache/geode/internal/jndi/JNDIInvoker.java b/geode-core/src/main/java/org/apache/geode/internal/jndi/JNDIInvoker.java index 8206cc8..f325963 100644 --- a/geode-core/src/main/java/org/apache/geode/internal/jndi/JNDIInvoker.java +++ b/geode-core/src/main/java/org/apache/geode/internal/jndi/JNDIInvoker.java @@ -21,6 +21,8 @@ import java.util.Hashtable; import java.util.Iterator; import java.util.List; import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; import javax.naming.Binding; import javax.naming.Context; @@ -29,9 +31,13 @@ import javax.naming.NameNotFoundException; import javax.naming.NamingEnumeration; import javax.naming.NamingException; import javax.naming.NoInitialContextException; +import javax.sql.DataSource; import javax.transaction.SystemException; import javax.transaction.TransactionManager; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + import org.apache.geode.LogWriter; import org.apache.geode.distributed.DistributedSystem; import org.apache.geode.distributed.internal.DistributionConfig; @@ -44,6 +50,7 @@ import org.apache.geode.internal.datasource.DataSourceFactory; import org.apache.geode.internal.jta.TransactionManagerImpl; import org.apache.geode.internal.jta.TransactionUtils; import org.apache.geode.internal.jta.UserTransactionImpl; +import org.apache.geode.internal.logging.LogService; /** * <p> @@ -66,6 +73,8 @@ import org.apache.geode.internal.jta.UserTransactionImpl; */ public class JNDIInvoker { + private static final Logger logger = LogService.getLogger(); + // private static boolean DEBUG = false; /** * JNDI Context, this may refer to GemFire JNDI Context or external Context, in case the external @@ -103,7 +112,8 @@ public class JNDIInvoker { * List of DataSource bound to the context, used for cleaning gracefully closing datasource and * associated threads. */ - private static List dataSourceList = new ArrayList(); +// private static List dataSourceList = new ArrayList(); + private static final ConcurrentMap<String, DataSource> dataSourceMap = new ConcurrentHashMap<>(); /** * If this system property is set to true, GemFire will not try to lookup for an existing JTA @@ -208,16 +218,27 @@ public class JNDIInvoker { // ok to ignore, rebind will be tried later } } - int len = dataSourceList.size(); - for (int i = 0; i < len; i++) { - if (dataSourceList.get(i) instanceof AbstractDataSource) - ((AbstractDataSource) dataSourceList.get(i)).clearUp(); - else if (dataSourceList.get(i) instanceof ClientConnectionFactoryWrapper) { - ((ClientConnectionFactoryWrapper) dataSourceList.get(i)).clearUp(); + dataSourceMap.values().stream().forEach(JNDIInvoker::closeDataSource); + dataSourceMap.clear(); + IGNORE_JTA = Boolean.getBoolean(DistributionConfig.GEMFIRE_PREFIX + "ignoreJTA"); + } + + private static void closeDataSource(DataSource dataSource) { + if (dataSource instanceof AutoCloseable) { + try { + ((AutoCloseable) dataSource).close(); + } catch (Exception e) { + if (logger.isDebugEnabled()) { + logger.debug("Exception closing DataSource", e); + } } } - dataSourceList.clear(); - IGNORE_JTA = Boolean.getBoolean(DistributionConfig.GEMFIRE_PREFIX + "ignoreJTA"); + else if (dataSource instanceof AbstractDataSource) { + ((AbstractDataSource) dataSource).clearUp(); + } + else if (dataSource instanceof ClientConnectionFactoryWrapper) { + ((ClientConnectionFactoryWrapper) dataSource).clearUp(); + } } /* @@ -321,31 +342,37 @@ public class JNDIInvoker { String value = (String) map.get("type"); String jndiName = ""; LogWriter writer = TransactionUtils.getLogWriter(); - Object ds = null; + DataSource ds = null; try { jndiName = (String) map.get("jndi-name"); if (value.equals("PooledDataSource")) { ds = DataSourceFactory.getPooledDataSource(map, props); ctx.rebind("java:/" + jndiName, ds); - dataSourceList.add(ds); + dataSourceMap.put(jndiName, ds); if (writer.fineEnabled()) writer.fine("Bound java:/" + jndiName + " to Context"); } else if (value.equals("XAPooledDataSource")) { ds = DataSourceFactory.getTranxDataSource(map, props); ctx.rebind("java:/" + jndiName, ds); - dataSourceList.add(ds); + dataSourceMap.put(jndiName, ds); if (writer.fineEnabled()) writer.fine("Bound java:/" + jndiName + " to Context"); } else if (value.equals("SimpleDataSource")) { ds = DataSourceFactory.getSimpleDataSource(map); ctx.rebind("java:/" + jndiName, ds); - dataSourceList.add(ds); + dataSourceMap.put(jndiName, ds); + if (writer.fineEnabled()) + writer.fine("Bound java:/" + jndiName + " to Context"); + } else if (value.equals("HikariDataSource")) { + ds = DataSourceFactory.getHikariDataSource(map); + ctx.rebind("java:/" + jndiName, ds); + dataSourceMap.put(jndiName, ds); if (writer.fineEnabled()) writer.fine("Bound java:/" + jndiName + " to Context"); } else if (value.equals("ManagedDataSource")) { ClientConnectionFactoryWrapper ds1 = DataSourceFactory.getManagedDataSource(map, props); ctx.rebind("java:/" + jndiName, ds1.getClientConnFactory()); - dataSourceList.add(ds1); + dataSourceMap.put(jndiName, ds); if (writer.fineEnabled()) writer.fine("Bound java:/" + jndiName + " to Context"); } else { @@ -370,15 +397,8 @@ public class JNDIInvoker { public static void unMapDatasource(String jndiName) throws NamingException { ctx.unbind("java:/" + jndiName); - for (Iterator it = dataSourceList.iterator(); it.hasNext();) { - Object obj = it.next(); - if (obj instanceof AbstractDataSource) { - ((AbstractDataSource) obj).clearUp(); - } else if (obj instanceof ClientConnectionFactoryWrapper) { - ((ClientConnectionFactoryWrapper) obj).clearUp(); - } - it.remove(); - } + DataSource removedDataSource = dataSourceMap.remove(jndiName); + closeDataSource(removedDataSource); } /** @@ -398,7 +418,7 @@ public class JNDIInvoker { } public static int getNoOfAvailableDataSources() { - return dataSourceList.size(); + return dataSourceMap.size(); } public static Map<String, String> getBindingNamesRecursively(Context ctx) throws Exception { diff --git a/geode-core/src/main/java/org/apache/geode/management/internal/cli/commands/CreateJndiBindingCommand.java b/geode-core/src/main/java/org/apache/geode/management/internal/cli/commands/CreateJndiBindingCommand.java index e034aef..bebb226 100644 --- a/geode-core/src/main/java/org/apache/geode/management/internal/cli/commands/CreateJndiBindingCommand.java +++ b/geode-core/src/main/java/org/apache/geode/management/internal/cli/commands/CreateJndiBindingCommand.java @@ -182,7 +182,8 @@ public class CreateJndiBindingCommand extends SingleGfshCommand { MANAGED("ManagedDataSource"), SIMPLE("SimpleDataSource"), POOLED("PooledDataSource"), - XAPOOLED("XAPooledDataSource"); + XAPOOLED("XAPooledDataSource"), + HIKARI("HikariDataSource"); private final String type; diff --git a/geode-core/src/test/resources/expected-pom.xml b/geode-core/src/test/resources/expected-pom.xml index 0ff3525..1428d4a 100644 --- a/geode-core/src/test/resources/expected-pom.xml +++ b/geode-core/src/test/resources/expected-pom.xml @@ -36,6 +36,12 @@ </scm> <dependencies> <dependency> + <groupId>com.zaxxer</groupId> + <artifactId>HikariCP</artifactId> + <version>3.2.0</version> + <scope>compile</scope> + </dependency> + <dependency> <groupId>com.github.stephenc.findbugs</groupId> <artifactId>findbugs-annotations</artifactId> <version>1.3.9-1</version>