You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ignite.apache.org by vo...@apache.org on 2016/11/09 08:38:47 UTC

[33/50] [abbrv] ignite git commit: Web console beta-5.

http://git-wip-us.apache.org/repos/asf/ignite/blob/087f6405/modules/web-console/frontend/app/modules/configuration/generator/JavaTransformer.service.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/modules/configuration/generator/JavaTransformer.service.js b/modules/web-console/frontend/app/modules/configuration/generator/JavaTransformer.service.js
new file mode 100644
index 0000000..64d43d8
--- /dev/null
+++ b/modules/web-console/frontend/app/modules/configuration/generator/JavaTransformer.service.js
@@ -0,0 +1,1721 @@
+/*
+ * 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 AbstractTransformer from './AbstractTransformer';
+import StringBuilder from './StringBuilder';
+
+const STORE_FACTORY = ['org.apache.ignite.cache.store.jdbc.CacheJdbcPojoStoreFactory'];
+
+// Descriptors for generation of demo data.
+const PREDEFINED_QUERIES = [
+    {
+        schema: 'CARS',
+        type: 'PARKING',
+        create: [
+            'CREATE TABLE IF NOT EXISTS CARS.PARKING (',
+            'ID       INTEGER     NOT NULL PRIMARY KEY,',
+            'NAME     VARCHAR(50) NOT NULL,',
+            'CAPACITY INTEGER NOT NULL)'
+        ],
+        clearQuery: ['DELETE FROM CARS.PARKING'],
+        insertCntConsts: [{name: 'DEMO_MAX_PARKING_CNT', val: 5, comment: 'How many parkings to generate.'}],
+        insertPattern: ['INSERT INTO CARS.PARKING(ID, NAME, CAPACITY) VALUES(?, ?, ?)'],
+        fillInsertParameters(sb) {
+            sb.append('stmt.setInt(1, id);');
+            sb.append('stmt.setString(2, "Parking #" + (id + 1));');
+            sb.append('stmt.setInt(3, 10 + rnd.nextInt(20));');
+        },
+        selectQuery: ['SELECT * FROM PARKING WHERE CAPACITY >= 20']
+    },
+    {
+        schema: 'CARS',
+        type: 'CAR',
+        create: [
+            'CREATE TABLE IF NOT EXISTS CARS.CAR (',
+            'ID         INTEGER NOT NULL PRIMARY KEY,',
+            'PARKING_ID INTEGER NOT NULL,',
+            'NAME       VARCHAR(50) NOT NULL);'
+        ],
+        clearQuery: ['DELETE FROM CARS.CAR'],
+        rndRequired: true,
+        insertCntConsts: [
+            {name: 'DEMO_MAX_CAR_CNT', val: 10, comment: 'How many cars to generate.'},
+            {name: 'DEMO_MAX_PARKING_CNT', val: 5, comment: 'How many parkings to generate.'}
+        ],
+        insertPattern: ['INSERT INTO CARS.CAR(ID, PARKING_ID, NAME) VALUES(?, ?, ?)'],
+        fillInsertParameters(sb) {
+            sb.append('stmt.setInt(1, id);');
+            sb.append('stmt.setInt(2, rnd.nextInt(DEMO_MAX_PARKING_CNT));');
+            sb.append('stmt.setString(3, "Car #" + (id + 1));');
+        },
+        selectQuery: ['SELECT * FROM CAR WHERE PARKINGID = 2']
+    },
+    {
+        type: 'COUNTRY',
+        create: [
+            'CREATE TABLE IF NOT EXISTS COUNTRY (',
+            'ID         INTEGER NOT NULL PRIMARY KEY,',
+            'NAME       VARCHAR(50),',
+            'POPULATION INTEGER NOT NULL);'
+        ],
+        clearQuery: ['DELETE FROM COUNTRY'],
+        insertCntConsts: [{name: 'DEMO_MAX_COUNTRY_CNT', val: 5, comment: 'How many countries to generate.'}],
+        insertPattern: ['INSERT INTO COUNTRY(ID, NAME, POPULATION) VALUES(?, ?, ?)'],
+        fillInsertParameters(sb) {
+            sb.append('stmt.setInt(1, id);');
+            sb.append('stmt.setString(2, "Country #" + (id + 1));');
+            sb.append('stmt.setInt(3, 10000000 + rnd.nextInt(100000000));');
+        },
+        selectQuery: ['SELECT * FROM COUNTRY WHERE POPULATION BETWEEN 15000000 AND 25000000']
+    },
+    {
+        type: 'DEPARTMENT',
+        create: [
+            'CREATE TABLE IF NOT EXISTS DEPARTMENT (',
+            'ID         INTEGER NOT NULL PRIMARY KEY,',
+            'COUNTRY_ID INTEGER NOT NULL,',
+            'NAME       VARCHAR(50) NOT NULL);'
+        ],
+        clearQuery: ['DELETE FROM DEPARTMENT'],
+        rndRequired: true,
+        insertCntConsts: [
+            {name: 'DEMO_MAX_DEPARTMENT_CNT', val: 5, comment: 'How many departments to generate.'},
+            {name: 'DEMO_MAX_COUNTRY_CNT', val: 5, comment: 'How many countries to generate.'}
+        ],
+        insertPattern: ['INSERT INTO DEPARTMENT(ID, COUNTRY_ID, NAME) VALUES(?, ?, ?)'],
+        fillInsertParameters(sb) {
+            sb.append('stmt.setInt(1, id);');
+            sb.append('stmt.setInt(2, rnd.nextInt(DEMO_MAX_COUNTRY_CNT));');
+            sb.append('stmt.setString(3, "Department #" + (id + 1));');
+        },
+        selectQuery: ['SELECT * FROM DEPARTMENT']
+    },
+    {
+        type: 'EMPLOYEE',
+        create: [
+            'CREATE TABLE IF NOT EXISTS EMPLOYEE (',
+            'ID            INTEGER NOT NULL PRIMARY KEY,',
+            'DEPARTMENT_ID INTEGER NOT NULL,',
+            'MANAGER_ID    INTEGER,',
+            'FIRST_NAME    VARCHAR(50) NOT NULL,',
+            'LAST_NAME     VARCHAR(50) NOT NULL,',
+            'EMAIL         VARCHAR(50) NOT NULL,',
+            'PHONE_NUMBER  VARCHAR(50),',
+            'HIRE_DATE     DATE        NOT NULL,',
+            'JOB           VARCHAR(50) NOT NULL,',
+            'SALARY        DOUBLE);'
+        ],
+        clearQuery: ['DELETE FROM EMPLOYEE'],
+        rndRequired: true,
+        insertCntConsts: [
+            {name: 'DEMO_MAX_EMPLOYEE_CNT', val: 10, comment: 'How many employees to generate.'},
+            {name: 'DEMO_MAX_DEPARTMENT_CNT', val: 5, comment: 'How many departments to generate.'}
+        ],
+        customGeneration(sb, conVar, stmtVar) {
+            sb.append(`${stmtVar} = ${conVar}.prepareStatement("INSERT INTO EMPLOYEE(ID, DEPARTMENT_ID, MANAGER_ID, FIRST_NAME, LAST_NAME, EMAIL, PHONE_NUMBER, HIRE_DATE, JOB, SALARY) VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?)");`);
+
+            sb.emptyLine();
+
+            sb.startBlock('for (int id = 0; id < DEMO_MAX_EMPLOYEE_CNT; id ++) {');
+
+            sb.append('int depId = rnd.nextInt(DEMO_MAX_DEPARTMENT_CNT);');
+
+            sb.emptyLine();
+
+            sb.append('stmt.setInt(1, DEMO_MAX_DEPARTMENT_CNT + id);');
+            sb.append('stmt.setInt(2, depId);');
+            sb.append('stmt.setInt(3, depId);');
+            sb.append('stmt.setString(4, "First name manager #" + (id + 1));');
+            sb.append('stmt.setString(5, "Last name manager#" + (id + 1));');
+            sb.append('stmt.setString(6, "Email manager#" + (id + 1));');
+            sb.append('stmt.setString(7, "Phone number manager#" + (id + 1));');
+            sb.append('stmt.setString(8, "2014-01-01");');
+            sb.append('stmt.setString(9, "Job manager #" + (id + 1));');
+            sb.append('stmt.setDouble(10, 600.0 + rnd.nextInt(300));');
+
+            sb.emptyLine();
+
+            sb.append('stmt.executeUpdate();');
+
+            sb.endBlock('}');
+        },
+        selectQuery: ['SELECT * FROM EMPLOYEE WHERE SALARY > 700']
+    }
+];
+
+// Var name generator function.
+const beenNameSeed = () => {
+    let idx = '';
+    const names = [];
+
+    return (bean) => {
+        let name;
+
+        while (_.includes(names, name = `${bean.id}${idx ? '_' + idx : idx}`))
+            idx++;
+
+        names.push(name);
+
+        return name;
+    };
+};
+
+export default ['JavaTypes', 'igniteEventGroups', 'IgniteConfigurationGenerator', (JavaTypes, eventGroups, generator) => {
+    class JavaTransformer extends AbstractTransformer {
+        static generator = generator;
+
+        // Mapping for objects to method call.
+        static METHOD_MAPPING = {
+            'org.apache.ignite.configuration.CacheConfiguration': {
+                id: (ccfg) => JavaTypes.toJavaName('cache', ccfg.findProperty('name').value),
+                args: '',
+                generator: (sb, id, ccfg) => {
+                    const cacheName = ccfg.findProperty('name').value;
+                    const dataSources = JavaTransformer.collectDataSources(ccfg);
+
+                    const javadoc = [
+                        `Create configuration for cache "${cacheName}".`,
+                        '',
+                        '@return Configured cache.'
+                    ];
+
+                    if (dataSources.length)
+                        javadoc.push('@throws Exception if failed to create cache configuration.');
+
+                    JavaTransformer.commentBlock(sb, ...javadoc);
+                    sb.startBlock(`public static CacheConfiguration ${id}()${dataSources.length ? ' throws Exception' : ''} {`);
+
+                    JavaTransformer.constructBean(sb, ccfg, [], true);
+
+                    sb.emptyLine();
+                    sb.append(`return ${ccfg.id};`);
+
+                    sb.endBlock('}');
+
+                    return sb;
+                }
+            },
+            'org.apache.ignite.cache.store.jdbc.JdbcType': {
+                id: (type) => JavaTypes.toJavaName('jdbcType', JavaTypes.shortClassName(type.findProperty('valueType').value)),
+                args: 'ccfg.getName()',
+                generator: (sb, name, jdbcType) => {
+                    const javadoc = [
+                        `Create JDBC type for "${name}".`,
+                        '',
+                        '@param cacheName Cache name.',
+                        '@return Configured JDBC type.'
+                    ];
+
+                    JavaTransformer.commentBlock(sb, ...javadoc);
+                    sb.startBlock(`private static JdbcType ${name}(String cacheName) {`);
+
+                    const cacheName = jdbcType.findProperty('cacheName');
+
+                    cacheName.clsName = 'var';
+                    cacheName.value = 'cacheName';
+
+                    JavaTransformer.constructBean(sb, jdbcType);
+
+                    sb.emptyLine();
+                    sb.append(`return ${jdbcType.id};`);
+
+                    sb.endBlock('}');
+
+                    return sb;
+                }
+            }
+        };
+
+        // Append comment line.
+        static comment(sb, ...lines) {
+            _.forEach(lines, (line) => sb.append(`// ${line}`));
+        }
+
+        // Append comment block.
+        static commentBlock(sb, ...lines) {
+            if (lines.length === 1)
+                sb.append(`/** ${_.head(lines)} **/`);
+            else {
+                sb.append('/**');
+
+                _.forEach(lines, (line) => sb.append(` * ${line}`));
+
+                sb.append(' **/');
+            }
+        }
+
+        /**
+         * @param {Bean} bean
+         */
+        static _newBean(bean) {
+            const shortClsName = JavaTypes.shortClassName(bean.clsName);
+
+            if (_.isEmpty(bean.arguments))
+                return `new ${shortClsName}()`;
+
+            const args = _.map(bean.arguments, (arg) => {
+                switch (arg.clsName) {
+                    case 'MAP':
+                        return arg.id;
+                    case 'BEAN':
+                        return this._newBean(arg.value);
+                    default:
+                        return this._toObject(arg.clsName, arg.value);
+                }
+            });
+
+            if (bean.factoryMtd)
+                return `${shortClsName}.${bean.factoryMtd}(${args.join(', ')})`;
+
+            return `new ${shortClsName}(${args.join(', ')})`;
+        }
+
+        /**
+         * @param {StringBuilder} sb
+         * @param {String} parentId
+         * @param {String} propertyName
+         * @param {String} value
+         * @private
+         */
+        static _setProperty(sb, parentId, propertyName, value) {
+            sb.append(`${parentId}.set${_.upperFirst(propertyName)}(${value});`);
+        }
+
+        /**
+         * @param {StringBuilder} sb
+         * @param {Array.<String>} vars
+         * @param {Boolean} limitLines
+         * @param {Bean} bean
+         * @param {String} id
+
+         * @private
+         */
+        static constructBean(sb, bean, vars = [], limitLines = false, id = bean.id) {
+            _.forEach(bean.arguments, (arg) => {
+                switch (arg.clsName) {
+                    case 'MAP':
+                        this._constructMap(sb, arg, vars);
+
+                        sb.emptyLine();
+
+                        break;
+                    default:
+                        if (this._isBean(arg.clsName) && arg.value.isComplex()) {
+                            this.constructBean(sb, arg.value, vars, limitLines);
+
+                            sb.emptyLine();
+                        }
+                }
+            });
+
+            const clsName = JavaTypes.shortClassName(bean.clsName);
+
+            sb.append(`${this.varInit(clsName, id, vars)} = ${this._newBean(bean)};`);
+
+            if (_.nonEmpty(bean.properties)) {
+                sb.emptyLine();
+
+                this._setProperties(sb, bean, vars, limitLines, id);
+            }
+        }
+
+        /**
+         * @param {StringBuilder} sb
+         * @param {Bean} bean
+         * @param {Array.<String>} vars
+         * @param {Boolean} limitLines
+         * @private
+         */
+        static constructStoreFactory(sb, bean, vars, limitLines = false) {
+            const shortClsName = JavaTypes.shortClassName(bean.clsName);
+
+            if (_.includes(vars, bean.id))
+                sb.append(`${bean.id} = ${this._newBean(bean)};`);
+            else {
+                vars.push(bean.id);
+
+                sb.append(`${shortClsName} ${bean.id} = ${this._newBean(bean)};`);
+            }
+
+            sb.emptyLine();
+
+            sb.startBlock(`${bean.id}.setDataSourceFactory(new Factory<DataSource>() {`);
+            this.commentBlock(sb, '{@inheritDoc}');
+            sb.startBlock('@Override public DataSource create() {');
+
+            sb.append(`return DataSources.INSTANCE_${bean.findProperty('dataSourceBean').id};`);
+
+            sb.endBlock('};');
+            sb.endBlock('});');
+
+            const storeFactory = _.cloneDeep(bean);
+
+            _.remove(storeFactory.properties, (p) => _.includes(['dataSourceBean'], p.name));
+
+            if (storeFactory.properties.length) {
+                sb.emptyLine();
+
+                this._setProperties(sb, storeFactory, vars, limitLines);
+            }
+        }
+
+        static _isBean(clsName) {
+            return JavaTypes.nonBuiltInClass(clsName) && JavaTypes.nonEnum(clsName) && _.includes(clsName, '.');
+        }
+
+        static _toObject(clsName, val) {
+            const items = _.isArray(val) ? val : [val];
+
+            return _.map(items, (item) => {
+                if (_.isNil(item))
+                    return 'null';
+
+                switch (clsName) {
+                    case 'var':
+                        return item;
+                    case 'byte':
+                        return `(byte) ${item}`;
+                    case 'float':
+                        return `${item}f`;
+                    case 'long':
+                        return `${item}L`;
+                    case 'java.io.Serializable':
+                    case 'java.lang.String':
+                        return `"${item}"`;
+                    case 'PATH':
+                        return `"${item.replace(/\\/g, '\\\\')}"`;
+                    case 'java.lang.Class':
+                        return `${JavaTypes.shortClassName(item)}.class`;
+                    case 'java.util.UUID':
+                        return `UUID.fromString("${item}")`;
+                    case 'PROPERTY_CHAR':
+                        return `props.getProperty("${item}").toCharArray()`;
+                    case 'PROPERTY':
+                        return `props.getProperty("${item}")`;
+                    default:
+                        if (this._isBean(clsName)) {
+                            if (item.isComplex())
+                                return item.id;
+
+                            return this._newBean(item);
+                        }
+
+                        if (JavaTypes.nonEnum(clsName))
+                            return item;
+
+                        return `${JavaTypes.shortClassName(clsName)}.${item}`;
+                }
+            });
+        }
+
+        static _constructBeans(sb, type, items, vars, limitLines) {
+            if (this._isBean(type)) {
+                // Construct objects inline for preview or simple objects.
+                const mapper = this.METHOD_MAPPING[type];
+
+                const nextId = mapper ? mapper.id : beenNameSeed();
+
+                // Prepare objects refs.
+                return _.map(items, (item) => {
+                    if (limitLines && mapper)
+                        return mapper.id(item) + (limitLines ? `(${mapper.args})` : '');
+
+                    if (item.isComplex()) {
+                        const id = nextId(item);
+
+                        this.constructBean(sb, item, vars, limitLines, id);
+
+                        sb.emptyLine();
+
+                        return id;
+                    }
+
+                    return this._newBean(item);
+                });
+            }
+
+            return this._toObject(type, items);
+        }
+
+        /**
+         *
+         * @param sb
+         * @param parentId
+         * @param arrProp
+         * @param vars
+         * @param limitLines
+         * @private
+         */
+        static _setVarArg(sb, parentId, arrProp, vars, limitLines) {
+            const refs = this._constructBeans(sb, arrProp.typeClsName, arrProp.items, vars, limitLines);
+
+            // Set refs to property.
+            if (refs.length === 1)
+                this._setProperty(sb, parentId, arrProp.name, _.head(refs));
+            else {
+                sb.startBlock(`${parentId}.set${_.upperFirst(arrProp.name)}(`);
+
+                const lastIdx = refs.length - 1;
+
+                _.forEach(refs, (ref, idx) => {
+                    sb.append(ref + (lastIdx !== idx ? ',' : ''));
+                });
+
+                sb.endBlock(');');
+            }
+        }
+
+        /**
+         *
+         * @param sb
+         * @param parentId
+         * @param arrProp
+         * @param vars
+         * @param limitLines
+         * @private
+         */
+        static _setArray(sb, parentId, arrProp, vars, limitLines) {
+            const refs = this._constructBeans(sb, arrProp.typeClsName, arrProp.items, vars, limitLines);
+
+            const arrType = JavaTypes.shortClassName(arrProp.typeClsName);
+
+            // Set refs to property.
+            sb.startBlock(`${parentId}.set${_.upperFirst(arrProp.name)}(new ${arrType}[] {`);
+
+            const lastIdx = refs.length - 1;
+
+            _.forEach(refs, (ref, idx) => sb.append(ref + (lastIdx !== idx ? ',' : '')));
+
+            sb.endBlock('});');
+        }
+
+        static _constructMap(sb, map, vars = []) {
+            const keyClsName = JavaTypes.shortClassName(map.keyClsName);
+            const valClsName = JavaTypes.shortClassName(map.valClsName);
+
+            const mapClsName = map.ordered ? 'LinkedHashMap' : 'HashMap';
+
+            const type = `${mapClsName}<${keyClsName}, ${valClsName}>`;
+
+            sb.append(`${this.varInit(type, map.id, vars)} = new ${mapClsName}<>();`);
+
+            sb.emptyLine();
+
+            _.forEach(map.entries, (entry) => {
+                const key = this._toObject(map.keyClsName, entry[map.keyField]);
+                const val = entry[map.valField];
+
+                if (_.isArray(val) && map.valClsName === 'java.lang.String') {
+                    if (val.length > 1) {
+                        sb.startBlock(`${map.id}.put(${key},`);
+
+                        _.forEach(val, (line, idx) => {
+                            sb.append(`"${line}"${idx !== val.length - 1 ? ' +' : ''}`);
+                        });
+
+                        sb.endBlock(');');
+                    }
+                    else
+                        sb.append(`${map.id}.put(${key}, ${this._toObject(map.valClsName, _.head(val))});`);
+                }
+                else
+                    sb.append(`${map.id}.put(${key}, ${this._toObject(map.valClsName, val)});`);
+            });
+        }
+
+        static varInit(type, id, vars) {
+            if (_.includes(vars, id))
+                return id;
+
+            vars.push(id);
+
+            return `${type} ${id}`;
+        }
+
+        /**
+         *
+         * @param {StringBuilder} sb
+         * @param {Bean} bean
+         * @param {String} id
+         * @param {Array.<String>} vars
+         * @param {Boolean} limitLines
+         * @returns {StringBuilder}
+         */
+        static _setProperties(sb = new StringBuilder(), bean, vars = [], limitLines = false, id = bean.id) {
+            _.forEach(bean.properties, (prop, idx) => {
+                switch (prop.clsName) {
+                    case 'DATA_SOURCE':
+                        this._setProperty(sb, id, 'dataSource', `DataSources.INSTANCE_${prop.id}`);
+
+                        break;
+                    case 'EVENT_TYPES':
+                        if (prop.eventTypes.length === 1)
+                            this._setProperty(sb, id, prop.name, _.head(prop.eventTypes));
+                        else {
+                            sb.append(`int[] ${prop.id} = new int[${_.head(prop.eventTypes)}.length`);
+
+                            _.forEach(_.tail(prop.eventTypes), (evtGrp) => {
+                                sb.append(`    + ${evtGrp}.length`);
+                            });
+
+                            sb.append('];');
+
+                            sb.emptyLine();
+
+                            sb.append('int k = 0;');
+
+                            _.forEach(prop.eventTypes, (evtGrp, evtIdx) => {
+                                sb.emptyLine();
+
+                                sb.append(`System.arraycopy(${evtGrp}, 0, ${prop.id}, k, ${evtGrp}.length);`);
+
+                                if (evtIdx < prop.eventTypes.length - 1)
+                                    sb.append(`k += ${evtGrp}.length;`);
+                            });
+
+                            sb.emptyLine();
+
+                            sb.append(`cfg.setIncludeEventTypes(${prop.id});`);
+                        }
+
+                        break;
+                    case 'ARRAY':
+                        if (prop.varArg)
+                            this._setVarArg(sb, id, prop, vars, limitLines);
+                        else
+                            this._setArray(sb, id, prop, vars, limitLines);
+
+                        break;
+                    case 'COLLECTION':
+                        const nonBean = !this._isBean(prop.typeClsName);
+
+                        if (nonBean && prop.implClsName === 'java.util.ArrayList') {
+                            const items = _.map(prop.items, (item) => this._toObject(prop.typeClsName, item));
+
+                            if (items.length > 1) {
+                                sb.startBlock(`${id}.set${_.upperFirst(prop.name)}(Arrays.asList(`);
+
+                                _.forEach(items, (item, i) => sb.append(item + (i !== items.length - 1 ? ',' : '')));
+
+                                sb.endBlock('));');
+                            }
+                            else
+                                this._setProperty(sb, id, prop.name, `Arrays.asList(${items})`);
+                        }
+                        else {
+                            const colTypeClsName = JavaTypes.shortClassName(prop.typeClsName);
+                            const implClsName = JavaTypes.shortClassName(prop.implClsName);
+
+                            sb.append(`${this.varInit(`${implClsName}<${colTypeClsName}>`, prop.id, vars)} = new ${implClsName}<>();`);
+
+                            sb.emptyLine();
+
+                            if (nonBean) {
+                                _.forEach(this._toObject(colTypeClsName, prop.items), (item) => {
+                                    sb.append(`${prop.id}.add("${item}");`);
+
+                                    sb.emptyLine();
+                                });
+                            }
+                            else {
+                                _.forEach(prop.items, (item) => {
+                                    this.constructBean(sb, item, vars, limitLines);
+
+                                    sb.append(`${prop.id}.add(${item.id});`);
+
+                                    sb.emptyLine();
+                                });
+                            }
+
+                            this._setProperty(sb, id, prop.name, prop.id);
+                        }
+
+                        break;
+                    case 'MAP':
+                        this._constructMap(sb, prop, vars);
+
+                        if (_.nonEmpty(prop.entries))
+                            sb.emptyLine();
+
+                        this._setProperty(sb, id, prop.name, prop.id);
+
+                        break;
+                    case 'java.util.Properties':
+                        sb.append(`${this.varInit('Properties', prop.id, vars)} = new Properties();`);
+
+                        if (_.nonEmpty(prop.entries))
+                            sb.emptyLine();
+
+                        _.forEach(prop.entries, (entry) => {
+                            const key = this._toObject('java.lang.String', entry.name);
+                            const val = this._toObject('java.lang.String', entry.value);
+
+                            sb.append(`${prop.id}.setProperty(${key}, ${val});`);
+                        });
+
+                        sb.emptyLine();
+
+                        this._setProperty(sb, id, prop.name, prop.id);
+
+                        break;
+                    case 'BEAN':
+                        const embedded = prop.value;
+
+                        if (_.includes(STORE_FACTORY, embedded.clsName)) {
+                            this.constructStoreFactory(sb, embedded, vars, limitLines);
+
+                            sb.emptyLine();
+
+                            this._setProperty(sb, id, prop.name, embedded.id);
+                        }
+                        else if (embedded.isComplex()) {
+                            this.constructBean(sb, embedded, vars, limitLines);
+
+                            sb.emptyLine();
+
+                            this._setProperty(sb, id, prop.name, embedded.id);
+                        }
+                        else
+                            this._setProperty(sb, id, prop.name, this._newBean(embedded));
+
+                        break;
+                    default:
+                        this._setProperty(sb, id, prop.name, this._toObject(prop.clsName, prop.value));
+                }
+
+                this._emptyLineIfNeeded(sb, bean.properties, idx);
+            });
+
+            return sb;
+        }
+
+        static collectBeanImports(bean) {
+            const imports = [bean.clsName];
+
+            _.forEach(bean.arguments, (arg) => {
+                switch (arg.clsName) {
+                    case 'BEAN':
+                        imports.push(...this.collectPropertiesImports(arg.value.properties));
+
+                        break;
+                    case 'java.lang.Class':
+                        imports.push(JavaTypes.fullClassName(arg.value));
+
+                        break;
+                    default:
+                        imports.push(arg.clsName);
+                }
+            });
+
+            imports.push(...this.collectPropertiesImports(bean.properties));
+
+            if (_.includes(STORE_FACTORY, bean.clsName))
+                imports.push('javax.sql.DataSource', 'javax.cache.configuration.Factory');
+
+            return imports;
+        }
+
+        /**
+         * @param {Array.<Object>} props
+         * @returns {Array.<String>}
+         */
+        static collectPropertiesImports(props) {
+            const imports = [];
+
+            _.forEach(props, (prop) => {
+                switch (prop.clsName) {
+                    case 'DATA_SOURCE':
+                        imports.push(prop.value.clsName);
+
+                        break;
+                    case 'PROPERTY':
+                    case 'PROPERTY_CHAR':
+                        imports.push('java.io.InputStream', 'java.util.Properties');
+
+                        break;
+                    case 'BEAN':
+                        imports.push(...this.collectBeanImports(prop.value));
+
+                        break;
+                    case 'ARRAY':
+                        imports.push(prop.typeClsName);
+
+                        if (this._isBean(prop.typeClsName))
+                            _.forEach(prop.items, (item) => imports.push(...this.collectBeanImports(item)));
+
+                        break;
+                    case 'COLLECTION':
+                        imports.push(prop.typeClsName);
+
+                        if (this._isBean(prop.typeClsName)) {
+                            _.forEach(prop.items, (item) => imports.push(...this.collectBeanImports(item)));
+
+                            imports.push(prop.implClsName);
+                        }
+                        else if (prop.implClsName === 'java.util.ArrayList')
+                            imports.push('java.util.Arrays');
+                        else
+                            imports.push(prop.implClsName);
+
+                        break;
+                    case 'MAP':
+                        imports.push(prop.ordered ? 'java.util.LinkedHashMap' : 'java.util.HashMap');
+                        imports.push(prop.keyClsName);
+                        imports.push(prop.valClsName);
+
+                        break;
+                    default:
+                        if (!JavaTypes.nonEnum(prop.clsName))
+                            imports.push(prop.clsName);
+                }
+            });
+
+            return imports;
+        }
+
+        static _prepareImports(imports) {
+            return _.sortedUniq(_.sortBy(_.filter(imports, (cls) => !cls.startsWith('java.lang.') && _.includes(cls, '.'))));
+        }
+
+        /**
+         * @param {Bean} bean
+         * @returns {Array.<String>}
+         */
+        static collectStaticImports(bean) {
+            const imports = [];
+
+            _.forEach(bean.properties, (prop) => {
+                switch (prop.clsName) {
+                    case 'EVENT_TYPES':
+                        _.forEach(prop.eventTypes, (value) => {
+                            const evtGrp = _.find(eventGroups, {value});
+
+                            imports.push(`${evtGrp.class}.${evtGrp.value}`);
+                        });
+
+                        break;
+                    default:
+                        // No-op.
+                }
+            });
+
+            return imports;
+        }
+
+        /**
+         * @param {Bean} bean
+         * @returns {Object}
+         */
+        static collectBeansWithMapping(bean) {
+            const beans = {};
+
+            _.forEach(bean.properties, (prop) => {
+                switch (prop.clsName) {
+                    case 'BEAN':
+                        _.merge(beans, this.collectBeansWithMapping(prop.value));
+
+                        break;
+                    case 'ARRAY':
+                        if (this._isBean(prop.typeClsName)) {
+                            const mapping = this.METHOD_MAPPING[prop.typeClsName];
+
+                            _.reduce(prop.items, (acc, item) => {
+                                if (mapping) {
+                                    acc[mapping.id(item)] = item;
+
+                                    _.merge(acc, this.collectBeansWithMapping(item));
+                                }
+                                return acc;
+                            }, beans);
+                        }
+
+                        break;
+                    default:
+                        // No-op.
+                }
+            });
+
+            return beans;
+        }
+
+        /**
+         * Build Java startup class with configuration.
+         *
+         * @param {Bean} cfg
+         * @param pkg Package name.
+         * @param {String} clsName Class name for generate factory class otherwise generate code snippet.
+         * @param {Array.<Object>} clientNearCaches Is client node.
+         * @returns {StringBuilder}
+         */
+        static igniteConfiguration(cfg, pkg, clsName, clientNearCaches) {
+            const sb = new StringBuilder();
+
+            sb.append(`package ${pkg};`);
+            sb.emptyLine();
+
+            const imports = this.collectBeanImports(cfg);
+
+            if (_.nonEmpty(clientNearCaches))
+                imports.push('org.apache.ignite.configuration.NearCacheConfiguration');
+
+            if (_.includes(imports, 'oracle.jdbc.pool.OracleDataSource'))
+                imports.push('java.sql.SQLException');
+
+            const hasProps = this.hasProperties(cfg);
+
+            if (hasProps)
+                imports.push('java.util.Properties', 'java.io.InputStream');
+
+            _.forEach(this._prepareImports(imports), (cls) => sb.append(`import ${cls};`));
+
+            sb.emptyLine();
+
+            const staticImports = this._prepareImports(this.collectStaticImports(cfg));
+
+            if (staticImports.length) {
+                _.forEach(this._prepareImports(staticImports), (cls) => sb.append(`import static ${cls};`));
+
+                sb.emptyLine();
+            }
+
+            this.mainComment(sb);
+            sb.startBlock(`public class ${clsName} {`);
+
+            // 2. Add external property file
+            if (hasProps) {
+                this.commentBlock(sb, 'Secret properties loading.');
+                sb.append('private static final Properties props = new Properties();');
+                sb.emptyLine();
+                sb.startBlock('static {');
+                sb.startBlock('try (InputStream in = IgniteConfiguration.class.getClassLoader().getResourceAsStream("secret.properties")) {');
+                sb.append('props.load(in);');
+                sb.endBlock('}');
+                sb.startBlock('catch (Exception ignored) {');
+                sb.append('// No-op.');
+                sb.endBlock('}');
+                sb.endBlock('}');
+                sb.emptyLine();
+            }
+
+            // 3. Add data sources.
+            const dataSources = this.collectDataSources(cfg);
+
+            if (dataSources.length) {
+                this.commentBlock(sb, 'Helper class for datasource creation.');
+                sb.startBlock('public static class DataSources {');
+
+                _.forEach(dataSources, (ds, idx) => {
+                    const dsClsName = JavaTypes.shortClassName(ds.clsName);
+
+                    if (idx !== 0)
+                        sb.emptyLine();
+
+                    sb.append(`public static final ${dsClsName} INSTANCE_${ds.id} = create${ds.id}();`);
+                    sb.emptyLine();
+
+                    sb.startBlock(`private static ${dsClsName} create${ds.id}() {`);
+
+                    if (dsClsName === 'OracleDataSource')
+                        sb.startBlock('try {');
+
+                    this.constructBean(sb, ds);
+
+                    sb.emptyLine();
+                    sb.append(`return ${ds.id};`);
+
+                    if (dsClsName === 'OracleDataSource') {
+                        sb.endBlock('}');
+                        sb.startBlock('catch (SQLException ex) {');
+                        sb.append('throw new Error(ex);');
+                        sb.endBlock('}');
+                    }
+
+                    sb.endBlock('}');
+                });
+
+                sb.endBlock('}');
+
+                sb.emptyLine();
+            }
+
+            _.forEach(clientNearCaches, (cache) => {
+                this.commentBlock(sb, `Configuration of near cache for cache: ${cache.name}.`,
+                    '',
+                    '@return Near cache configuration.',
+                    '@throws Exception If failed to construct near cache configuration instance.'
+                );
+
+                const nearCacheBean = generator.cacheNearClient(cache);
+
+                sb.startBlock(`public static NearCacheConfiguration ${nearCacheBean.id}() throws Exception {`);
+
+                this.constructBean(sb, nearCacheBean);
+                sb.emptyLine();
+
+                sb.append(`return ${nearCacheBean.id};`);
+                sb.endBlock('}');
+
+                sb.emptyLine();
+            });
+
+            this.commentBlock(sb, 'Configure grid.',
+                '',
+                '@return Ignite configuration.',
+                '@throws Exception If failed to construct Ignite configuration instance.'
+            );
+            sb.startBlock('public static IgniteConfiguration createConfiguration() throws Exception {');
+
+            this.constructBean(sb, cfg, [], true);
+
+            sb.emptyLine();
+
+            sb.append(`return ${cfg.id};`);
+
+            sb.endBlock('}');
+
+            const beans = this.collectBeansWithMapping(cfg);
+
+            _.forEach(beans, (bean, id) => {
+                sb.emptyLine();
+
+                this.METHOD_MAPPING[bean.clsName].generator(sb, id, bean);
+            });
+
+            sb.endBlock('}');
+
+            return sb;
+        }
+
+        static cluster(cluster, pkg, clsName, client) {
+            const cfg = this.generator.igniteConfiguration(cluster, client);
+
+            const clientNearCaches = client ? _.filter(cluster.caches, (cache) => _.get(cache, 'clientNearConfiguration.enabled')) : [];
+
+            return this.igniteConfiguration(cfg, pkg, clsName, clientNearCaches);
+        }
+
+        /**
+         * Generate source code for type by its domain model.
+         *
+         * @param fullClsName Full class name.
+         * @param fields Fields.
+         * @param addConstructor If 'true' then empty and full constructors should be generated.
+         * @returns {StringBuilder}
+         */
+        static pojo(fullClsName, fields, addConstructor) {
+            const dotIdx = fullClsName.lastIndexOf('.');
+
+            const pkg = fullClsName.substring(0, dotIdx);
+            const clsName = fullClsName.substring(dotIdx + 1);
+
+            const sb = new StringBuilder();
+
+            sb.append(`package ${pkg};`);
+            sb.emptyLine();
+
+            const imports = ['java.io.Serializable'];
+
+            _.forEach(fields, (field) => imports.push(JavaTypes.fullClassName(field.javaFieldType)));
+
+            _.forEach(this._prepareImports(imports), (cls) => sb.append(`import ${cls};`));
+
+            sb.emptyLine();
+
+            this.mainComment(sb,
+                `${clsName} definition.`,
+                ''
+            );
+            sb.startBlock(`public class ${clsName} implements Serializable {`);
+            sb.append('/** */');
+            sb.append('private static final long serialVersionUID = 0L;');
+            sb.emptyLine();
+
+            // Generate fields declaration.
+            _.forEach(fields, (field) => {
+                const fldName = field.javaFieldName;
+                const fldType = JavaTypes.shortClassName(field.javaFieldType);
+
+                sb.append(`/** Value for ${fldName}. */`);
+                sb.append(`private ${fldType} ${fldName};`);
+
+                sb.emptyLine();
+            });
+
+            // Generate constructors.
+            if (addConstructor) {
+                this.commentBlock(sb, 'Empty constructor.');
+                sb.startBlock(`public ${clsName}() {`);
+                this.comment(sb, 'No-op.');
+                sb.endBlock('}');
+
+                sb.emptyLine();
+
+                this.commentBlock(sb, 'Full constructor.');
+
+                const arg = (field) => {
+                    const fldType = JavaTypes.shortClassName(field.javaFieldType);
+
+                    return `${fldType} ${field.javaFieldName}`;
+                };
+
+                sb.startBlock(`public ${clsName}(${arg(_.head(fields))}${fields.length === 1 ? ') {' : ','}`);
+
+                _.forEach(_.tail(fields), (field, idx) => {
+                    sb.append(`${arg(field)}${idx !== fields.length - 1 ? ',' : ') {'}`);
+                });
+
+                _.forEach(fields, (field) => sb.append(`this.${field.javaFieldName} = ${field.javaFieldName};`));
+
+                sb.endBlock('}');
+
+                sb.emptyLine();
+            }
+
+            // Generate getters and setters methods.
+            _.forEach(fields, (field) => {
+                const fldType = JavaTypes.shortClassName(field.javaFieldType);
+                const fldName = field.javaFieldName;
+
+                this.commentBlock(sb,
+                    `Gets ${fldName}`,
+                    '',
+                    `@return Value for ${fldName}.`
+                );
+                sb.startBlock(`public ${fldType} ${JavaTypes.toJavaName('get', fldName)}() {`);
+                sb.append('return ' + fldName + ';');
+                sb.endBlock('}');
+
+                sb.emptyLine();
+
+                this.commentBlock(sb,
+                    `Sets ${fldName}`,
+                    '',
+                    `@param ${fldName} New value for ${fldName}.`
+                );
+                sb.startBlock(`public void ${JavaTypes.toJavaName('set', fldName)}(${fldType} ${fldName}) {`);
+                sb.append(`this.${fldName} = ${fldName};`);
+                sb.endBlock('}');
+
+                sb.emptyLine();
+            });
+
+            // Generate equals() method.
+            this.commentBlock(sb, '{@inheritDoc}');
+            sb.startBlock('@Override public boolean equals(Object o) {');
+            sb.startBlock('if (this == o)');
+            sb.append('return true;');
+
+            sb.endBlock('');
+
+            sb.startBlock(`if (!(o instanceof ${clsName}))`);
+            sb.append('return false;');
+
+            sb.endBlock('');
+
+            sb.append(`${clsName} that = (${clsName})o;`);
+
+            _.forEach(fields, (field) => {
+                sb.emptyLine();
+
+                const javaName = field.javaFieldName;
+                const javaType = field.javaFieldType;
+
+                switch (javaType) {
+                    case 'float':
+                        sb.startBlock(`if (Float.compare(${javaName}, that.${javaName}) != 0)`);
+
+                        break;
+                    case 'double':
+                        sb.startBlock(`if (Double.compare(${javaName}, that.${javaName}) != 0)`);
+
+                        break;
+                    default:
+                        if (JavaTypes.isJavaPrimitive(javaType))
+                            sb.startBlock('if (' + javaName + ' != that.' + javaName + ')');
+                        else
+                            sb.startBlock('if (' + javaName + ' != null ? !' + javaName + '.equals(that.' + javaName + ') : that.' + javaName + ' != null)');
+                }
+
+                sb.append('return false;');
+
+                sb.endBlock('');
+            });
+
+            sb.append('return true;');
+            sb.endBlock('}');
+
+            sb.emptyLine();
+
+            // Generate hashCode() method.
+            this.commentBlock(sb, '{@inheritDoc}');
+            sb.startBlock('@Override public int hashCode() {');
+
+            let first = true;
+            let tempVar = false;
+
+            _.forEach(fields, (field) => {
+                const javaName = field.javaFieldName;
+                const javaType = field.javaFieldType;
+
+                let fldHashCode;
+
+                switch (javaType) {
+                    case 'boolean':
+                        fldHashCode = `${javaName} ? 1 : 0`;
+
+                        break;
+                    case 'byte':
+                    case 'short':
+                        fldHashCode = `(int)${javaName}`;
+
+                        break;
+                    case 'int':
+                        fldHashCode = `${javaName}`;
+
+                        break;
+                    case 'long':
+                        fldHashCode = `(int)(${javaName} ^ (${javaName} >>> 32))`;
+
+                        break;
+                    case 'float':
+                        fldHashCode = `${javaName} != +0.0f ? Float.floatToIntBits(${javaName}) : 0`;
+
+                        break;
+                    case 'double':
+                        sb.append(`${tempVar ? 'ig_hash_temp' : 'long ig_hash_temp'} = Double.doubleToLongBits(${javaName});`);
+
+                        tempVar = true;
+
+                        fldHashCode = `${javaName} != +0.0f ? Float.floatToIntBits(${javaName}) : 0`;
+
+                        break;
+                    default:
+                        fldHashCode = `${javaName} != null ? ${javaName}.hashCode() : 0`;
+                }
+
+                sb.append(first ? `int res = ${fldHashCode};` : `res = 31 * res + ${fldHashCode.startsWith('(') ? fldHashCode : `(${fldHashCode})`};`);
+
+                first = false;
+
+                sb.emptyLine();
+            });
+
+            sb.append('return res;');
+            sb.endBlock('}');
+
+            sb.emptyLine();
+
+            this.commentBlock(sb, '{@inheritDoc}');
+            sb.startBlock('@Override public String toString() {');
+            sb.startBlock(`return "${clsName} [" + `);
+
+            _.forEach(fields, (field, idx) => {
+                sb.append(`"${field.javaFieldName}=" + ${field.javaFieldName}${idx < fields.length - 1 ? ' + ", " + ' : ' +'}`);
+            });
+
+            sb.endBlock('"]";');
+            sb.endBlock('}');
+
+            sb.endBlock('}');
+
+            return sb.asString();
+        }
+
+        /**
+         * Generate source code for type by its domain models.
+         *
+         * @param caches List of caches to generate POJOs for.
+         * @param addConstructor If 'true' then generate constructors.
+         * @param includeKeyFields If 'true' then include key fields into value POJO.
+         */
+        static pojos(caches, addConstructor, includeKeyFields) {
+            const pojos = [];
+
+            _.forEach(caches, (cache) => {
+                _.forEach(cache.domains, (domain) => {
+                    // Process only  domains with 'generatePojo' flag and skip already generated classes.
+                    if (domain.generatePojo && !_.find(pojos, {valueType: domain.valueType}) &&
+                        // Skip domain models without value fields.
+                        _.nonEmpty(domain.valueFields)) {
+                        const pojo = {};
+
+                        // Key class generation only if key is not build in java class.
+                        if (_.nonNil(domain.keyFields) && domain.keyFields.length > 0) {
+                            pojo.keyType = domain.keyType;
+                            pojo.keyClass = this.pojo(domain.keyType, domain.keyFields, addConstructor);
+                        }
+
+                        const valueFields = _.clone(domain.valueFields);
+
+                        if (includeKeyFields) {
+                            _.forEach(domain.keyFields, ({fld}) => {
+                                if (!_.find(valueFields, {name: fld.name}))
+                                    valueFields.push(fld);
+                            });
+                        }
+
+                        pojo.valueType = domain.valueType;
+                        pojo.valueClass = this.pojo(domain.valueType, valueFields, addConstructor);
+
+                        pojos.push(pojo);
+                    }
+                });
+            });
+
+            return pojos;
+        }
+
+        // Generate creation and execution of cache query.
+        static _multilineQuery(sb, query, prefix, postfix) {
+            if (_.isEmpty(query))
+                return;
+
+            _.forEach(query, (line, ix) => {
+                if (ix === 0) {
+                    if (query.length === 1)
+                        sb.append(`${prefix}"${line}"${postfix}`);
+                    else
+                        sb.startBlock(`${prefix}"${line}" +`);
+                }
+                else
+                    sb.append(`"${line}"${ix === query.length - 1 ? postfix : ' +'}`);
+            });
+
+            if (query.length > 1)
+                sb.endBlock('');
+            else
+                sb.emptyLine();
+        }
+
+        // Generate creation and execution of prepared statement.
+        static _prepareStatement(sb, conVar, query) {
+            this._multilineQuery(sb, query, `${conVar}.prepareStatement(`, ').executeUpdate();');
+        }
+
+        static demoStartup(sb, cluster, shortFactoryCls) {
+            const cachesWithDataSource = _.filter(cluster.caches, (cache) => {
+                const kind = _.get(cache, 'cacheStoreFactory.kind');
+
+                if (kind) {
+                    const store = cache.cacheStoreFactory[kind];
+
+                    return (store.connectVia === 'DataSource' || _.isNil(store.connectVia)) && store.dialect;
+                }
+
+                return false;
+            });
+
+            const uniqDomains = [];
+
+            // Prepare array of cache and his demo domain model list. Every domain is contained only in first cache.
+            const demoTypes = _.reduce(cachesWithDataSource, (acc, cache) => {
+                const domains = _.filter(cache.domains, (domain) => _.nonEmpty(domain.valueFields) &&
+                    !_.includes(uniqDomains, domain));
+
+                if (_.nonEmpty(domains)) {
+                    uniqDomains.push(...domains);
+
+                    acc.push({
+                        cache,
+                        domains
+                    });
+                }
+
+                return acc;
+            }, []);
+
+            if (_.nonEmpty(demoTypes)) {
+                // Group domain modes by data source
+                const typeByDs = _.groupBy(demoTypes, ({cache}) => cache.cacheStoreFactory[cache.cacheStoreFactory.kind].dataSourceBean);
+
+                let rndNonDefined = true;
+
+                const generatedConsts = [];
+
+                _.forEach(typeByDs, (types) => {
+                    _.forEach(types, (type) => {
+                        _.forEach(type.domains, (domain) => {
+                            const valType = domain.valueType.toUpperCase();
+
+                            const desc = _.find(PREDEFINED_QUERIES, (qry) => valType.endsWith(qry.type));
+
+                            if (desc) {
+                                if (rndNonDefined && desc.rndRequired) {
+                                    this.commentBlock(sb, 'Random generator for demo data.');
+                                    sb.append('private static final Random rnd = new Random();');
+
+                                    sb.emptyLine();
+
+                                    rndNonDefined = false;
+                                }
+
+                                _.forEach(desc.insertCntConsts, (cnt) => {
+                                    if (!_.includes(generatedConsts, cnt.name)) {
+                                        this.commentBlock(sb, cnt.comment);
+                                        sb.append(`private static final int ${cnt.name} = ${cnt.val};`);
+
+                                        sb.emptyLine();
+
+                                        generatedConsts.push(cnt.name);
+                                    }
+                                });
+                            }
+                        });
+                    });
+                });
+
+                // Generation of fill database method
+                this.commentBlock(sb, 'Fill data for Demo.');
+                sb.startBlock('private static void prepareDemoData() throws SQLException {');
+
+                let firstDs = true;
+
+                _.forEach(typeByDs, (types, ds) => {
+                    const conVar = ds + 'Con';
+
+                    if (firstDs)
+                        firstDs = false;
+                    else
+                        sb.emptyLine();
+
+                    sb.startBlock(`try (Connection ${conVar} = ${shortFactoryCls}.DataSources.INSTANCE_${ds}.getConnection()) {`);
+
+                    let first = true;
+                    let stmtFirst = true;
+
+                    _.forEach(types, (type) => {
+                        _.forEach(type.domains, (domain) => {
+                            const valType = domain.valueType.toUpperCase();
+
+                            const desc = _.find(PREDEFINED_QUERIES, (qry) => valType.endsWith(qry.type));
+
+                            if (desc) {
+                                if (first)
+                                    first = false;
+                                else
+                                    sb.emptyLine();
+
+                                this.comment(sb, `Generate ${desc.type}.`);
+
+                                if (desc.schema)
+                                    this._prepareStatement(sb, conVar, [`CREATE SCHEMA IF NOT EXISTS ${desc.schema}`]);
+
+                                this._prepareStatement(sb, conVar, desc.create);
+
+                                this._prepareStatement(sb, conVar, desc.clearQuery);
+
+                                let stmtVar = 'stmt';
+
+                                if (stmtFirst) {
+                                    stmtFirst = false;
+
+                                    stmtVar = 'PreparedStatement stmt';
+                                }
+
+                                if (_.isFunction(desc.customGeneration))
+                                    desc.customGeneration(sb, conVar, stmtVar);
+                                else {
+                                    sb.append(`${stmtVar} = ${conVar}.prepareStatement("${desc.insertPattern}");`);
+
+                                    sb.emptyLine();
+
+                                    sb.startBlock(`for (int id = 0; id < ${desc.insertCntConsts[0].name}; id ++) {`);
+
+                                    desc.fillInsertParameters(sb);
+
+                                    sb.emptyLine();
+
+                                    sb.append('stmt.executeUpdate();');
+
+                                    sb.endBlock('}');
+                                }
+
+                                sb.emptyLine();
+
+                                sb.append(`${conVar}.commit();`);
+                            }
+                        });
+                    });
+
+                    sb.endBlock('}');
+                });
+
+                sb.endBlock('}');
+
+                sb.emptyLine();
+
+                this.commentBlock(sb, 'Print result table to console.');
+                sb.startBlock('private static void printResult(List<Cache.Entry<Object, Object>> rows) {');
+                sb.append('for (Cache.Entry<Object, Object> row: rows)');
+                sb.append('    System.out.println(row);');
+                sb.endBlock('}');
+
+                sb.emptyLine();
+
+                // Generation of execute queries method.
+                this.commentBlock(sb, 'Run demo.');
+                sb.startBlock('private static void runDemo(Ignite ignite) throws SQLException {');
+
+                const getType = (fullType) => fullType.substr(fullType.lastIndexOf('.') + 1);
+
+                const cacheLoaded = [];
+                let rowVariableDeclared = false;
+                firstDs = true;
+
+                _.forEach(typeByDs, (types, ds) => {
+                    const conVar = ds + 'Con';
+
+                    if (firstDs)
+                        firstDs = false;
+                    else
+                        sb.emptyLine();
+
+                    sb.startBlock(`try (Connection ${conVar} = ${shortFactoryCls}.DataSources.INSTANCE_${ds}.getConnection()) {`);
+
+                    let first = true;
+
+                    _.forEach(types, (type) => {
+                        _.forEach(type.domains, (domain) => {
+                            const valType = domain.valueType.toUpperCase();
+
+                            const desc = _.find(PREDEFINED_QUERIES, (qry) => valType.endsWith(qry.type));
+
+                            if (desc) {
+                                if (_.isEmpty(desc.selectQuery))
+                                    return;
+
+                                if (first)
+                                    first = false;
+                                else
+                                    sb.emptyLine();
+
+                                const cacheName = type.cache.name;
+
+                                if (!_.includes(cacheLoaded, cacheName)) {
+                                    sb.append(`ignite.cache("${cacheName}").loadCache(null);`);
+
+                                    sb.emptyLine();
+
+                                    cacheLoaded.push(cacheName);
+                                }
+
+                                const varRows = rowVariableDeclared ? 'rows' : 'List<Cache.Entry<Object, Object>> rows';
+
+                                this._multilineQuery(sb, desc.selectQuery, `${varRows} = ignite.cache("${cacheName}").query(new SqlQuery<>("${getType(domain.valueType)}", `, ')).getAll();');
+
+                                sb.append('printResult(rows);');
+
+                                rowVariableDeclared = true;
+                            }
+                        });
+                    });
+
+                    sb.endBlock('}');
+                });
+
+                sb.endBlock('}');
+            }
+        }
+
+        /**
+         * Function to generate java class for node startup with cluster configuration.
+         *
+         * @param {Object} cluster Cluster to process.
+         * @param {String} fullClsName Full class name.
+         * @param {String} cfgRef Config.
+         * @param {String} [factoryCls] fully qualified class name of configuration factory.
+         * @param {Array.<Object>} [clientNearCaches] Is client node.
+         */
+        static nodeStartup(cluster, fullClsName, cfgRef, factoryCls, clientNearCaches) {
+            const dotIdx = fullClsName.lastIndexOf('.');
+
+            const pkg = fullClsName.substring(0, dotIdx);
+            const clsName = fullClsName.substring(dotIdx + 1);
+
+            const demo = clsName === 'DemoStartup';
+
+            const sb = new StringBuilder();
+
+            const imports = ['org.apache.ignite.Ignition', 'org.apache.ignite.Ignite'];
+
+            if (demo) {
+                imports.push('org.h2.tools.Server', 'java.sql.Connection', 'java.sql.PreparedStatement',
+                    'java.sql.SQLException', 'java.util.Random', 'java.util.List', 'javax.cache.Cache',
+                    'org.apache.ignite.cache.query.SqlQuery');
+            }
+
+            let shortFactoryCls;
+
+            if (factoryCls) {
+                imports.push(factoryCls);
+
+                shortFactoryCls = JavaTypes.shortClassName(factoryCls);
+            }
+
+            sb.append(`package ${pkg};`)
+                .emptyLine();
+
+            _.forEach(this._prepareImports(imports), (cls) => sb.append(`import ${cls};`));
+            sb.emptyLine();
+
+            if (demo) {
+                this.mainComment(sb,
+                    'To start demo configure data sources in secret.properties file.',
+                    'For H2 database it should be like following:',
+                    'dsH2.jdbc.url=jdbc:h2:tcp://localhost/mem:DemoDB;DB_CLOSE_DELAY=-1',
+                    'dsH2.jdbc.username=sa',
+                    'dsH2.jdbc.password=',
+                    ''
+                );
+            }
+            else
+                this.mainComment(sb);
+
+            sb.startBlock(`public class ${clsName} {`);
+
+            if (demo && shortFactoryCls)
+                this.demoStartup(sb, cluster, shortFactoryCls);
+
+            this.commentBlock(sb,
+                'Start up node with specified configuration.',
+                '',
+                '@param args Command line arguments, none required.',
+                '@throws Exception If failed.'
+            );
+            sb.startBlock('public static void main(String[] args) throws Exception {');
+
+            if (demo) {
+                sb.startBlock('try {');
+                sb.append('// Start H2 database server.');
+                sb.append('Server.createTcpServer("-tcpDaemon").start();');
+                sb.endBlock('}');
+                sb.startBlock('catch (SQLException ignore) {');
+                sb.append('// No-op.');
+                sb.endBlock('}');
+
+                sb.emptyLine();
+            }
+
+            if ((_.nonEmpty(clientNearCaches) || demo) && shortFactoryCls) {
+                sb.append(`Ignite ignite = Ignition.start(${cfgRef});`);
+
+                _.forEach(clientNearCaches, (cache, idx) => {
+                    sb.emptyLine();
+
+                    if (idx === 0)
+                        sb.append('// Demo of near cache creation on client node.');
+
+                    const nearCacheMtd = JavaTypes.toJavaName('nearConfiguration', cache.name);
+
+                    sb.append(`ignite.getOrCreateCache(${shortFactoryCls}.${cache.name}(), ${shortFactoryCls}.${nearCacheMtd}());`);
+                });
+            }
+            else
+                sb.append(`Ignition.start(${cfgRef});`);
+
+            if (demo) {
+                sb.emptyLine();
+
+                sb.append('prepareDemoData();');
+
+                sb.emptyLine();
+
+                sb.append('runDemo(ignite);');
+            }
+
+            sb.endBlock('}');
+
+            sb.endBlock('}');
+
+            return sb.asString();
+        }
+
+        /**
+         * Function to generate java class for load caches.
+         *
+         * @param caches Caches to load.
+         * @param pkg Class package name.
+         * @param clsName Class name.
+         * @param {String} cfgRef Config.
+         */
+        static loadCaches(caches, pkg, clsName, cfgRef) {
+            const sb = new StringBuilder();
+
+            sb.append(`package ${pkg};`)
+                .emptyLine();
+
+            const imports = ['org.apache.ignite.Ignition', 'org.apache.ignite.Ignite'];
+
+            _.forEach(this._prepareImports(imports), (cls) => sb.append(`import ${cls};`));
+            sb.emptyLine();
+
+            this.mainComment(sb);
+            sb.startBlock(`public class ${clsName} {`);
+
+            this.commentBlock(sb,
+                '<p>',
+                'Utility to load caches from database.',
+                '<p>',
+                'How to use:',
+                '<ul>',
+                '    <li>Start cluster.</li>',
+                '    <li>Start this utility and wait while load complete.</li>',
+                '</ul>',
+                '',
+                '@param args Command line arguments, none required.',
+                '@throws Exception If failed.'
+            );
+            sb.startBlock('public static void main(String[] args) throws Exception {');
+
+            sb.startBlock(`try (Ignite ignite = Ignition.start(${cfgRef})) {`);
+
+            sb.append('System.out.println(">>> Loading caches...");');
+
+            sb.emptyLine();
+
+            _.forEach(caches, (cache) => {
+                sb.append('System.out.println(">>> Loading cache: ' + cache.name + '");');
+                sb.append('ignite.cache("' + cache.name + '").loadCache(null);');
+
+                sb.emptyLine();
+            });
+
+            sb.append('System.out.println(">>> All caches loaded!");');
+
+            sb.endBlock('}');
+
+            sb.endBlock('}');
+
+            sb.endBlock('}');
+
+            return sb.asString();
+        }
+
+        /**
+         * Checks if cluster has demo types.
+         *
+         * @param cluster Cluster to check.
+         * @param demo Is demo enabled.
+         * @returns {boolean} True if cluster has caches with demo types.
+         */
+        static isDemoConfigured(cluster, demo) {
+            return demo && _.find(cluster.caches, (cache) => _.find(cache.domains, (domain) => _.find(PREDEFINED_QUERIES, (desc) => domain.valueType.toUpperCase().endsWith(desc.type))));
+        }
+    }
+
+    return JavaTransformer;
+}];

http://git-wip-us.apache.org/repos/asf/ignite/blob/087f6405/modules/web-console/frontend/app/modules/configuration/generator/PlatformGenerator.js
----------------------------------------------------------------------
diff --git a/modules/web-console/frontend/app/modules/configuration/generator/PlatformGenerator.js b/modules/web-console/frontend/app/modules/configuration/generator/PlatformGenerator.js
new file mode 100644
index 0000000..b076193
--- /dev/null
+++ b/modules/web-console/frontend/app/modules/configuration/generator/PlatformGenerator.js
@@ -0,0 +1,522 @@
+/*
+ * 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';
+import { EmptyBean, Bean } from './Beans';
+
+export default ['JavaTypes', 'igniteClusterPlatformDefaults', 'igniteCachePlatformDefaults', (JavaTypes, clusterDflts, cacheDflts) => {
+    class PlatformGenerator {
+        static igniteConfigurationBean(cluster) {
+            return new Bean('Apache.Ignite.Core.IgniteConfiguration', 'cfg', cluster, clusterDflts);
+        }
+
+        static cacheConfigurationBean(cache) {
+            return new Bean('Apache.Ignite.Core.Cache.Configuration.CacheConfiguration', 'ccfg', cache, cacheDflts);
+        }
+
+        /**
+         * Function to generate ignite configuration.
+         *
+         * @param {Object} cluster Cluster to process.
+         * @return {String} Generated ignite configuration.
+         */
+        static igniteConfiguration(cluster) {
+            const cfg = this.igniteConfigurationBean(cluster);
+
+            this.clusterAtomics(cluster.atomics, cfg);
+
+            return cfg;
+        }
+
+        // Generate general section.
+        static clusterGeneral(cluster, cfg = this.igniteConfigurationBean(cluster)) {
+            cfg.stringProperty('name', 'GridName')
+                .stringProperty('localHost', 'Localhost');
+
+            if (_.isNil(cluster.discovery))
+                return cfg;
+
+            const discovery = new Bean('Apache.Ignite.Core.Discovery.Tcp.TcpDiscoverySpi', 'discovery',
+                cluster.discovery, clusterDflts.discovery);
+
+            let ipFinder;
+
+            switch (discovery.valueOf('kind')) {
+                case 'Vm':
+                    ipFinder = new Bean('Apache.Ignite.Core.Discovery.Tcp.Static.TcpDiscoveryStaticIpFinder',
+                        'ipFinder', cluster.discovery.Vm, clusterDflts.discovery.Vm);
+
+                    ipFinder.collectionProperty('addrs', 'addresses', cluster.discovery.Vm.addresses, 'ICollection');
+
+                    break;
+                case 'Multicast':
+                    ipFinder = new Bean('Apache.Ignite.Core.Discovery.Tcp.Multicast.TcpDiscoveryMulticastIpFinder',
+                        'ipFinder', cluster.discovery.Multicast, clusterDflts.discovery.Multicast);
+
+                    ipFinder.stringProperty('MulticastGroup')
+                        .intProperty('multicastPort', 'MulticastPort')
+                        .intProperty('responseWaitTime', 'ResponseTimeout')
+                        .intProperty('addressRequestAttempts', 'AddressRequestAttempts')
+                        .stringProperty('localAddress', 'LocalAddress')
+                        .collectionProperty('addrs', 'Endpoints', cluster.discovery.Multicast.addresses, 'ICollection');
+
+                    break;
+                default:
+            }
+
+            if (ipFinder)
+                discovery.beanProperty('IpFinder', ipFinder);
+
+            cfg.beanProperty('DiscoverySpi', discovery);
+
+
+            return cfg;
+        }
+
+        static clusterAtomics(atomics, cfg = this.igniteConfigurationBean()) {
+            const acfg = new Bean('Apache.Ignite.Core.DataStructures.Configuration.AtomicConfiguration', 'atomicCfg',
+                atomics, clusterDflts.atomics);
+
+            acfg.enumProperty('cacheMode', 'CacheMode')
+                .intProperty('atomicSequenceReserveSize', 'AtomicSequenceReserveSize');
+
+            if (acfg.valueOf('cacheMode') === 'PARTITIONED')
+                acfg.intProperty('backups', 'Backups');
+
+            if (acfg.isEmpty())
+                return cfg;
+
+            cfg.beanProperty('AtomicConfiguration', acfg);
+
+            return cfg;
+        }
+
+        // Generate binary group.
+        static clusterBinary(binary, cfg = this.igniteConfigurationBean()) {
+            const binaryCfg = new Bean('Apache.Ignite.Core.Binary.BinaryConfiguration', 'binaryCfg',
+                binary, clusterDflts.binary);
+
+            binaryCfg.emptyBeanProperty('idMapper', 'DefaultIdMapper')
+                .emptyBeanProperty('nameMapper', 'DefaultNameMapper')
+                .emptyBeanProperty('serializer', 'DefaultSerializer');
+
+            // const typeCfgs = [];
+            //
+            // _.forEach(binary.typeConfigurations, (type) => {
+            //     const typeCfg = new MethodBean('Apache.Ignite.Core.Binary.BinaryTypeConfiguration',
+            //         JavaTypes.toJavaName('binaryType', type.typeName), type, clusterDflts.binary.typeConfigurations);
+            //
+            //     typeCfg.stringProperty('typeName', 'TypeName')
+            //         .emptyBeanProperty('idMapper', 'IdMapper')
+            //         .emptyBeanProperty('nameMapper', 'NameMapper')
+            //         .emptyBeanProperty('serializer', 'Serializer')
+            //         .intProperty('enum', 'IsEnum');
+            //
+            //     if (typeCfg.nonEmpty())
+            //         typeCfgs.push(typeCfg);
+            // });
+            //
+            // binaryCfg.collectionProperty('types', 'TypeConfigurations', typeCfgs, 'ICollection',
+            //     'Apache.Ignite.Core.Binary.BinaryTypeConfiguration');
+            //
+            // binaryCfg.boolProperty('compactFooter', 'CompactFooter');
+            //
+            // if (binaryCfg.isEmpty())
+            //     return cfg;
+            //
+            // cfg.beanProperty('binaryConfiguration', binaryCfg);
+
+            return cfg;
+        }
+
+        // Generate communication group.
+        static clusterCommunication(cluster, cfg = this.igniteConfigurationBean(cluster)) {
+            const commSpi = new Bean('Apache.Ignite.Core.Communication.Tcp.TcpCommunicationSpi', 'communicationSpi',
+                cluster.communication, clusterDflts.communication);
+
+            commSpi.emptyBeanProperty('listener')
+                .stringProperty('localAddress')
+                .intProperty('localPort')
+                .intProperty('localPortRange')
+                // .intProperty('sharedMemoryPort')
+                .intProperty('directBuffer')
+                .intProperty('directSendBuffer')
+                .intProperty('idleConnectionTimeout')
+                .intProperty('connectTimeout')
+                .intProperty('maxConnectTimeout')
+                .intProperty('reconnectCount')
+                .intProperty('socketSendBuffer')
+                .intProperty('socketReceiveBuffer')
+                .intProperty('messageQueueLimit')
+                .intProperty('slowClientQueueLimit')
+                .intProperty('tcpNoDelay')
+                .intProperty('ackSendThreshold')
+                .intProperty('unacknowledgedMessagesBufferSize')
+                // .intProperty('socketWriteTimeout')
+                .intProperty('selectorsCount');
+                // .emptyBeanProperty('addressResolver');
+
+            if (commSpi.nonEmpty())
+                cfg.beanProperty('CommunicationSpi', commSpi);
+
+            cfg.intProperty('networkTimeout', 'NetworkTimeout')
+                .intProperty('networkSendRetryDelay')
+                .intProperty('networkSendRetryCount');
+                // .intProperty('discoveryStartupDelay');
+
+            return cfg;
+        }
+
+        // Generate discovery group.
+        static clusterDiscovery(discovery, cfg = this.igniteConfigurationBean()) {
+            if (discovery) {
+                let discoveryCfg = cfg.findProperty('discovery');
+
+                if (_.isNil(discoveryCfg)) {
+                    discoveryCfg = new Bean('Apache.Ignite.Core.Discovery.Tcp.TcpDiscoverySpi', 'discovery',
+                        discovery, clusterDflts.discovery);
+                }
+
+                discoveryCfg.stringProperty('localAddress')
+                    .intProperty('localPort')
+                    .intProperty('localPortRange')
+                    .intProperty('socketTimeout')
+                    .intProperty('ackTimeout')
+                    .intProperty('maxAckTimeout')
+                    .intProperty('networkTimeout')
+                    .intProperty('joinTimeout')
+                    .intProperty('threadPriority')
+                    .intProperty('heartbeatFrequency')
+                    .intProperty('maxMissedHeartbeats')
+                    .intProperty('maxMissedClientHeartbeats')
+                    .intProperty('topHistorySize')
+                    .intProperty('reconnectCount')
+                    .intProperty('statisticsPrintFrequency')
+                    .intProperty('ipFinderCleanFrequency')
+                    .intProperty('forceServerMode')
+                    .intProperty('clientReconnectDisabled');
+
+                if (discoveryCfg.nonEmpty())
+                    cfg.beanProperty('discoverySpi', discoveryCfg);
+            }
+
+            return cfg;
+        }
+
+        // Generate events group.
+        static clusterEvents(cluster, cfg = this.igniteConfigurationBean(cluster)) {
+            if (_.nonEmpty(cluster.includeEventTypes))
+                cfg.eventTypes('events', 'includeEventTypes', cluster.includeEventTypes);
+
+            return cfg;
+        }
+
+        // Generate metrics group.
+        static clusterMetrics(cluster, cfg = this.igniteConfigurationBean(cluster)) {
+            cfg.intProperty('metricsExpireTime')
+                .intProperty('metricsHistorySize')
+                .intProperty('metricsLogFrequency')
+                .intProperty('metricsUpdateFrequency');
+
+            return cfg;
+        }
+
+        // Generate transactions group.
+        static clusterTransactions(transactionConfiguration, cfg = this.igniteConfigurationBean()) {
+            const bean = new Bean('Apache.Ignite.Core.Transactions.TransactionConfiguration', 'TransactionConfiguration',
+                transactionConfiguration, clusterDflts.transactionConfiguration);
+
+            bean.enumProperty('defaultTxConcurrency', 'DefaultTransactionConcurrency')
+                .enumProperty('defaultTxIsolation', 'DefaultTransactionIsolation')
+                .intProperty('defaultTxTimeout', 'DefaultTimeout')
+                .intProperty('pessimisticTxLogLinger', 'PessimisticTransactionLogLinger')
+                .intProperty('pessimisticTxLogSize', 'PessimisticTransactionLogSize');
+
+            if (bean.nonEmpty())
+                cfg.beanProperty('transactionConfiguration', bean);
+
+            return cfg;
+        }
+
+        // Generate user attributes group.
+        static clusterUserAttributes(cluster, cfg = this.igniteConfigurationBean(cluster)) {
+            cfg.mapProperty('attributes', 'attributes', 'UserAttributes');
+
+            return cfg;
+        }
+
+        static clusterCaches(cluster, caches, igfss, isSrvCfg, cfg = this.igniteConfigurationBean(cluster)) {
+            // const cfg = this.clusterGeneral(cluster, cfg);
+            //
+            // if (_.nonEmpty(caches)) {
+            //     const ccfgs = _.map(caches, (cache) => this.cacheConfiguration(cache));
+            //
+            //     cfg.collectionProperty('', '', ccfgs, );
+            // }
+
+            return this.clusterGeneral(cluster, cfg);
+        }
+
+        // Generate cache general group.
+        static cacheGeneral(cache, ccfg = this.cacheConfigurationBean(cache)) {
+            ccfg.stringProperty('name')
+                .enumProperty('cacheMode')
+                .enumProperty('atomicityMode');
+
+            if (ccfg.valueOf('cacheMode') === 'PARTITIONED' && ccfg.valueOf('backups')) {
+                ccfg.intProperty('backups')
+                    .intProperty('readFromBackup');
+            }
+
+            ccfg.intProperty('copyOnRead');
+
+            if (ccfg.valueOf('cacheMode') === 'PARTITIONED' && ccfg.valueOf('atomicityMode') === 'TRANSACTIONAL')
+                ccfg.intProperty('invalidate');
+
+            return ccfg;
+        }
+
+        // Generate cache memory group.
+        static cacheMemory(cache, ccfg = this.cacheConfigurationBean(cache)) {
+            ccfg.enumProperty('memoryMode');
+
+            if (ccfg.valueOf('memoryMode') !== 'OFFHEAP_VALUES')
+                ccfg.intProperty('offHeapMaxMemory');
+
+            // this._evictionPolicy(ccfg, 'evictionPolicy', cache.evictionPolicy, cacheDflts.evictionPolicy);
+
+            ccfg.intProperty('startSize')
+                .boolProperty('swapEnabled', 'EnableSwap');
+
+            return ccfg;
+        }
+
+        // Generate cache queries & Indexing group.
+        static cacheQuery(cache, domains, ccfg = this.cacheConfigurationBean(cache)) {
+            ccfg.intProperty('sqlOnheapRowCacheSize')
+                .intProperty('longQueryWarningTimeout');
+
+            return ccfg;
+        }
+
+        // Generate cache store group.
+        static cacheStore(cache, domains, ccfg = this.cacheConfigurationBean(cache)) {
+            const kind = _.get(cache, 'cacheStoreFactory.kind');
+
+            if (kind && cache.cacheStoreFactory[kind]) {
+                let bean = null;
+
+                const storeFactory = cache.cacheStoreFactory[kind];
+
+                switch (kind) {
+                    case 'CacheJdbcPojoStoreFactory':
+                        bean = new Bean('org.apache.ignite.cache.store.jdbc.CacheJdbcPojoStoreFactory', 'cacheStoreFactory',
+                            storeFactory);
+
+                        const id = bean.valueOf('dataSourceBean');
+
+                        bean.dataSource(id, 'dataSourceBean', this.dataSourceBean(id, storeFactory.dialect))
+                            .beanProperty('dialect', new EmptyBean(this.dialectClsName(storeFactory.dialect)));
+
+                        const setType = (typeBean, propName) => {
+                            if (JavaTypes.nonBuiltInClass(typeBean.valueOf(propName)))
+                                typeBean.stringProperty(propName);
+                            else
+                                typeBean.classProperty(propName);
+                        };
+
+                        const types = _.reduce(domains, (acc, domain) => {
+                            if (_.isNil(domain.databaseTable))
+                                return acc;
+
+                            const typeBean = new Bean('org.apache.ignite.cache.store.jdbc.JdbcType', 'type',
+                                _.merge({}, domain, {cacheName: cache.name}))
+                                .stringProperty('cacheName');
+
+                            setType(typeBean, 'keyType');
+                            setType(typeBean, 'valueType');
+
+                            this.domainStore(domain, typeBean);
+
+                            acc.push(typeBean);
+
+                            return acc;
+                        }, []);
+
+                        bean.arrayProperty('types', 'types', types, 'org.apache.ignite.cache.store.jdbc.JdbcType');
+
+                        break;
+                    case 'CacheJdbcBlobStoreFactory':
+                        bean = new Bean('org.apache.ignite.cache.store.jdbc.CacheJdbcBlobStoreFactory', 'cacheStoreFactory',
+                            storeFactory);
+
+                        if (bean.valueOf('connectVia') === 'DataSource')
+                            bean.dataSource(bean.valueOf('dataSourceBean'), 'dataSourceBean', this.dialectClsName(storeFactory.dialect));
+                        else {
+                            ccfg.stringProperty('connectionUrl')
+                                .stringProperty('user')
+                                .property('password', `ds.${storeFactory.user}.password`, 'YOUR_PASSWORD');
+                        }
+
+                        bean.boolProperty('initSchema')
+                            .stringProperty('createTableQuery')
+                            .stringProperty('loadQuery')
+                            .stringProperty('insertQuery')
+                            .stringProperty('updateQuery')
+                            .stringProperty('deleteQuery');
+
+                        break;
+                    case 'CacheHibernateBlobStoreFactory':
+                        bean = new Bean('org.apache.ignite.cache.store.hibernate.CacheHibernateBlobStoreFactory',
+                            'cacheStoreFactory', storeFactory);
+
+                        bean.propsProperty('props', 'hibernateProperties');
+
+                        break;
+                    default:
+                }
+
+                if (bean)
+                    ccfg.beanProperty('cacheStoreFactory', bean);
+            }
+
+            ccfg.boolProperty('storeKeepBinary')
+                .boolProperty('loadPreviousValue')
+                .boolProperty('readThrough')
+                .boolProperty('writeThrough');
+
+            if (ccfg.valueOf('writeBehindEnabled')) {
+                ccfg.boolProperty('writeBehindEnabled')
+                    .intProperty('writeBehindBatchSize')
+                    .intProperty('writeBehindFlushSize')
+                    .intProperty('writeBehindFlushFrequency')
+                    .intProperty('writeBehindFlushThreadCount');
+            }
+
+            return ccfg;
+        }
+
+        // Generate cache concurrency control group.
+        static cacheConcurrency(cache, ccfg = this.cacheConfigurationBean(cache)) {
+            ccfg.intProperty('maxConcurrentAsyncOperations')
+                .intProperty('defaultLockTimeout')
+                .enumProperty('atomicWriteOrderMode')
+                .enumProperty('writeSynchronizationMode');
+
+            return ccfg;
+        }
+
+        // Generate cache node filter group.
+        static cacheNodeFilter(cache, igfss, ccfg = this.cacheConfigurationBean(cache)) {
+            const kind = _.get(cache, 'nodeFilter.kind');
+
+            if (kind && cache.nodeFilter[kind]) {
+                let bean = null;
+
+                switch (kind) {
+                    case 'IGFS':
+                        const foundIgfs = _.find(igfss, (igfs) => igfs._id === cache.nodeFilter.IGFS.igfs);
+
+                        if (foundIgfs) {
+                            bean = new Bean('org.apache.ignite.internal.processors.igfs.IgfsNodePredicate', 'nodeFilter', foundIgfs)
+                                .stringConstructorArgument('name');
+                        }
+
+                        break;
+                    case 'Custom':
+                        bean = new Bean(cache.nodeFilter.Custom.className, 'nodeFilter');
+
+                        break;
+                    default:
+                        return ccfg;
+                }
+
+                if (bean)
+                    ccfg.beanProperty('nodeFilter', bean);
+            }
+
+            return ccfg;
+        }
+
+        // Generate cache rebalance group.
+        static cacheRebalance(cache, ccfg = this.cacheConfigurationBean(cache)) {
+            if (ccfg.valueOf('cacheMode') !== 'LOCAL') {
+                ccfg.enumProperty('rebalanceMode')
+                    .intProperty('rebalanceThreadPoolSize')
+                    .intProperty('rebalanceBatchSize')
+                    .intProperty('rebalanceBatchesPrefetchCount')
+                    .intProperty('rebalanceOrder')
+                    .intProperty('rebalanceDelay')
+                    .intProperty('rebalanceTimeout')
+                    .intProperty('rebalanceThrottle');
+            }
+
+            if (ccfg.includes('igfsAffinnityGroupSize')) {
+                const bean = new Bean('org.apache.ignite.igfs.IgfsGroupDataBlocksKeyMapper', 'affinityMapper', cache)
+                    .intConstructorArgument('igfsAffinnityGroupSize');
+
+                ccfg.beanProperty('affinityMapper', bean);
+            }
+
+            return ccfg;
+        }
+
+        // Generate server near cache group.
+        static cacheServerNearCache(cache, ccfg = this.cacheConfigurationBean(cache)) {
+            if (cache.cacheMode === 'PARTITIONED' && cache.nearCacheEnabled) {
+                const bean = new Bean('org.apache.ignite.configuration.NearCacheConfiguration', 'nearConfiguration',
+                    cache.nearConfiguration, {nearStartSize: 375000});
+
+                bean.intProperty('nearStartSize');
+
+                this._evictionPolicy(bean, 'nearEvictionPolicy',
+                    bean.valueOf('nearEvictionPolicy'), cacheDflts.evictionPolicy);
+
+                ccfg.beanProperty('nearConfiguration', bean);
+            }
+
+            return ccfg;
+        }
+
+        // Generate cache statistics group.
+        static cacheStatistics(cache, ccfg = this.cacheConfigurationBean(cache)) {
+            ccfg.boolProperty('statisticsEnabled')
+                .boolProperty('managementEnabled');
+
+            return ccfg;
+        }
+
+        static cacheConfiguration(cache, ccfg = this.cacheConfigurationBean(cache)) {
+            this.cacheGeneral(cache, ccfg);
+            this.cacheMemory(cache, ccfg);
+            this.cacheQuery(cache, cache.domains, ccfg);
+            this.cacheStore(cache, cache.domains, ccfg);
+
+            const igfs = _.get(cache, 'nodeFilter.IGFS.instance');
+            this.cacheNodeFilter(cache, igfs ? [igfs] : [], ccfg);
+            this.cacheConcurrency(cache, ccfg);
+            this.cacheRebalance(cache, ccfg);
+            this.cacheServerNearCache(cache, ccfg);
+            this.cacheStatistics(cache, ccfg);
+            // this.cacheDomains(cache.domains, cfg);
+
+            return ccfg;
+        }
+    }
+
+    return PlatformGenerator;
+}];