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;
+}];