sprint-1 - JDBC renaming and reshuffling.
Project: http://git-wip-us.apache.org/repos/asf/incubator-ignite/repo Commit: http://git-wip-us.apache.org/repos/asf/incubator-ignite/commit/17d816fe Tree: http://git-wip-us.apache.org/repos/asf/incubator-ignite/tree/17d816fe Diff: http://git-wip-us.apache.org/repos/asf/incubator-ignite/diff/17d816fe Branch: refs/heads/ignite-188 Commit: 17d816fe47d68ba0f8a15806e8a67c390ed11aea Parents: 2f1c7b3 Author: Dmitiry Setrakyan <dsetrak...@gridgain.com> Authored: Thu Feb 5 19:48:13 2015 -0800 Committer: Dmitiry Setrakyan <dsetrak...@gridgain.com> Committed: Thu Feb 5 19:48:13 2015 -0800 ---------------------------------------------------------------------- .../ignite/jdbc/JdbcComplexQuerySelfTest.java | 2 +- .../ignite/jdbc/JdbcConnectionSelfTest.java | 2 +- .../ignite/jdbc/JdbcEmptyCacheSelfTest.java | 2 +- .../ignite/jdbc/JdbcLocalCachesSelfTest.java | 4 +- .../ignite/jdbc/JdbcMetadataSelfTest.java | 2 +- .../jdbc/JdbcPreparedStatementSelfTest.java | 2 +- .../ignite/jdbc/JdbcResultSetSelfTest.java | 2 +- .../ignite/jdbc/JdbcStatementSelfTest.java | 2 +- .../org/apache/ignite/IgniteJdbcDriver.java | 484 ++++++ .../ignite/internal/jdbc/JdbcConnection.java | 547 +++++++ .../internal/jdbc/JdbcConnectionInfo.java | 91 ++ .../internal/jdbc/JdbcDatabaseMetadata.java | 1313 +++++++++++++++ .../internal/jdbc/JdbcPreparedStatement.java | 411 +++++ .../ignite/internal/jdbc/JdbcResultSet.java | 1519 +++++++++++++++++ .../internal/jdbc/JdbcResultSetMetadata.java | 170 ++ .../ignite/internal/jdbc/JdbcStatement.java | 448 ++++++ .../apache/ignite/internal/jdbc/JdbcUtils.java | 232 +++ .../ignite/jdbc/IgniteJdbcConnection.java | 547 ------- .../ignite/jdbc/IgniteJdbcConnectionInfo.java | 91 -- .../ignite/jdbc/IgniteJdbcDatabaseMetadata.java | 1314 --------------- .../apache/ignite/jdbc/IgniteJdbcDriver.java | 482 ------ .../jdbc/IgniteJdbcPreparedStatement.java | 411 ----- .../apache/ignite/jdbc/IgniteJdbcResultSet.java | 1520 ------------------ .../jdbc/IgniteJdbcResultSetMetadata.java | 172 -- .../apache/ignite/jdbc/IgniteJdbcStatement.java | 449 ------ .../java/org/apache/ignite/jdbc/package.html | 23 - .../java/org/apache/ignite/jdbc/typedef/JU.java | 28 - .../org/apache/ignite/jdbc/typedef/package.html | 23 - .../ignite/jdbc/util/IgniteJdbcUtils.java | 232 --- .../org/apache/ignite/jdbc/util/package.html | 23 - 30 files changed, 5224 insertions(+), 5324 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/17d816fe/modules/clients/src/test/java/org/apache/ignite/jdbc/JdbcComplexQuerySelfTest.java ---------------------------------------------------------------------- diff --git a/modules/clients/src/test/java/org/apache/ignite/jdbc/JdbcComplexQuerySelfTest.java b/modules/clients/src/test/java/org/apache/ignite/jdbc/JdbcComplexQuerySelfTest.java index e01143e..e098387 100644 --- a/modules/clients/src/test/java/org/apache/ignite/jdbc/JdbcComplexQuerySelfTest.java +++ b/modules/clients/src/test/java/org/apache/ignite/jdbc/JdbcComplexQuerySelfTest.java @@ -92,7 +92,7 @@ public class JdbcComplexQuerySelfTest extends GridCommonAbstractTest { personCache.put(new CacheAffinityKey<>("p2", "o1"), new Person(2, "Joe Black", 35, 1)); personCache.put(new CacheAffinityKey<>("p3", "o2"), new Person(3, "Mike Green", 40, 2)); - Class.forName("org.apache.ignite.jdbc.IgniteJdbcDriver"); + Class.forName("org.apache.ignite.IgniteJdbcDriver"); } /** {@inheritDoc} */ http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/17d816fe/modules/clients/src/test/java/org/apache/ignite/jdbc/JdbcConnectionSelfTest.java ---------------------------------------------------------------------- diff --git a/modules/clients/src/test/java/org/apache/ignite/jdbc/JdbcConnectionSelfTest.java b/modules/clients/src/test/java/org/apache/ignite/jdbc/JdbcConnectionSelfTest.java index c79b86b..251039b 100644 --- a/modules/clients/src/test/java/org/apache/ignite/jdbc/JdbcConnectionSelfTest.java +++ b/modules/clients/src/test/java/org/apache/ignite/jdbc/JdbcConnectionSelfTest.java @@ -88,7 +88,7 @@ public class JdbcConnectionSelfTest extends GridCommonAbstractTest { @Override protected void beforeTestsStarted() throws Exception { startGridsMultiThreaded(2); - Class.forName("org.apache.ignite.jdbc.IgniteJdbcDriver"); + Class.forName("org.apache.ignite.IgniteJdbcDriver"); } /** {@inheritDoc} */ http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/17d816fe/modules/clients/src/test/java/org/apache/ignite/jdbc/JdbcEmptyCacheSelfTest.java ---------------------------------------------------------------------- diff --git a/modules/clients/src/test/java/org/apache/ignite/jdbc/JdbcEmptyCacheSelfTest.java b/modules/clients/src/test/java/org/apache/ignite/jdbc/JdbcEmptyCacheSelfTest.java index 03562a2..38cebf3 100644 --- a/modules/clients/src/test/java/org/apache/ignite/jdbc/JdbcEmptyCacheSelfTest.java +++ b/modules/clients/src/test/java/org/apache/ignite/jdbc/JdbcEmptyCacheSelfTest.java @@ -72,7 +72,7 @@ public class JdbcEmptyCacheSelfTest extends GridCommonAbstractTest { @Override protected void beforeTestsStarted() throws Exception { startGrid(); - Class.forName("org.apache.ignite.jdbc.IgniteJdbcDriver"); + Class.forName("org.apache.ignite.IgniteJdbcDriver"); } /** {@inheritDoc} */ http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/17d816fe/modules/clients/src/test/java/org/apache/ignite/jdbc/JdbcLocalCachesSelfTest.java ---------------------------------------------------------------------- diff --git a/modules/clients/src/test/java/org/apache/ignite/jdbc/JdbcLocalCachesSelfTest.java b/modules/clients/src/test/java/org/apache/ignite/jdbc/JdbcLocalCachesSelfTest.java index 244133f..ae3e8cb 100644 --- a/modules/clients/src/test/java/org/apache/ignite/jdbc/JdbcLocalCachesSelfTest.java +++ b/modules/clients/src/test/java/org/apache/ignite/jdbc/JdbcLocalCachesSelfTest.java @@ -30,7 +30,7 @@ import java.util.*; import static org.apache.ignite.cache.CacheMode.*; import static org.apache.ignite.cache.CacheWriteSynchronizationMode.*; -import static org.apache.ignite.jdbc.IgniteJdbcDriver.*; +import static org.apache.ignite.IgniteJdbcDriver.*; /** * Test JDBC with several local caches. @@ -92,7 +92,7 @@ public class JdbcLocalCachesSelfTest extends GridCommonAbstractTest { assert cache2.putx("key1", 3); assert cache2.putx("key2", 4); - Class.forName("org.apache.ignite.jdbc.IgniteJdbcDriver"); + Class.forName("org.apache.ignite.IgniteJdbcDriver"); } /** {@inheritDoc} */ http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/17d816fe/modules/clients/src/test/java/org/apache/ignite/jdbc/JdbcMetadataSelfTest.java ---------------------------------------------------------------------- diff --git a/modules/clients/src/test/java/org/apache/ignite/jdbc/JdbcMetadataSelfTest.java b/modules/clients/src/test/java/org/apache/ignite/jdbc/JdbcMetadataSelfTest.java index 82a5a54..977809c 100644 --- a/modules/clients/src/test/java/org/apache/ignite/jdbc/JdbcMetadataSelfTest.java +++ b/modules/clients/src/test/java/org/apache/ignite/jdbc/JdbcMetadataSelfTest.java @@ -87,7 +87,7 @@ public class JdbcMetadataSelfTest extends GridCommonAbstractTest { personCache.put(new CacheAffinityKey<>("p2", "o1"), new Person("Joe Black", 35, 1)); personCache.put(new CacheAffinityKey<>("p3", "o2"), new Person("Mike Green", 40, 2)); - Class.forName("org.apache.ignite.jdbc.IgniteJdbcDriver"); + Class.forName("org.apache.ignite.IgniteJdbcDriver"); } /** {@inheritDoc} */ http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/17d816fe/modules/clients/src/test/java/org/apache/ignite/jdbc/JdbcPreparedStatementSelfTest.java ---------------------------------------------------------------------- diff --git a/modules/clients/src/test/java/org/apache/ignite/jdbc/JdbcPreparedStatementSelfTest.java b/modules/clients/src/test/java/org/apache/ignite/jdbc/JdbcPreparedStatementSelfTest.java index 5850f5a..de973bd 100644 --- a/modules/clients/src/test/java/org/apache/ignite/jdbc/JdbcPreparedStatementSelfTest.java +++ b/modules/clients/src/test/java/org/apache/ignite/jdbc/JdbcPreparedStatementSelfTest.java @@ -102,7 +102,7 @@ public class JdbcPreparedStatementSelfTest extends GridCommonAbstractTest { cache.put(1, o); cache.put(2, new TestObject(2)); - Class.forName("org.apache.ignite.jdbc.IgniteJdbcDriver"); + Class.forName("org.apache.ignite.IgniteJdbcDriver"); } /** {@inheritDoc} */ http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/17d816fe/modules/clients/src/test/java/org/apache/ignite/jdbc/JdbcResultSetSelfTest.java ---------------------------------------------------------------------- diff --git a/modules/clients/src/test/java/org/apache/ignite/jdbc/JdbcResultSetSelfTest.java b/modules/clients/src/test/java/org/apache/ignite/jdbc/JdbcResultSetSelfTest.java index 9155742..e3c6f84 100644 --- a/modules/clients/src/test/java/org/apache/ignite/jdbc/JdbcResultSetSelfTest.java +++ b/modules/clients/src/test/java/org/apache/ignite/jdbc/JdbcResultSetSelfTest.java @@ -94,7 +94,7 @@ public class JdbcResultSetSelfTest extends GridCommonAbstractTest { cache.put(1, o); cache.put(2, new TestObject(2)); - Class.forName("org.apache.ignite.jdbc.IgniteJdbcDriver"); + Class.forName("org.apache.ignite.IgniteJdbcDriver"); } /** {@inheritDoc} */ http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/17d816fe/modules/clients/src/test/java/org/apache/ignite/jdbc/JdbcStatementSelfTest.java ---------------------------------------------------------------------- diff --git a/modules/clients/src/test/java/org/apache/ignite/jdbc/JdbcStatementSelfTest.java b/modules/clients/src/test/java/org/apache/ignite/jdbc/JdbcStatementSelfTest.java index 082f980..39b619d 100644 --- a/modules/clients/src/test/java/org/apache/ignite/jdbc/JdbcStatementSelfTest.java +++ b/modules/clients/src/test/java/org/apache/ignite/jdbc/JdbcStatementSelfTest.java @@ -86,7 +86,7 @@ public class JdbcStatementSelfTest extends GridCommonAbstractTest { cache.put("p2", new Person(2, "Joe", "Black", 35)); cache.put("p3", new Person(3, "Mike", "Green", 40)); - Class.forName("org.apache.ignite.jdbc.IgniteJdbcDriver"); + Class.forName("org.apache.ignite.IgniteJdbcDriver"); } /** {@inheritDoc} */ http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/17d816fe/modules/core/src/main/java/org/apache/ignite/IgniteJdbcDriver.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/IgniteJdbcDriver.java b/modules/core/src/main/java/org/apache/ignite/IgniteJdbcDriver.java new file mode 100644 index 0000000..489e8ac --- /dev/null +++ b/modules/core/src/main/java/org/apache/ignite/IgniteJdbcDriver.java @@ -0,0 +1,484 @@ +/* + * 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.ignite; + + +import org.apache.ignite.internal.jdbc.*; + +import java.sql.*; +import java.util.*; +import java.util.logging.*; + +/** + * JDBC driver implementation for In-Memory Data Grid. + * <p> + * Driver allows to get distributed data from GridGain cache using standard + * SQL queries and standard JDBC API. It will automatically get only fields that + * you actually need from objects stored in cache. + * <h1 class="header">Limitations</h1> + * Data in GridGain cache is usually distributed across several nodes, + * so some queries may not work as expected since the query will be sent to each + * individual node and results will then be collected and returned as JDBC result set. + * Keep in mind following limitations (not applied if data is queried from one node only, + * or data is fully co-located or fully replicated on multiple nodes): + * <ul> + * <li> + * {@code Group by} and {@code sort by} statements are applied separately + * on each node, so result set will likely be incorrectly grouped or sorted + * after results from multiple remote nodes are grouped together. + * </li> + * <li> + * Aggregation functions like {@code sum}, {@code max}, {@code avg}, etc. + * are also applied on each node. Therefore you will get several results + * containing aggregated values, one for each node. + * </li> + * <li> + * Joins will work correctly only if joined objects are stored in + * collocated mode. Refer to + * {@link org.apache.ignite.cache.affinity.CacheAffinityKey} + * javadoc for more details. + * </li> + * <li> + * Note that if you are connected to local or replicated cache, all data will + * be queried only on one node, not depending on what caches participate in + * the query (some data from partitioned cache can be lost). And visa versa, + * if you are connected to partitioned cache, data from replicated caches + * will be duplicated. + * </li> + * </ul> + * <h1 class="header">SQL Notice</h1> + * Driver allows to query data from several caches. Cache that driver is connected to is + * treated as default schema in this case. Other caches can be referenced by their names. + * <p> + * Note that cache name is case sensitive and you have to always specify it in quotes. + * <h1 class="header">Dependencies</h1> + * JDBC driver is located in main GridGain JAR and depends on all libraries located in + * {@code IGNITE_HOME/libs} folder. So if you are using JDBC driver in any external tool, + * you have to add main GridGain JAR will all dependencies to its classpath. + * <h1 class="header">Configuration</h1> + * Internally JDBC driver <b>is based on GridGain Java client</b>. Therefore, all client + * configuration properties can be applied to JDBC connection. + * <p> + * JDBC connection URL has the following pattern: + * {@code jdbc:gridgain://<hostname>:<port>/<cache_name>?nodeId=<UUID>}<br> + * Note the following: + * <ul> + * <li>Hostname is required.</li> + * <li>If port is not defined, {@code 11211} is used (default for GridGain client).</li> + * <li>Leave {@code <cache_name>} empty if you are connecting to default cache.</li> + * <li> + * Provide {@code nodeId} parameter if you want to specify node where to execute + * your queries. Note that local and replicated caches will be queried locally on + * this node while partitioned cache is queried distributively. If node ID is not + * provided, random node is used. If node with provided ID doesn't exist, + * exception is thrown. + * </li> + * </ul> + * Other properties can be defined in {@link Properties} object passed to + * {@link DriverManager#getConnection(String, Properties)} method: + * <table class="doctable"> + * <tr> + * <th>Name</th> + * <th>Description</th> + * <th>Default</th> + * <th>Optional</th> + * </tr> + * <tr> + * <td><b>gg.client.protocol</b></td> + * <td>Communication protocol ({@code TCP} or {@code HTTP}).</td> + * <td>{@code TCP}</td> + * <td>Yes</td> + * </tr> + * <tr> + * <td><b>gg.client.connectTimeout</b></td> + * <td>Socket connection timeout.</td> + * <td>{@code 0} (infinite timeout)</td> + * <td>Yes</td> + * </tr> + * <tr> + * <td><b>gg.client.tcp.noDelay</b></td> + * <td>Flag indicating whether TCP_NODELAY flag should be enabled for outgoing connections.</td> + * <td>{@code true}</td> + * <td>Yes</td> + * </tr> + * <tr> + * <td><b>gg.client.ssl.enabled</b></td> + * <td>Flag indicating that {@code SSL} is needed for connection.</td> + * <td>{@code false}</td> + * <td>Yes</td> + * </tr> + * <tr> + * <td><b>gg.client.ssl.protocol</b></td> + * <td>SSL protocol ({@code SSL} or {@code TLS}).</td> + * <td>{@code TLS}</td> + * <td>Yes</td> + * </tr> + * <tr> + * <td><b>gg.client.ssl.key.algorithm</b></td> + * <td>Key manager algorithm.</td> + * <td>{@code SunX509}</td> + * <td>Yes</td> + * </tr> + * <tr> + * <td><b>gg.client.ssl.keystore.location</b></td> + * <td>Key store to be used by client to connect with GridGain topology.</td> + * <td> </td> + * <td>No (if {@code SSL} is enabled)</td> + * </tr> + * <tr> + * <td><b>gg.client.ssl.keystore.password</b></td> + * <td>Key store password.</td> + * <td> </td> + * <td>Yes</td> + * </tr> + * <tr> + * <td><b>gg.client.ssl.keystore.type</b></td> + * <td>Key store type.</td> + * <td>{@code jks}</td> + * <td>Yes</td> + * </tr> + * <tr> + * <td><b>gg.client.ssl.truststore.location</b></td> + * <td>Trust store to be used by client to connect with GridGain topology.</td> + * <td> </td> + * <td>No (if {@code SSL} is enabled)</td> + * </tr> + * <tr> + * <td><b>gg.client.ssl.truststore.password</b></td> + * <td>Trust store password.</td> + * <td> </td> + * <td>Yes</td> + * </tr> + * <tr> + * <td><b>gg.client.ssl.truststore.type</b></td> + * <td>Trust store type.</td> + * <td>{@code jks}</td> + * <td>Yes</td> + * </tr> + * <tr> + * <td><b>gg.client.credentials</b></td> + * <td>Client credentials used in authentication process.</td> + * <td> </td> + * <td>Yes</td> + * </tr> + * <tr> + * <td><b>gg.client.cache.top</b></td> + * <td> + * Flag indicating that topology is cached internally. Cache will be refreshed in + * the background with interval defined by {@code gg.client.topology.refresh} + * property (see below). + * </td> + * <td>{@code false}</td> + * <td>Yes</td> + * </tr> + * <tr> + * <td><b>gg.client.topology.refresh</b></td> + * <td>Topology cache refresh frequency (ms).</td> + * <td>{@code 2000}</td> + * <td>Yes</td> + * </tr> + * <tr> + * <td><b>gg.client.idleTimeout</b></td> + * <td>Maximum amount of time that connection can be idle before it is closed (ms).</td> + * <td>{@code 30000}</td> + * <td>Yes</td> + * </tr> + * </table> + * <h1 class="header">Example</h1> + * <pre name="code" class="java"> + * // Register JDBC driver. + * Class.forName("org.gridgain.jdbc.IgniteJdbcDriver"); + * + * // Open JDBC connection. + * Connection conn = DriverManager.getConnection("jdbc:gridgain://localhost/cache"); + * + * // Query persons' names + * ResultSet rs = conn.createStatement().executeQuery("select name from Person"); + * + * while (rs.next()) { + * String name = rs.getString(1); + * + * ... + * } + * + * // Query persons with specific age + * PreparedStatement stmt = conn.prepareStatement("select name, age from Person where age = ?"); + * + * stmt.setInt(1, 30); + * + * ResultSet rs = stmt.executeQuery(); + * + * while (rs.next()) { + * String name = rs.getString("name"); + * int age = rs.getInt("age"); + * + * ... + * } + * </pre> + */ +@SuppressWarnings("JavadocReference") +public class IgniteJdbcDriver implements Driver { + /** Prefix for property names. */ + private static final String PROP_PREFIX = "gg.jdbc."; + + /** Hostname property name. */ + public static final String PROP_HOST = PROP_PREFIX + "host"; + + /** Port number property name. */ + public static final String PROP_PORT = PROP_PREFIX + "port"; + + /** Cache name property name. */ + public static final String PROP_CACHE = PROP_PREFIX + "cache"; + + /** Node ID URL parameter name. */ + public static final String PARAM_NODE_ID = "nodeId"; + + /** Node ID property name. */ + public static final String PROP_NODE_ID = PROP_PREFIX + PARAM_NODE_ID; + + /** URL prefix. */ + public static final String URL_PREFIX = "jdbc:gridgain://"; + + /** Default port. */ + public static final int DFLT_PORT = 11211; + + /** Major version. */ + private static final int MAJOR_VER = 1; + + /** Minor version. */ + private static final int MINOR_VER = 0; + + /** + * Register driver. + */ + static { + try { + DriverManager.registerDriver(new IgniteJdbcDriver()); + } + catch (SQLException e) { + throw new RuntimeException("Failed to register GridGain JDBC driver.", e); + } + } + + /** {@inheritDoc} */ + @Override public Connection connect(String url, Properties props) throws SQLException { + if (!parseUrl(url, props)) + throw new SQLException("URL is invalid: " + url); + + return new JdbcConnection(url, props); + } + + /** {@inheritDoc} */ + @Override public boolean acceptsURL(String url) throws SQLException { + return url.startsWith(URL_PREFIX); + } + + /** {@inheritDoc} */ + @Override public DriverPropertyInfo[] getPropertyInfo(String url, Properties info) throws SQLException { + if (!parseUrl(url, info)) + throw new SQLException("URL is invalid: " + url); + + DriverPropertyInfo[] props = new DriverPropertyInfo[20]; + + props[0] = new PropertyInfo("Hostname", info.getProperty(PROP_HOST), true); + props[1] = new PropertyInfo("Port number", info.getProperty(PROP_PORT), ""); + props[2] = new PropertyInfo("Cache name", info.getProperty(PROP_CACHE), ""); + props[3] = new PropertyInfo("Node ID", info.getProperty(PROP_NODE_ID, "")); + props[4] = new PropertyInfo("gg.client.protocol", info.getProperty("gg.client.protocol", "TCP"), + "Communication protocol (TCP or HTTP)."); + props[5] = new PropertyInfo("gg.client.connectTimeout", info.getProperty("gg.client.connectTimeout", "0"), + "Socket connection timeout."); + props[6] = new PropertyInfo("gg.client.tcp.noDelay", info.getProperty("gg.client.tcp.noDelay", "true"), + "Flag indicating whether TCP_NODELAY flag should be enabled for outgoing connections."); + props[7] = new PropertyInfo("gg.client.ssl.enabled", info.getProperty("gg.client.ssl.enabled", "false"), + "Flag indicating that SSL is needed for connection."); + props[8] = new PropertyInfo("gg.client.ssl.protocol", info.getProperty("gg.client.ssl.protocol", "TLS"), + "SSL protocol."); + props[9] = new PropertyInfo("gg.client.ssl.key.algorithm", info.getProperty("gg.client.ssl.key.algorithm", + "SunX509"), "Key manager algorithm."); + props[10] = new PropertyInfo("gg.client.ssl.keystore.location", + info.getProperty("gg.client.ssl.keystore.location", ""), + "Key store to be used by client to connect with GridGain topology."); + props[11] = new PropertyInfo("gg.client.ssl.keystore.password", + info.getProperty("gg.client.ssl.keystore.password", ""), "Key store password."); + props[12] = new PropertyInfo("gg.client.ssl.keystore.type", info.getProperty("gg.client.ssl.keystore.type", + "jks"), "Key store type."); + props[13] = new PropertyInfo("gg.client.ssl.truststore.location", + info.getProperty("gg.client.ssl.truststore.location", ""), + "Trust store to be used by client to connect with GridGain topology."); + props[14] = new PropertyInfo("gg.client.ssl.keystore.password", + info.getProperty("gg.client.ssl.truststore.password", ""), "Trust store password."); + props[15] = new PropertyInfo("gg.client.ssl.truststore.type", info.getProperty("gg.client.ssl.truststore.type", + "jks"), "Trust store type."); + props[16] = new PropertyInfo("gg.client.credentials", info.getProperty("gg.client.credentials", ""), + "Client credentials used in authentication process."); + props[17] = new PropertyInfo("gg.client.cache.top", info.getProperty("gg.client.cache.top", "false"), + "Flag indicating that topology is cached internally. Cache will be refreshed in the background with " + + "interval defined by topologyRefreshFrequency property (see below)."); + props[18] = new PropertyInfo("gg.client.topology.refresh", info.getProperty("gg.client.topology.refresh", + "2000"), "Topology cache refresh frequency (ms)."); + props[19] = new PropertyInfo("gg.client.idleTimeout", info.getProperty("gg.client.idleTimeout", "30000"), + "Maximum amount of time that connection can be idle before it is closed (ms)."); + + return props; + } + + /** {@inheritDoc} */ + @Override public int getMajorVersion() { + return MAJOR_VER; + } + + /** {@inheritDoc} */ + @Override public int getMinorVersion() { + return MINOR_VER; + } + + /** {@inheritDoc} */ + @Override public boolean jdbcCompliant() { + return false; + } + + /** {@inheritDoc} */ + @Override public Logger getParentLogger() throws SQLFeatureNotSupportedException { + throw new SQLFeatureNotSupportedException("java.util.logging is not used."); + } + + /** + * Validates and parses connection URL. + * + * @param props Properties. + * @param url URL. + * @return Whether URL is valid. + */ + private boolean parseUrl(String url, Properties props) { + if (url == null || !url.startsWith(URL_PREFIX) || url.length() == URL_PREFIX.length()) + return false; + + url = url.substring(URL_PREFIX.length()); + + String[] parts = url.split("\\?"); + + if (parts.length > 2) + return false; + + if (parts.length == 2) + if (!parseUrlParameters(parts[1], props)) + return false; + + parts = parts[0].split("/"); + + assert parts.length > 0; + + if (parts.length > 2) + return false; + + if (parts.length == 2 && !parts[1].isEmpty()) + props.setProperty(PROP_CACHE, parts[1]); + + url = parts[0]; + + parts = url.split(":"); + + assert parts.length > 0; + + if (parts.length > 2) + return false; + + props.setProperty(PROP_HOST, parts[0]); + + try { + props.setProperty(PROP_PORT, String.valueOf(parts.length == 2 ? Integer.valueOf(parts[1]) : DFLT_PORT)); + } + catch (NumberFormatException ignored) { + return false; + } + + return true; + } + + /** + * Validates and parses URL parameters. + * + * @param urlParams URL parameters string. + * @param props Properties. + * @return Whether URL parameters string is valid. + */ + private boolean parseUrlParameters(String urlParams, Properties props) { + String[] params = urlParams.split("&"); + + for (String param : params) { + String[] pair = param.split("="); + + if (pair.length != 2 || pair[0].isEmpty() || pair[1].isEmpty()) + return false; + + props.setProperty(PROP_PREFIX + pair[0], pair[1]); + } + + return true; + } + + /** + * Extension of {@link DriverPropertyInfo} that adds + * convenient constructors. + */ + private static class PropertyInfo extends DriverPropertyInfo { + /** + * @param name Name. + * @param val Value. + */ + private PropertyInfo(String name, String val) { + super(name, val); + } + + /** + * @param name Name. + * @param val Value. + * @param desc Description. + */ + private PropertyInfo(String name, String val, String desc) { + super(name, val); + + description = desc; + } + + /** + * @param name Name. + * @param val Value. + * @param required Required flag. + */ + private PropertyInfo(String name, String val, boolean required) { + super(name, val); + + this.required = required; + } + + /** + * @param name Name. + * @param val Value. + * @param desc Description. + * @param required Required flag. + */ + private PropertyInfo(String name, String val, String desc, boolean required) { + super(name, val); + + description = desc; + this.required = required; + } + } +} http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/17d816fe/modules/core/src/main/java/org/apache/ignite/internal/jdbc/JdbcConnection.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/jdbc/JdbcConnection.java b/modules/core/src/main/java/org/apache/ignite/internal/jdbc/JdbcConnection.java new file mode 100644 index 0000000..5d37cc7 --- /dev/null +++ b/modules/core/src/main/java/org/apache/ignite/internal/jdbc/JdbcConnection.java @@ -0,0 +1,547 @@ +/* + * 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.ignite.internal.jdbc; + +import org.apache.ignite.client.*; + +import java.sql.*; +import java.util.*; +import java.util.concurrent.*; + +import static java.sql.ResultSet.*; +import static java.util.concurrent.TimeUnit.*; +import static org.apache.ignite.IgniteJdbcDriver.*; + +/** + * JDBC connection implementation. + */ +public class JdbcConnection implements Connection { + /** Validation task name. */ + private static final String VALID_TASK_NAME = + "org.apache.ignite.internal.processors.cache.query.jdbc.GridCacheQueryJdbcValidationTask"; + + /** GridGain client. */ + private final GridClient client; + + /** Cache name. */ + private String cacheName; + + /** Closed flag. */ + private boolean closed; + + /** URL. */ + private String url; + + /** Node ID. */ + private UUID nodeId; + + /** Timeout. */ + private int timeout; + + /** + * Creates new connection. + * + * @param url Connection URL. + * @param props Additional properties. + * @throws SQLException In case GridGain client failed to start. + */ + public JdbcConnection(String url, Properties props) throws SQLException { + assert url != null; + assert props != null; + + this.url = url; + cacheName = props.getProperty(PROP_CACHE); + + String nodeIdProp = props.getProperty(PROP_NODE_ID); + + if (nodeIdProp != null) + nodeId = UUID.fromString(nodeIdProp); + + try { + GridClientConfiguration cfg = new GridClientConfiguration(props); + + cfg.setServers(Collections.singleton(props.getProperty(PROP_HOST) + ":" + props.getProperty(PROP_PORT))); + + // Disable all fetching and caching for metadata. + cfg.setEnableMetricsCache(false); + cfg.setEnableAttributesCache(false); + cfg.setAutoFetchMetrics(false); + cfg.setAutoFetchAttributes(false); + + client = GridClientFactory.start(cfg); + } + catch (GridClientException e) { + throw new SQLException("Failed to start GridGain client.", e); + } + + if (!isValid(2)) + throw new SQLException("Client is invalid. Probably cache name is wrong."); + } + + /** {@inheritDoc} */ + @Override public Statement createStatement() throws SQLException { + return createStatement(TYPE_FORWARD_ONLY, CONCUR_READ_ONLY, HOLD_CURSORS_OVER_COMMIT); + } + + /** {@inheritDoc} */ + @Override public PreparedStatement prepareStatement(String sql) throws SQLException { + ensureNotClosed(); + + return prepareStatement(sql, TYPE_FORWARD_ONLY, CONCUR_READ_ONLY, HOLD_CURSORS_OVER_COMMIT); + } + + /** {@inheritDoc} */ + @Override public CallableStatement prepareCall(String sql) throws SQLException { + ensureNotClosed(); + + throw new SQLFeatureNotSupportedException("Callable functions are not supported."); + } + + /** {@inheritDoc} */ + @Override public String nativeSQL(String sql) throws SQLException { + ensureNotClosed(); + + return sql; + } + + /** {@inheritDoc} */ + @Override public void setAutoCommit(boolean autoCommit) throws SQLException { + ensureNotClosed(); + + if (!autoCommit) + throw new SQLFeatureNotSupportedException("Transactions are not supported."); + } + + /** {@inheritDoc} */ + @Override public boolean getAutoCommit() throws SQLException { + ensureNotClosed(); + + return true; + } + + /** {@inheritDoc} */ + @Override public void commit() throws SQLException { + ensureNotClosed(); + + throw new SQLFeatureNotSupportedException("Transactions are not supported."); + } + + /** {@inheritDoc} */ + @Override public void rollback() throws SQLException { + ensureNotClosed(); + + throw new SQLFeatureNotSupportedException("Transactions are not supported."); + } + + /** {@inheritDoc} */ + @Override public void close() throws SQLException { + if (closed) + return; + + closed = true; + + GridClientFactory.stop(client.id(), false); + } + + /** {@inheritDoc} */ + @Override public boolean isClosed() throws SQLException { + return closed; + } + + /** {@inheritDoc} */ + @Override public DatabaseMetaData getMetaData() throws SQLException { + ensureNotClosed(); + + return new JdbcDatabaseMetadata(this); + } + + /** {@inheritDoc} */ + @Override public void setReadOnly(boolean readOnly) throws SQLException { + ensureNotClosed(); + + if (!readOnly) + throw new SQLFeatureNotSupportedException("Updates are not supported."); + } + + /** {@inheritDoc} */ + @Override public boolean isReadOnly() throws SQLException { + ensureNotClosed(); + + return true; + } + + /** {@inheritDoc} */ + @Override public void setCatalog(String catalog) throws SQLException { + ensureNotClosed(); + + throw new SQLFeatureNotSupportedException("Catalogs are not supported."); + } + + /** {@inheritDoc} */ + @Override public String getCatalog() throws SQLException { + ensureNotClosed(); + + return null; + } + + /** {@inheritDoc} */ + @Override public void setTransactionIsolation(int level) throws SQLException { + ensureNotClosed(); + + throw new SQLFeatureNotSupportedException("Transactions are not supported."); + } + + /** {@inheritDoc} */ + @Override public int getTransactionIsolation() throws SQLException { + ensureNotClosed(); + + throw new SQLFeatureNotSupportedException("Transactions are not supported."); + } + + /** {@inheritDoc} */ + @Override public SQLWarning getWarnings() throws SQLException { + ensureNotClosed(); + + return null; + } + + /** {@inheritDoc} */ + @Override public void clearWarnings() throws SQLException { + ensureNotClosed(); + } + + /** {@inheritDoc} */ + @Override public Statement createStatement(int resSetType, int resSetConcurrency) throws SQLException { + return createStatement(resSetType, resSetConcurrency, HOLD_CURSORS_OVER_COMMIT); + } + + /** {@inheritDoc} */ + @Override public PreparedStatement prepareStatement(String sql, int resSetType, + int resSetConcurrency) throws SQLException { + ensureNotClosed(); + + return prepareStatement(sql, resSetType, resSetConcurrency, HOLD_CURSORS_OVER_COMMIT); + } + + /** {@inheritDoc} */ + @Override public CallableStatement prepareCall(String sql, int resSetType, + int resSetConcurrency) throws SQLException { + ensureNotClosed(); + + throw new SQLFeatureNotSupportedException("Callable functions are not supported."); + } + + /** {@inheritDoc} */ + @Override public Map<String, Class<?>> getTypeMap() throws SQLException { + throw new SQLFeatureNotSupportedException("Types mapping is not supported."); + } + + /** {@inheritDoc} */ + @Override public void setTypeMap(Map<String, Class<?>> map) throws SQLException { + ensureNotClosed(); + + throw new SQLFeatureNotSupportedException("Types mapping is not supported."); + } + + /** {@inheritDoc} */ + @Override public void setHoldability(int holdability) throws SQLException { + ensureNotClosed(); + + if (holdability != HOLD_CURSORS_OVER_COMMIT) + throw new SQLFeatureNotSupportedException("Invalid holdability (transactions are not supported)."); + } + + /** {@inheritDoc} */ + @Override public int getHoldability() throws SQLException { + ensureNotClosed(); + + return HOLD_CURSORS_OVER_COMMIT; + } + + /** {@inheritDoc} */ + @Override public Savepoint setSavepoint() throws SQLException { + ensureNotClosed(); + + throw new SQLFeatureNotSupportedException("Transactions are not supported."); + } + + /** {@inheritDoc} */ + @Override public Savepoint setSavepoint(String name) throws SQLException { + ensureNotClosed(); + + throw new SQLFeatureNotSupportedException("Transactions are not supported."); + } + + /** {@inheritDoc} */ + @Override public void rollback(Savepoint savepoint) throws SQLException { + ensureNotClosed(); + + throw new SQLFeatureNotSupportedException("Transactions are not supported."); + } + + /** {@inheritDoc} */ + @Override public void releaseSavepoint(Savepoint savepoint) throws SQLException { + ensureNotClosed(); + + throw new SQLFeatureNotSupportedException("Transactions are not supported."); + } + + /** {@inheritDoc} */ + @Override public Statement createStatement(int resSetType, int resSetConcurrency, + int resSetHoldability) throws SQLException { + ensureNotClosed(); + + if (resSetType != TYPE_FORWARD_ONLY) + throw new SQLFeatureNotSupportedException("Invalid result set type (only forward is supported.)"); + + if (resSetConcurrency != CONCUR_READ_ONLY) + throw new SQLFeatureNotSupportedException("Invalid concurrency (updates are not supported)."); + + if (resSetHoldability != HOLD_CURSORS_OVER_COMMIT) + throw new SQLFeatureNotSupportedException("Invalid holdability (transactions are not supported)."); + + JdbcStatement stmt = new JdbcStatement(this); + + if (timeout > 0) + stmt.timeout(timeout); + + return stmt; + } + + /** {@inheritDoc} */ + @Override public PreparedStatement prepareStatement(String sql, int resSetType, int resSetConcurrency, + int resSetHoldability) throws SQLException { + ensureNotClosed(); + + if (resSetType != TYPE_FORWARD_ONLY) + throw new SQLFeatureNotSupportedException("Invalid result set type (only forward is supported.)"); + + if (resSetConcurrency != CONCUR_READ_ONLY) + throw new SQLFeatureNotSupportedException("Invalid concurrency (updates are not supported)."); + + if (resSetHoldability != HOLD_CURSORS_OVER_COMMIT) + throw new SQLFeatureNotSupportedException("Invalid holdability (transactions are not supported)."); + + JdbcPreparedStatement stmt = new JdbcPreparedStatement(this, sql); + + if (timeout > 0) + stmt.timeout(timeout); + + return stmt; + } + + /** {@inheritDoc} */ + @Override public CallableStatement prepareCall(String sql, int resSetType, int resSetConcurrency, + int resSetHoldability) throws SQLException { + ensureNotClosed(); + + throw new SQLFeatureNotSupportedException("Callable functions are not supported."); + } + + /** {@inheritDoc} */ + @Override public PreparedStatement prepareStatement(String sql, int autoGeneratedKeys) throws SQLException { + ensureNotClosed(); + + throw new SQLFeatureNotSupportedException("Updates are not supported."); + } + + /** {@inheritDoc} */ + @Override public PreparedStatement prepareStatement(String sql, int[] colIndexes) throws SQLException { + ensureNotClosed(); + + throw new SQLFeatureNotSupportedException("Updates are not supported."); + } + + /** {@inheritDoc} */ + @Override public PreparedStatement prepareStatement(String sql, String[] colNames) throws SQLException { + ensureNotClosed(); + + throw new SQLFeatureNotSupportedException("Updates are not supported."); + } + + /** {@inheritDoc} */ + @Override public Clob createClob() throws SQLException { + ensureNotClosed(); + + throw new SQLFeatureNotSupportedException("SQL-specific types are not supported."); + } + + /** {@inheritDoc} */ + @Override public Blob createBlob() throws SQLException { + ensureNotClosed(); + + throw new SQLFeatureNotSupportedException("SQL-specific types are not supported."); + } + + /** {@inheritDoc} */ + @Override public NClob createNClob() throws SQLException { + ensureNotClosed(); + + throw new SQLFeatureNotSupportedException("SQL-specific types are not supported."); + } + + /** {@inheritDoc} */ + @Override public SQLXML createSQLXML() throws SQLException { + ensureNotClosed(); + + throw new SQLFeatureNotSupportedException("SQL-specific types are not supported."); + } + + /** {@inheritDoc} */ + @Override public boolean isValid(int timeout) throws SQLException { + ensureNotClosed(); + + if (timeout < 0) + throw new SQLException("Invalid timeout: " + timeout); + + try { + return client.compute().<Boolean>executeAsync(VALID_TASK_NAME, cacheName).get(timeout, SECONDS); + } + catch (GridClientDisconnectedException | GridClientFutureTimeoutException e) { + throw new SQLException("Failed to establish connection.", e); + } + catch (GridClientException ignored) { + return false; + } + } + + /** {@inheritDoc} */ + @Override public void setClientInfo(String name, String val) throws SQLClientInfoException { + throw new UnsupportedOperationException("Client info is not supported."); + } + + /** {@inheritDoc} */ + @Override public void setClientInfo(Properties props) throws SQLClientInfoException { + throw new UnsupportedOperationException("Client info is not supported."); + } + + /** {@inheritDoc} */ + @Override public String getClientInfo(String name) throws SQLException { + ensureNotClosed(); + + return null; + } + + /** {@inheritDoc} */ + @Override public Properties getClientInfo() throws SQLException { + ensureNotClosed(); + + return new Properties(); + } + + /** {@inheritDoc} */ + @Override public Array createArrayOf(String typeName, Object[] elements) throws SQLException { + ensureNotClosed(); + + throw new SQLFeatureNotSupportedException("SQL-specific types are not supported."); + } + + /** {@inheritDoc} */ + @Override public Struct createStruct(String typeName, Object[] attrs) throws SQLException { + ensureNotClosed(); + + throw new SQLFeatureNotSupportedException("SQL-specific types are not supported."); + } + + /** {@inheritDoc} */ + @Override public <T> T unwrap(Class<T> iface) throws SQLException { + if (!isWrapperFor(iface)) + throw new SQLException("Connection is not a wrapper for " + iface.getName()); + + return (T)this; + } + + /** {@inheritDoc} */ + @Override public boolean isWrapperFor(Class<?> iface) throws SQLException { + return iface != null && iface == Connection.class; + } + + /** {@inheritDoc} */ + @Override public void setSchema(String schema) throws SQLException { + cacheName = schema; + } + + /** {@inheritDoc} */ + @Override public String getSchema() throws SQLException { + return cacheName; + } + + /** {@inheritDoc} */ + @Override public void abort(Executor executor) throws SQLException { + close(); + } + + /** {@inheritDoc} */ + @Override public void setNetworkTimeout(Executor executor, int ms) throws SQLException { + if (ms < 0) + throw new IllegalArgumentException("Timeout is below zero: " + ms); + + timeout = ms; + } + + /** {@inheritDoc} */ + @Override public int getNetworkTimeout() throws SQLException { + return timeout; + } + + /** + * @return GridGain client. + */ + GridClient client() { + return client; + } + + /** + * @return Cache name. + */ + String cacheName() { + return cacheName; + } + + /** + * @return URL. + */ + String url() { + return url; + } + + /** + * @return Node ID. + */ + UUID nodeId() { + return nodeId; + } + + /** + * Ensures that connection is not closed. + * + * @throws SQLException If connection is closed. + */ + private void ensureNotClosed() throws SQLException { + if (closed) + throw new SQLException("Connection is closed."); + } + + /** + * @return Internal statement. + * @throws SQLException In case of error. + */ + JdbcStatement createStatement0() throws SQLException { + return (JdbcStatement)createStatement(); + } +} http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/17d816fe/modules/core/src/main/java/org/apache/ignite/internal/jdbc/JdbcConnectionInfo.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/jdbc/JdbcConnectionInfo.java b/modules/core/src/main/java/org/apache/ignite/internal/jdbc/JdbcConnectionInfo.java new file mode 100644 index 0000000..33d82ec --- /dev/null +++ b/modules/core/src/main/java/org/apache/ignite/internal/jdbc/JdbcConnectionInfo.java @@ -0,0 +1,91 @@ +/* + * 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.ignite.internal.jdbc; + +/** + * Connection properties. + */ +public class JdbcConnectionInfo { + /** URL. */ + private final String url; + + /** Hostname. */ + private String hostname; + + /** Port number. */ + private int port; + + /** Cache name. */ + private String cacheName; + + /** + * @param url URL. + */ + JdbcConnectionInfo(String url) { + this.url = url; + } + + /** + * @return URL. + */ + public String url() { + return url; + } + + /** + * @return Hostname. + */ + public String hostname() { + return hostname; + } + + /** + * @param hostname Hostname. + */ + public void hostname(String hostname) { + this.hostname = hostname; + } + + /** + * @return Port number. + */ + public int port() { + return port; + } + + /** + * @param port Port number. + */ + public void port(int port) { + this.port = port; + } + + /** + * @return Cache name. + */ + public String cacheName() { + return cacheName; + } + + /** + * @param cacheName Cache name. + */ + public void cacheName(String cacheName) { + this.cacheName = cacheName; + } +}