This is an automated email from the ASF dual-hosted git repository.

akuznetsov pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/ignite.git


The following commit(s) were added to refs/heads/master by this push:
     new 5aa1481  IGNITE-10214 Web Console: Improved support for JDBC drivers 
for project generation.
5aa1481 is described below

commit 5aa1481aa645b0d42992b49b6e22cd440575e160
Author: Vasiliy Sisko <vsi...@gridgain.com>
AuthorDate: Fri Mar 29 14:03:58 2019 +0700

    IGNITE-10214 Web Console: Improved support for JDBC drivers for project 
generation.
---
 modules/web-console/backend/app/schemas.js         |  1 +
 .../components/modal-import-models/component.js    | 14 +++-
 .../components/cache-edit-form/controller.ts       | 10 +++
 .../components/cache-edit-form/templates/store.pug | 18 +++--
 .../templates/checkpoint/jdbc.pug                  |  4 +-
 .../templates/general/discovery/jdbc.pug           |  4 +-
 .../generator/configuration.module.js              |  4 +-
 .../generator/ArtifactVersionChecker.service.js    | 86 ++++++++++++++++++++++
 .../generator/generator/ConfigurationGenerator.js  | 72 +++++++++++++++---
 .../generator/generator/Maven.service.js           | 38 ++++++----
 .../frontend/app/configuration/index.ts            |  9 ++-
 .../frontend/app/configuration/mixins.pug          |  3 +-
 .../frontend/app/configuration/services/Caches.ts  | 13 +++-
 .../app/configuration/services/Clusters.ts         | 16 ++--
 .../frontend/app/data/pom-dependencies.json        | 10 +--
 .../app/primitives/form-field/dropdown.pug         |  4 +-
 .../console/agent/handlers/DatabaseListener.java   | 28 ++++++-
 17 files changed, 274 insertions(+), 60 deletions(-)

diff --git a/modules/web-console/backend/app/schemas.js 
b/modules/web-console/backend/app/schemas.js
index 10c294f..29ec9b4 100644
--- a/modules/web-console/backend/app/schemas.js
+++ b/modules/web-console/backend/app/schemas.js
@@ -226,6 +226,7 @@ module.exports.factory = function(mongoose) {
                     type: String,
                     enum: ['Generic', 'Oracle', 'DB2', 'SQLServer', 'MySQL', 
'PostgreSQL', 'H2']
                 },
+                implementationVersion: String,
                 batchSize: Number,
                 maximumPoolSize: Number,
                 maximumWriteAttempts: Number,
diff --git 
a/modules/web-console/frontend/app/configuration/components/modal-import-models/component.js
 
b/modules/web-console/frontend/app/configuration/components/modal-import-models/component.js
index b1439e5..9fe23ec 100644
--- 
a/modules/web-console/frontend/app/configuration/components/modal-import-models/component.js
+++ 
b/modules/web-console/frontend/app/configuration/components/modal-import-models/component.js
@@ -375,6 +375,12 @@ export class ModalImportModels {
             },
             {
                 db: 'MySQL',
+                jdbcDriverClass: 'com.mysql.cj.jdbc.Driver',
+                jdbcUrl: 'jdbc:mysql://[host]:[port]/[database]',
+                user: 'root'
+            },
+            {
+                db: 'MySQL',
                 jdbcDriverClass: 'org.mariadb.jdbc.Driver',
                 jdbcUrl: 'jdbc:mariadb://[host]:[port]/[database]',
                 user: 'root'
@@ -452,6 +458,7 @@ export class ModalImportModels {
 
             result.jdbcDriverJar = selectedJdbcJar.jdbcDriverJar;
             result.jdbcDriverClass = selectedJdbcJar.jdbcDriverClass;
+            result.jdbcDriverImplementationVersion = 
selectedJdbcJar.jdbcDriverImplementationVersion;
 
             return result;
         }
@@ -818,7 +825,8 @@ export class ModalImportModels {
                             kind: 'CacheJdbcPojoStoreFactory',
                             CacheJdbcPojoStoreFactory: {
                                 dataSourceBean: 'ds' + dialect + '_' + catalog,
-                                dialect
+                                dialect,
+                                implementationVersion: 
$scope.selectedPreset.jdbcDriverImplementationVersion
                             },
                             CacheJdbcBlobStoreFactory: { connectVia: 
'DataSource' }
                         };
@@ -1040,7 +1048,8 @@ export class ModalImportModels {
                                         label: drv.jdbcDriverJar,
                                         value: {
                                             jdbcDriverJar: drv.jdbcDriverJar,
-                                            jdbcDriverClass: drv.jdbcDriverCls
+                                            jdbcDriverClass: drv.jdbcDriverCls,
+                                            jdbcDriverImplementationVersion: 
drv.jdbcDriverImplVersion
                                         }
                                     });
                                 });
@@ -1093,6 +1102,7 @@ export class ModalImportModels {
                 selectedPreset.db = foundPreset.db;
                 selectedPreset.jdbcDriverJar = foundPreset.jdbcDriverJar;
                 selectedPreset.jdbcDriverClass = foundPreset.jdbcDriverClass;
+                selectedPreset.jdbcDriverImplementationVersion = 
foundPreset.jdbcDriverImplementationVersion;
                 selectedPreset.jdbcUrl = foundPreset.jdbcUrl;
                 selectedPreset.user = foundPreset.user;
             }
diff --git 
a/modules/web-console/frontend/app/configuration/components/page-configure-advanced/components/cache-edit-form/controller.ts
 
b/modules/web-console/frontend/app/configuration/components/page-configure-advanced/components/cache-edit-form/controller.ts
index 5980613..7facc31 100644
--- 
a/modules/web-console/frontend/app/configuration/components/page-configure-advanced/components/cache-edit-form/controller.ts
+++ 
b/modules/web-console/frontend/app/configuration/components/page-configure-advanced/components/cache-edit-form/controller.ts
@@ -85,9 +85,11 @@ export default class CacheEditFormController {
             {text: 'Save and Download', icon: 'download', click: () => 
this.save(true)}
         ];
     }
+
     $onDestroy() {
         this.subscription.unsubscribe();
     }
+
     $onChanges(changes) {
         if (
             'cache' in changes && get(this.clonedCache, '_id') !== 
get(this.cache, '_id')
@@ -105,17 +107,25 @@ export default class CacheEditFormController {
             this.igfsIDs = (changes.igfss.currentValue || []).map((i) => 
i._id);
         }
     }
+
     getValuesToCompare() {
         return [this.cache, this.clonedCache].map(this.Caches.normalize);
     }
+
     save(download) {
         if (this.$scope.ui.inputForm.$invalid)
             return 
this.IgniteFormUtils.triggerValidation(this.$scope.ui.inputForm, this.$scope);
         this.onSave({$event: {cache: cloneDeep(this.clonedCache), download}});
     }
+
     reset = (forReal) => forReal ? this.clonedCache = cloneDeep(this.cache) : 
void 0;
+
     confirmAndReset() {
         return this.IgniteConfirm.confirm('Are you sure you want to undo all 
changes for current cache?')
         .then(this.reset);
     }
+
+    clearImplementationVersion(storeFactory) {
+        delete storeFactory.implementationVersion;
+    }
 }
diff --git 
a/modules/web-console/frontend/app/configuration/components/page-configure-advanced/components/cache-edit-form/templates/store.pug
 
b/modules/web-console/frontend/app/configuration/components/page-configure-advanced/components/cache-edit-form/templates/store.pug
index e9a14e4..96ce5a4 100644
--- 
a/modules/web-console/frontend/app/configuration/components/page-configure-advanced/components/cache-edit-form/templates/store.pug
+++ 
b/modules/web-console/frontend/app/configuration/components/page-configure-advanced/components/cache-edit-form/templates/store.pug
@@ -59,7 +59,7 @@ panel-collapsible(ng-form=form 
on-open=`ui.loadPanel('${form}')`)
                     -var pojoStoreFactory = 
`${storeFactory}.CacheJdbcPojoStoreFactory`
                     -var required = `${storeFactoryKind} === 
'CacheJdbcPojoStoreFactory'`
 
-                    .pc-form-grid-col-60
+                    .pc-form-grid-col-30
                         +form-field__text({
                             label: 'Data source bean name:',
                             model: `${pojoStoreFactory}.dataSourceBean`,
@@ -74,7 +74,7 @@ panel-collapsible(ng-form=form 
on-open=`ui.loadPanel('${form}')`)
                             +form-field__error({ error: 'required', message: 
'Data source bean name is required' })
                             +form-field__error({ error: 
'isValidJavaIdentifier', message: 'Data source bean name is not a valid Java 
identifier' })
                             +form-field__error({ error: 'notJavaReservedWord', 
message: 'Data source bean name should not be a Java reserved word' })
-                    .pc-form-grid-col-60
+                    .pc-form-grid-col-30
                         +form-field__dialect({
                             label: 'Dialect:',
                             model: `${pojoStoreFactory}.dialect`,
@@ -82,8 +82,12 @@ panel-collapsible(ng-form=form 
on-open=`ui.loadPanel('${form}')`)
                             required,
                             tip: 'Dialect of SQL implemented by a particular 
RDBMS:',
                             genericDialectName: 'Generic JDBC dialect',
-                            placeholder: 'Choose JDBC dialect'
+                            placeholder: 'Choose JDBC dialect',
+                            
change:`$ctrl.clearImplementationVersion(${pojoStoreFactory})`
                         })
+                    
.pc-form-grid-col-60(ng-if=`$ctrl.Caches.requiresProprietaryDrivers(${pojoStoreFactory})`)
+                        a.link-success(ng-href=`{{ 
$ctrl.Caches.JDBCDriverURL(${pojoStoreFactory}) }}` target='_blank')
+                            | Download JDBC drivers?
                     .pc-form-grid-col-30
                         +form-field__number({
                             label:'Batch size:',
@@ -193,7 +197,7 @@ panel-collapsible(ng-form=form 
on-open=`ui.loadPanel('${form}')`)
 
                     -var required = `${storeFactoryKind} === 
'CacheJdbcBlobStoreFactory' && ${blobStoreFactoryVia} !== 'URL'`
 
-                    .pc-form-grid-col-60(ng-if-start=`${blobStoreFactoryVia} 
!== 'URL'`)
+                    .pc-form-grid-col-30(ng-if-start=`${blobStoreFactoryVia} 
!== 'URL'`)
                         +form-field__text({
                             label: 'Data source bean name:',
                             model: `${blobStoreFactory}.dataSourceBean`,
@@ -208,7 +212,7 @@ panel-collapsible(ng-form=form 
on-open=`ui.loadPanel('${form}')`)
                             +form-field__error({ error: 'required', message: 
'Data source bean name is required' })
                             +form-field__error({ error: 
'isValidJavaIdentifier', message: 'Data source bean name is not a valid Java 
identifier' })
                             +form-field__error({ error: 'notJavaReservedWord', 
message: 'Data source bean name should not be a Java reserved word' })
-                    .pc-form-grid-col-60(ng-if-end)
+                    .pc-form-grid-col-30(ng-if-end)
                         +form-field__dialect({
                             label: 'Database:',
                             model: `${blobStoreFactory}.dialect`,
@@ -218,7 +222,9 @@ panel-collapsible(ng-form=form 
on-open=`ui.loadPanel('${form}')`)
                             genericDialectName: 'Generic database',
                             placeholder: 'Choose database'
                         })
-
+                    
.pc-form-grid-col-60(ng-if=`$ctrl.Caches.requiresProprietaryDrivers(${blobStoreFactory})`)
+                        a.link-success(ng-href=`{{ 
$ctrl.Caches.JDBCDriverURL(${blobStoreFactory}) }}` target='_blank')
+                            | Download JDBC drivers?
                     .pc-form-grid-col-60
                         +form-field__checkbox({
                             label: 'Init schema',
diff --git 
a/modules/web-console/frontend/app/configuration/components/page-configure-advanced/components/cluster-edit-form/templates/checkpoint/jdbc.pug
 
b/modules/web-console/frontend/app/configuration/components/page-configure-advanced/components/cluster-edit-form/templates/checkpoint/jdbc.pug
index be4afc4..ed5f148 100644
--- 
a/modules/web-console/frontend/app/configuration/components/page-configure-advanced/components/cluster-edit-form/templates/checkpoint/jdbc.pug
+++ 
b/modules/web-console/frontend/app/configuration/components/page-configure-advanced/components/cluster-edit-form/templates/checkpoint/jdbc.pug
@@ -37,7 +37,9 @@ include /app/helpers/jade/mixins
         genericDialectName: 'Generic JDBC dialect',
         placeholder: 'Choose JDBC dialect'
     })
-
+.pc-form-grid-col-60(ng-if='$ctrl.Clusters.requiresProprietaryDrivers($checkpointSPI.JDBC)')
+    a.link-success(ng-href='{{ 
$ctrl.Clusters.JDBCDriverURL($checkpointSPI.JDBC) }}' target='_blank')
+        | Download JDBC drivers?
 .pc-form-grid-col-60
     +form-field__java-class({
         label: 'Listener:',
diff --git 
a/modules/web-console/frontend/app/configuration/components/page-configure-advanced/components/cluster-edit-form/templates/general/discovery/jdbc.pug
 
b/modules/web-console/frontend/app/configuration/components/page-configure-advanced/components/cluster-edit-form/templates/general/discovery/jdbc.pug
index eb9f0aa..a285408 100644
--- 
a/modules/web-console/frontend/app/configuration/components/page-configure-advanced/components/cluster-edit-form/templates/general/discovery/jdbc.pug
+++ 
b/modules/web-console/frontend/app/configuration/components/page-configure-advanced/components/cluster-edit-form/templates/general/discovery/jdbc.pug
@@ -47,6 +47,6 @@ mixin discovery-jdbc(modelAt = '$ctrl.clonedCluster')
                 name: '"initSchema"',
                 tip: 'Flag indicating whether DB schema should be initialized 
by Ignite or was explicitly created by user'
             })
-        
.pc-form-grid-col-30(ng-if=`$ctrl.Clusters.requiresProprietaryDrivers(${modelAt})`)
-            a.link-success(ng-href=`{{ 
$ctrl.Clusters.JDBCDriverURL(${modelAt}) }}` target='_blank')
+        
.pc-form-grid-col-30(ng-if=`$ctrl.Clusters.requiresProprietaryDrivers(${modelAt}.discovery.Jdbc)`)
+            a.link-success(ng-href=`{{ 
$ctrl.Clusters.JDBCDriverURL(${modelAt}.discovery.Jdbc) }}` target='_blank')
                 | Download JDBC drivers?
\ No newline at end of file
diff --git 
a/modules/web-console/frontend/app/configuration/generator/configuration.module.js
 
b/modules/web-console/frontend/app/configuration/generator/configuration.module.js
index cc04095..fbbfc01 100644
--- 
a/modules/web-console/frontend/app/configuration/generator/configuration.module.js
+++ 
b/modules/web-console/frontend/app/configuration/generator/configuration.module.js
@@ -34,6 +34,7 @@ import IgniteMavenGenerator from './generator/Maven.service';
 import IgniteGeneratorProperties from './generator/Properties.service';
 import IgniteReadmeGenerator from './generator/Readme.service';
 import IgniteCustomGenerator from './generator/Custom.service';
+import IgniteArtifactVersionUtils from 
'./generator/ArtifactVersionChecker.service';
 
 
 // Ignite events groups.
@@ -55,4 +56,5 @@ export default angular
     .service('IgniteReadmeGenerator', IgniteReadmeGenerator)
     .service('IgniteDockerGenerator', IgniteDockerGenerator)
     .service('IgniteMavenGenerator', IgniteMavenGenerator)
-    .service('IgniteCustomGenerator', IgniteCustomGenerator);
+    .service('IgniteCustomGenerator', IgniteCustomGenerator)
+    .service('IgniteArtifactVersionUtils', IgniteArtifactVersionUtils);
diff --git 
a/modules/web-console/frontend/app/configuration/generator/generator/ArtifactVersionChecker.service.js
 
b/modules/web-console/frontend/app/configuration/generator/generator/ArtifactVersionChecker.service.js
new file mode 100644
index 0000000..0aa8ff1
--- /dev/null
+++ 
b/modules/web-console/frontend/app/configuration/generator/generator/ArtifactVersionChecker.service.js
@@ -0,0 +1,86 @@
+/*
+ * 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.
+ */
+
+import _ from 'lodash';
+
+export default class ArtifactVersionChecker {
+    /**
+     * Compare two numbers.
+     *
+     * @param a {Number} First number to compare
+     * @param b {Number} Second number to compare.
+     * @return {Number} 1 when a is greater then b, -1 when b is greater then 
a, 0 when a and b is equal.
+     */
+    static _numberComparator(a, b) {
+        return a > b ? 1 : a < b ? -1 : 0;
+    }
+
+    /**
+     * Compare to version.
+     *
+     * @param {Object} a first compared version.
+     * @param {Object} b second compared version.
+     * @returns {Number} 1 if a > b, 0 if versions equals, -1 if a < b
+     */
+    static _compare(a, b) {
+        for (let i = 0; i < a.length && i < b.length; i++) {
+            const res = this._numberComparator(a[i], b[i]);
+
+            if (res !== 0)
+                return res;
+        }
+
+        return 0;
+    }
+
+    /**
+     * Tries to parse JDBC driver version.
+     *
+     * @param {String} ver - String representation of version.
+     * @returns {Number[]} - Array of version parts.
+     */
+    static _parse(ver) {
+        return _.map(ver.split(/[.-]/), (v) => {
+            return v.startsWith('jre') ? parseInt(v.substring(3), 10) : 
parseInt(v, 10);
+        });
+    }
+
+    /**
+     * Stay only latest versions of the same dependencies.
+     *
+     * @param deps Array of dependencies.
+     */
+    static latestVersions(deps) {
+        return _.map(_.values(_.groupBy(_.uniqWith(deps, _.isEqual), (dep) => 
dep.groupId + dep.artifactId)), (arr) => {
+            if (arr.length > 1) {
+                try {
+                    return _.reduce(arr, (resDep, dep) => {
+                        if (this._compare(this._parse(dep.version), 
this._parse(resDep.version)) > 0)
+                            return dep;
+
+                        return resDep;
+                    });
+                }
+                catch (err) {
+                    return _.last(_.sortBy(arr, 'version'));
+                }
+            }
+
+            return arr[0];
+        });
+    }
+}
diff --git 
a/modules/web-console/frontend/app/configuration/generator/generator/ConfigurationGenerator.js
 
b/modules/web-console/frontend/app/configuration/generator/generator/ConfigurationGenerator.js
index 358a453..973db07 100644
--- 
a/modules/web-console/frontend/app/configuration/generator/generator/ConfigurationGenerator.js
+++ 
b/modules/web-console/frontend/app/configuration/generator/generator/ConfigurationGenerator.js
@@ -23,6 +23,7 @@ import IgniteClusterDefaults from 
'./defaults/Cluster.service';
 import IgniteEventGroups from './defaults/Event-groups.service';
 import IgniteCacheDefaults from './defaults/Cache.service';
 import IgniteIGFSDefaults from './defaults/IGFS.service';
+import ArtifactVersionChecker from './ArtifactVersionChecker.service';
 
 import JavaTypes from '../../../services/JavaTypes.service';
 import VersionService from 'app/services/Version.service';
@@ -37,6 +38,9 @@ const igfsDflts = new IgniteIGFSDefaults();
 const javaTypes = new JavaTypes(clusterDflts, cacheDflts, igfsDflts);
 const versionService = new VersionService();
 
+// Pom dependency information.
+import POM_DEPENDENCIES from 'app/data/pom-dependencies.json';
+
 export default class IgniteConfigurationGenerator {
     static eventGrps = new IgniteEventGroups();
 
@@ -142,7 +146,7 @@ export default class IgniteConfigurationGenerator {
         return DFLT_DIALECTS[dialect] || 'Unknown database: ' + (dialect || 
'Choose JDBC dialect');
     }
 
-    static dataSourceBean(id, dialect) {
+    static dataSourceBean(id, dialect, available, storeDeps, 
implementationVersion) {
         let dsBean;
 
         switch (dialect) {
@@ -170,7 +174,13 @@ export default class IgniteConfigurationGenerator {
 
                 break;
             case 'MySQL':
-                dsBean = new 
Bean('com.mysql.jdbc.jdbc2.optional.MysqlDataSource', id, {})
+                const dep = storeDeps
+                    ? _.find(storeDeps, (d) => d.name === dialect)
+                    : 
_.first(ArtifactVersionChecker.latestVersions(this._getArtifact({dialect, 
implementationVersion}, available)));
+
+                const ver = parseInt(dep.version.split('.')[0], 10);
+
+                dsBean = new Bean(ver < 8 ? 
'com.mysql.jdbc.jdbc2.optional.MysqlDataSource' : 
'com.mysql.cj.jdbc.MysqlDataSource', id, {})
                     .property('URL', `${id}.jdbc.url`, 
'jdbc:mysql://[host]:[port]/[database]');
 
                 break;
@@ -278,7 +288,7 @@ export default class IgniteConfigurationGenerator {
                 if (ipFinder.includes('dataSourceBean', 'dialect')) {
                     const id = ipFinder.valueOf('dataSourceBean');
 
-                    ipFinder.dataSource(id, 'dataSource', 
this.dataSourceBean(id, ipFinder.valueOf('dialect')));
+                    ipFinder.dataSource(id, 'dataSource', 
this.dataSourceBean(id, ipFinder.valueOf('dialect'), available));
                 }
 
                 break;
@@ -414,8 +424,50 @@ export default class IgniteConfigurationGenerator {
         }, available);
     }
 
+    /**
+     * Get dependency artifact for specified datasource.
+     *
+     * @param source Datasource.
+     * @param available Function to check version availability.
+     * @return {Array<{{name: String, version: String}}>} Array of accordance 
datasource artifacts.
+     */
+    static _getArtifact(source, available) {
+        const deps = _.get(POM_DEPENDENCIES, source.dialect);
+
+        if (!deps)
+            return [];
+
+        const extractVersion = (version) => {
+            return _.isArray(version) ? _.find(version, (v) => 
available(v.range)).version : version;
+        };
+
+        return _.map(_.castArray(deps), ({version}) => {
+            return ({
+                name: source.dialect,
+                version: source.implementationVersion || 
extractVersion(version)
+            });
+        });
+    }
+
     static clusterCaches(cluster, caches, igfss, available, client, cfg = 
this.igniteConfigurationBean(cluster)) {
-        const ccfgs = _.map(caches, (cache) => this.cacheConfiguration(cache, 
available));
+        const usedDataSourceVersions = [];
+
+        if (cluster.discovery.kind === 'Jdbc')
+            
usedDataSourceVersions.push(...this._getArtifact(cluster.discovery.Jdbc, 
available));
+
+        _.forEach(cluster.checkpointSpi, (spi) => {
+            if (spi.kind === 'JDBC')
+                usedDataSourceVersions.push(...this._getArtifact(spi.JDBC, 
available));
+        });
+
+        _.forEach(caches, (cache) => {
+            if (_.get(cache, 'cacheStoreFactory.kind'))
+                
usedDataSourceVersions.push(...this._getArtifact(cache.cacheStoreFactory[cache.cacheStoreFactory.kind],
 available));
+        });
+
+        const useDeps = 
_.uniqWith(ArtifactVersionChecker.latestVersions(usedDataSourceVersions), 
_.isEqual);
+
+        const ccfgs = _.map(caches, (cache) => this.cacheConfiguration(cache, 
available, useDeps));
 
         if (!client) {
             _.forEach(igfss, (igfs) => {
@@ -751,7 +803,7 @@ export default class IgniteConfigurationGenerator {
                     const id = jdbcBean.valueOf('dataSourceBean');
                     const dialect = _.get(spi.JDBC, 'dialect');
 
-                    jdbcBean.dataSource(id, 'dataSource', 
this.dataSourceBean(id, dialect));
+                    jdbcBean.dataSource(id, 'dataSource', 
this.dataSourceBean(id, dialect, available));
 
                     if (!_.isEmpty(jdbcBean.valueOf('user'))) {
                         jdbcBean.stringProperty('user')
@@ -2159,7 +2211,7 @@ export default class IgniteConfigurationGenerator {
     }
 
     // Generate cache store group.
-    static cacheStore(cache, domains, available, ccfg = 
this.cacheConfigurationBean(cache)) {
+    static cacheStore(cache, domains, available, deps, ccfg = 
this.cacheConfigurationBean(cache)) {
         const kind = _.get(cache, 'cacheStoreFactory.kind');
 
         if (kind && cache.cacheStoreFactory[kind]) {
@@ -2174,7 +2226,7 @@ export default class IgniteConfigurationGenerator {
 
                     const jdbcId = bean.valueOf('dataSourceBean');
 
-                    bean.dataSource(jdbcId, 'dataSourceBean', 
this.dataSourceBean(jdbcId, storeFactory.dialect))
+                    bean.dataSource(jdbcId, 'dataSourceBean', 
this.dataSourceBean(jdbcId, storeFactory.dialect, available, deps, 
storeFactory.implementationVersion))
                         .beanProperty('dialect', new 
EmptyBean(this.dialectClsName(storeFactory.dialect)));
 
                     bean.intProperty('batchSize')
@@ -2219,7 +2271,7 @@ export default class IgniteConfigurationGenerator {
                     if (bean.valueOf('connectVia') === 'DataSource') {
                         const blobId = bean.valueOf('dataSourceBean');
 
-                        bean.dataSource(blobId, 'dataSourceBean', 
this.dataSourceBean(blobId, storeFactory.dialect));
+                        bean.dataSource(blobId, 'dataSourceBean', 
this.dataSourceBean(blobId, storeFactory.dialect, available, deps));
                     }
                     else {
                         ccfg.stringProperty('connectionUrl')
@@ -2405,12 +2457,12 @@ export default class IgniteConfigurationGenerator {
         ccfg.collectionProperty('qryEntities', 'queryEntities', qryEntities, 
'org.apache.ignite.cache.QueryEntity');
     }
 
-    static cacheConfiguration(cache, available, ccfg = 
this.cacheConfigurationBean(cache)) {
+    static cacheConfiguration(cache, available, deps = [], ccfg = 
this.cacheConfigurationBean(cache)) {
         this.cacheGeneral(cache, available, ccfg);
         this.cacheAffinity(cache, available, ccfg);
         this.cacheMemory(cache, available, ccfg);
         this.cacheQuery(cache, cache.domains, available, ccfg);
-        this.cacheStore(cache, cache.domains, available, ccfg);
+        this.cacheStore(cache, cache.domains, available, deps, ccfg);
 
         const igfs = _.get(cache, 'nodeFilter.IGFS.instance');
         this.cacheNodeFilter(cache, igfs ? [igfs] : [], ccfg);
diff --git 
a/modules/web-console/frontend/app/configuration/generator/generator/Maven.service.js
 
b/modules/web-console/frontend/app/configuration/generator/generator/Maven.service.js
index 449bc34..5442b79 100644
--- 
a/modules/web-console/frontend/app/configuration/generator/generator/Maven.service.js
+++ 
b/modules/web-console/frontend/app/configuration/generator/generator/Maven.service.js
@@ -15,14 +15,17 @@
  * limitations under the License.
  */
 
+import _ from 'lodash';
+
 import StringBuilder from './StringBuilder';
+import ArtifactVersionChecker from './ArtifactVersionChecker.service';
 import VersionService from 'app/services/Version.service';
 
-const versionService = new VersionService();
-
-// Java built-in class names.
+// Pom dependency information.
 import POM_DEPENDENCIES from 'app/data/pom-dependencies.json';
 
+const versionService = new VersionService();
+
 /**
  * Pom file generation entry point.
  */
@@ -38,22 +41,26 @@ export default class IgniteMavenGenerator {
         sb.append(`<${tag}>${val}</${tag}>`);
     }
 
-    addDependency(deps, groupId, artifactId, version, jar) {
-        deps.push({groupId, artifactId, version, jar});
+    addComment(sb, comment) {
+        sb.append(`<!-- ${comment} -->`);
     }
 
-    pickDependency(acc, key, dfltVer, igniteVer) {
+    addDependency(deps, groupId, artifactId, version, jar, link) {
+        deps.push({groupId, artifactId, version, jar, link});
+    }
+
+    _extractVersion(igniteVer, version) {
+        return _.isArray(version) ? _.find(version, (v) => 
versionService.since(igniteVer, v.range)).version : version;
+    }
+
+    pickDependency(acc, key, dfltVer, igniteVer, storedVer) {
         const deps = POM_DEPENDENCIES[key];
 
         if (_.isNil(deps))
             return;
 
-        const extractVersion = (version) => {
-            return _.isArray(version) ? _.find(version, (v) => 
versionService.since(igniteVer, v.range)).version : version;
-        };
-
-        _.forEach(_.castArray(deps), ({groupId, artifactId, version, jar}) => {
-            this.addDependency(acc, groupId || 'org.apache.ignite', 
artifactId, extractVersion(version) || dfltVer, jar);
+        _.forEach(_.castArray(deps), ({groupId, artifactId, version, jar, 
link}) => {
+            this.addDependency(acc, groupId || 'org.apache.ignite', 
artifactId, storedVer || this._extractVersion(igniteVer, version) || dfltVer, 
jar, link);
         });
     }
 
@@ -92,6 +99,9 @@ export default class IgniteMavenGenerator {
                 this.addProperty(sb, 'systemPath', 
'${project.basedir}/jdbc-drivers/' + dep.jar);
             }
 
+            if (dep.link)
+                this.addComment(sb, `You may download JDBC driver from: 
${dep.link}`);
+
             sb.endBlock('</dependency>');
         });
 
@@ -152,7 +162,7 @@ export default class IgniteMavenGenerator {
      */
     storeFactoryDependency(deps, storeFactory, igniteVer) {
         if (storeFactory.dialect && (!storeFactory.connectVia || 
storeFactory.connectVia === 'DataSource'))
-            this.pickDependency(deps, storeFactory.dialect, null, igniteVer);
+            this.pickDependency(deps, storeFactory.dialect, null, igniteVer, 
storeFactory.implementationVersion);
     }
 
     collectDependencies(cluster, targetVer) {
@@ -211,7 +221,7 @@ export default class IgniteMavenGenerator {
         if (cluster.logger && cluster.logger.kind)
             this.pickDependency(deps, cluster.logger.kind, igniteVer);
 
-        return _.uniqWith(deps.concat(...storeDeps), _.isEqual);
+        return 
_.uniqWith(deps.concat(ArtifactVersionChecker.latestVersions(storeDeps)), 
_.isEqual);
     }
 
     /**
diff --git a/modules/web-console/frontend/app/configuration/index.ts 
b/modules/web-console/frontend/app/configuration/index.ts
index 51ba059..c1fac18 100644
--- a/modules/web-console/frontend/app/configuration/index.ts
+++ b/modules/web-console/frontend/app/configuration/index.ts
@@ -85,7 +85,13 @@ import {
 import {errorState} from './transitionHooks/errorState';
 import {default as ActivitiesData} from '../core/activities/Activities.data';
 
+const JDBC_LINKS = {
+    Oracle: 
'https://www.oracle.com/technetwork/database/application-development/jdbc/downloads/index.html',
+    DB2: 'http://www-01.ibm.com/support/docview.wss?uid=swg21363866'
+};
+
 registerActivitiesHook.$inject = ['$uiRouter', 'IgniteActivitiesData'];
+
 function registerActivitiesHook($uiRouter: UIRouter, ActivitiesData: 
ActivitiesData) {
     $uiRouter.transitionService.onSuccess({to: 'base.configuration.**'}, 
(transition) => {
         ActivitiesData.post({group: 'configuration', action: 
transition.targetState().name()});
@@ -183,4 +189,5 @@ export default angular
     .directive('pcIsInCollection', isInCollection)
     .directive('fakeUiCanExit', fakeUiCanExit)
     .directive('formUiCanExitGuard', formUICanExitGuard)
-    .directive('igniteUiAceTabs', uiAceTabs);
+    .directive('igniteUiAceTabs', uiAceTabs)
+    .constant('JDBC_LINKS', JDBC_LINKS);
diff --git a/modules/web-console/frontend/app/configuration/mixins.pug 
b/modules/web-console/frontend/app/configuration/mixins.pug
index 92b4d39..f769c69 100644
--- a/modules/web-console/frontend/app/configuration/mixins.pug
+++ b/modules/web-console/frontend/app/configuration/mixins.pug
@@ -389,13 +389,14 @@ mixin list-pair-edit({ items, keyLbl, valLbl, itemName, 
itemsName })
                 label-multiple=itemsName
             )
 
-mixin form-field__dialect({ label, model, name, required, tip, 
genericDialectName, placeholder })
+mixin form-field__dialect({ label, model, name, required, tip, 
genericDialectName, placeholder, change })
     +form-field__dropdown({
         label,
         model,
         name,
         required,
         placeholder,
+        change,
         options: '[\
                 {value: "Generic", label: "' + genericDialectName + '"},\
                 {value: "Oracle", label: "Oracle"},\
diff --git a/modules/web-console/frontend/app/configuration/services/Caches.ts 
b/modules/web-console/frontend/app/configuration/services/Caches.ts
index a32281f..4a15c93 100644
--- a/modules/web-console/frontend/app/configuration/services/Caches.ts
+++ b/modules/web-console/frontend/app/configuration/services/Caches.ts
@@ -15,13 +15,14 @@
  * limitations under the License.
  */
 
+import get from 'lodash/get';
 import ObjectID from 'bson-objectid';
 import omit from 'lodash/fp/omit';
 import {CacheModes, AtomicityModes, ShortCache} from '../types';
 import {Menu} from 'app/types';
 
 export default class Caches {
-    static $inject = ['$http'];
+    static $inject = ['$http', 'JDBC_LINKS'];
 
     cacheModes: Menu<CacheModes> = [
         {value: 'LOCAL', label: 'LOCAL'},
@@ -35,7 +36,7 @@ export default class Caches {
         {value: 'TRANSACTIONAL_SNAPSHOT', label: 'TRANSACTIONAL_SNAPSHOT'}
     ];
 
-    constructor(private $http: ng.IHttpService) {}
+    constructor(private $http: ng.IHttpService, private JDBC_LINKS) {}
 
     saveCache(cache) {
         return this.$http.post('/api/v1/configuration/caches/save', cache);
@@ -223,4 +224,12 @@ export default class Caches {
     shouldShowCacheBackupsCount(cache: ShortCache) {
         return cache && cache.cacheMode === 'PARTITIONED';
     }
+
+    requiresProprietaryDrivers(storeFactory) {
+        return ['Oracle', 'DB2', 'SQLServer'].includes(get(storeFactory, 
'dialect'));
+    }
+
+    JDBCDriverURL(storeFactory) {
+        return this.JDBC_LINKS[get(storeFactory, 'dialect')];
+    }
 }
diff --git 
a/modules/web-console/frontend/app/configuration/services/Clusters.ts 
b/modules/web-console/frontend/app/configuration/services/Clusters.ts
index 63ad5a8..b03a9e0 100644
--- a/modules/web-console/frontend/app/configuration/services/Clusters.ts
+++ b/modules/web-console/frontend/app/configuration/services/Clusters.ts
@@ -28,7 +28,7 @@ const uniqueNameValidator = (defaultName = '') => (a, items = 
[]) => {
 };
 
 export default class Clusters {
-    static $inject = ['$http'];
+    static $inject = ['$http', 'JDBC_LINKS'];
 
     discoveries: Menu<DiscoveryKinds> = [
         {value: 'Vm', label: 'Static IPs'},
@@ -76,7 +76,7 @@ export default class Clusters {
     /**
      * Cluster-related configuration stuff
      */
-    constructor(private $http: ng.IHttpService) {}
+    constructor(private $http: ng.IHttpService, private JDBC_LINKS) {}
 
     getConfiguration(clusterID: string) {
         return this.$http.get(`/api/v1/configuration/${clusterID}`);
@@ -224,16 +224,12 @@ export default class Clusters {
         };
     }
 
-    requiresProprietaryDrivers(cluster) {
-        return get(cluster, 'discovery.kind') === 'Jdbc' && ['Oracle', 'DB2', 
'SQLServer'].includes(get(cluster, 'discovery.Jdbc.dialect'));
+    requiresProprietaryDrivers(dataSrc) {
+        return ['Oracle', 'DB2', 'SQLServer'].includes(get(dataSrc, 
'dialect'));
     }
 
-    JDBCDriverURL(cluster) {
-        return ({
-            Oracle: 
'http://www.oracle.com/technetwork/database/features/jdbc/default-2280470.html',
-            DB2: 'http://www-01.ibm.com/support/docview.wss?uid=swg21363866',
-            SQLServer: 
'https://www.microsoft.com/en-us/download/details.aspx?id=11774'
-        })[get(cluster, 'discovery.Jdbc.dialect')];
+    JDBCDriverURL(dataSrc) {
+        return this.JDBC_LINKS[get(dataSrc, 'dialect')];
     }
 
     dataRegion = {
diff --git a/modules/web-console/frontend/app/data/pom-dependencies.json 
b/modules/web-console/frontend/app/data/pom-dependencies.json
index d13bf14..428455f 100644
--- a/modules/web-console/frontend/app/data/pom-dependencies.json
+++ b/modules/web-console/frontend/app/data/pom-dependencies.json
@@ -15,14 +15,14 @@
         {"groupId": "com.mchange", "artifactId": "c3p0", "version": "0.9.5.2"},
         {"groupId": "com.mchange", "artifactId": "mchange-commons-java", 
"version": "0.2.11"}
     ],
-    "MySQL": {"groupId": "mysql", "artifactId": "mysql-connector-java", 
"version": "5.1.40"},
-    "PostgreSQL": {"groupId": "org.postgresql", "artifactId": "postgresql", 
"version": "9.4.1212.jre7"},
+    "MySQL": {"groupId": "mysql", "artifactId": "mysql-connector-java", 
"version": "8.0.15"},
+    "PostgreSQL": {"groupId": "org.postgresql", "artifactId": "postgresql", 
"version": "42.2.5"},
     "H2": {"groupId": "com.h2database", "artifactId": "h2", "version": [
         {"range": ["1.0.0", "2.0.0"], "version": "1.4.191"},
         {"range": ["2.0.0", "2.7.0"], "version": "1.4.195"},
         {"range": "2.7.0", "version": "1.4.197"}
     ]},
-    "Oracle": {"groupId": "com.oracle.jdbc", "artifactId": "ojdbc7", 
"version": "12.1.0.2", "jar": "ojdbc7.jar"},
-    "DB2": {"groupId": "ibm", "artifactId": "jdbc", "version": "4.21.29", 
"jar": "db2jcc4.jar"},
-    "SQLServer": {"groupId": "microsoft", "artifactId": "jdbc", "version": 
"4.2", "jar": "sqljdbc41.jar"}
+    "Oracle": {"groupId": "com.oracle.jdbc", "artifactId": "ojdbc8", 
"version": "18.3.0.0.0", "jar": "ojdbc8.jar", "link": 
"https://www.oracle.com/technetwork/database/application-development/jdbc/downloads/index.html"},
+    "DB2": {"groupId": "ibm", "artifactId": "jdbc", "version": "4.25.13", 
"jar": "db2jcc4.jar", "link": 
"http://www-01.ibm.com/support/docview.wss?uid=swg21363866"},
+    "SQLServer": {"groupId": "com.microsoft.sqlserver", "artifactId": 
"mssql-jdbc", "version": "7.2.1.jre8"}
 }
diff --git 
a/modules/web-console/frontend/app/primitives/form-field/dropdown.pug 
b/modules/web-console/frontend/app/primitives/form-field/dropdown.pug
index b13a177..73cced5 100644
--- a/modules/web-console/frontend/app/primitives/form-field/dropdown.pug
+++ b/modules/web-console/frontend/app/primitives/form-field/dropdown.pug
@@ -14,7 +14,7 @@
     See the License for the specific language governing permissions and
     limitations under the License.
 
-mixin form-field__dropdown({ label, model, name, disabled, required, multiple, 
placeholder, placeholderEmpty, options, optionLabel = 'label', tip, tipOpts })
+mixin form-field__dropdown({ label, model, name, disabled, required, multiple, 
placeholder, placeholderEmpty, options, optionLabel = 'label', tip, tipOpts, 
change })
     -var errLbl = label ? label.substring(0, label.length - 1) : 'Field';
 
     mixin __form-field__input()
@@ -31,6 +31,8 @@ mixin form-field__dropdown({ label, model, name, disabled, 
required, multiple, p
             ng-ref='$input'
             ng-ref-read='ngModel'
 
+            ng-change=change && `${change}`
+
             bs-select
             bs-options=`item.value as item.${optionLabel} for item in 
${options}`
 
diff --git 
a/modules/web-console/web-agent/src/main/java/org/apache/ignite/console/agent/handlers/DatabaseListener.java
 
b/modules/web-console/web-agent/src/main/java/org/apache/ignite/console/agent/handlers/DatabaseListener.java
index b6bd623..fde38bf 100644
--- 
a/modules/web-console/web-agent/src/main/java/org/apache/ignite/console/agent/handlers/DatabaseListener.java
+++ 
b/modules/web-console/web-agent/src/main/java/org/apache/ignite/console/agent/handlers/DatabaseListener.java
@@ -32,6 +32,8 @@ import java.util.Collections;
 import java.util.List;
 import java.util.Map;
 import java.util.Properties;
+import java.util.jar.JarFile;
+import java.util.jar.Manifest;
 import org.apache.ignite.console.agent.AgentConfiguration;
 import org.apache.ignite.console.agent.db.DbMetadataReader;
 import org.apache.ignite.console.agent.db.DbSchema;
@@ -50,6 +52,12 @@ public class DatabaseListener {
     private static final Logger log = 
Logger.getLogger(DatabaseListener.class.getName());
 
     /** */
+    private static final String IMPLEMENTATION_VERSION = 
"Implementation-Version";
+
+    /** */
+    private static final String BUNDLE_VERSION = "Bundle-Version";
+
+    /** */
     private final File driversFolder;
 
     /** */
@@ -156,17 +164,26 @@ public class DatabaseListener {
                     URL url = new URL("jar", null,
                         "file:" + (win ? "/" : "") + file.getPath() + 
"!/META-INF/services/java.sql.Driver");
 
-                    try (BufferedReader reader = new BufferedReader(new 
InputStreamReader(url.openStream(), UTF_8))) {
+                    try (
+                        BufferedReader reader = new BufferedReader(new 
InputStreamReader(url.openStream(), UTF_8));
+                        JarFile jar = new JarFile(file.getPath())
+                    ) {
+                        Manifest m = jar.getManifest();
+                        Object ver = 
m.getMainAttributes().getValue(IMPLEMENTATION_VERSION);
+
+                        if (ver == null)
+                            ver = 
m.getMainAttributes().getValue(BUNDLE_VERSION);
+
                         String jdbcDriverCls = reader.readLine();
 
-                        res.add(new JdbcDriver(file.getName(), jdbcDriverCls));
+                        res.add(new JdbcDriver(file.getName(), jdbcDriverCls, 
ver != null ? ver.toString() : null));
 
                         if (log.isDebugEnabled())
                             log.debug("Found: [driver=" + file + ", class=" + 
jdbcDriverCls + "]");
                     }
                 }
                 catch (IOException e) {
-                    res.add(new JdbcDriver(file.getName(), null));
+                    res.add(new JdbcDriver(file.getName(), null, null));
 
                     log.info("Found: [driver=" + file + "]");
                     log.info("Failed to detect driver class: " + 
e.getMessage());
@@ -319,14 +336,17 @@ public class DatabaseListener {
         public final String jdbcDriverJar;
         /** */
         public final String jdbcDriverCls;
+        /** */
+        public final String jdbcDriverImplVersion;
 
         /**
          * @param jdbcDriverJar File name of driver jar file.
          * @param jdbcDriverCls Optional JDBC driver class.
          */
-        public JdbcDriver(String jdbcDriverJar, String jdbcDriverCls) {
+        public JdbcDriver(String jdbcDriverJar, String jdbcDriverCls, String 
jdbcDriverImplVersion) {
             this.jdbcDriverJar = jdbcDriverJar;
             this.jdbcDriverCls = jdbcDriverCls;
+            this.jdbcDriverImplVersion = jdbcDriverImplVersion;
         }
     }
 }

Reply via email to