Return-Path: X-Original-To: archive-asf-public-internal@cust-asf2.ponee.io Delivered-To: archive-asf-public-internal@cust-asf2.ponee.io Received: from cust-asf.ponee.io (cust-asf.ponee.io [163.172.22.183]) by cust-asf2.ponee.io (Postfix) with ESMTP id E402E200C17 for ; Thu, 5 Jan 2017 10:23:38 +0100 (CET) Received: by cust-asf.ponee.io (Postfix) id E2AB0160B26; Thu, 5 Jan 2017 09:23:38 +0000 (UTC) Delivered-To: archive-asf-public@cust-asf.ponee.io Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by cust-asf.ponee.io (Postfix) with SMTP id 7A76D160B50 for ; Thu, 5 Jan 2017 10:23:35 +0100 (CET) Received: (qmail 61278 invoked by uid 500); 5 Jan 2017 09:23:34 -0000 Mailing-List: contact commits-help@ignite.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@ignite.apache.org Delivered-To: mailing list commits@ignite.apache.org Received: (qmail 61023 invoked by uid 99); 5 Jan 2017 09:23:34 -0000 Received: from git1-us-west.apache.org (HELO git1-us-west.apache.org) (140.211.11.23) by apache.org (qpsmtpd/0.29) with ESMTP; Thu, 05 Jan 2017 09:23:34 +0000 Received: by git1-us-west.apache.org (ASF Mail Server at git1-us-west.apache.org, from userid 33) id 69440DFE94; Thu, 5 Jan 2017 09:23:34 +0000 (UTC) Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit From: vozerov@apache.org To: commits@ignite.apache.org Date: Thu, 05 Jan 2017 09:23:46 -0000 Message-Id: In-Reply-To: <3128adad3ae64e69b405c9e4a0697c83@git.apache.org> References: <3128adad3ae64e69b405c9e4a0697c83@git.apache.org> X-Mailer: ASF-Git Admin Mailer Subject: [13/37] ignite git commit: Web console beta-7. archived-at: Thu, 05 Jan 2017 09:23:39 -0000 http://git-wip-us.apache.org/repos/asf/ignite/blob/2b3a180f/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 index b123ab5..9590779 100644 --- a/modules/web-console/frontend/app/modules/configuration/generator/JavaTransformer.service.js +++ b/modules/web-console/frontend/app/modules/configuration/generator/JavaTransformer.service.js @@ -158,7 +158,7 @@ const PREDEFINED_QUERIES = [ ]; // Var name generator function. -const beenNameSeed = () => { +const beanNameSeed = () => { let idx = ''; const names = []; @@ -174,1551 +174,1577 @@ const beenNameSeed = () => { }; }; -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.' - ]; +export default class IgniteJavaTransformer extends AbstractTransformer { + // Mapping for objects to method call. + static METHOD_MAPPING = { + 'org.apache.ignite.configuration.CacheConfiguration': { + prefix: 'cache', + name: 'name', + args: '', + generator: (sb, id, ccfg) => { + const cacheName = ccfg.findProperty('name').value; + const dataSources = IgniteJavaTransformer.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.'); + 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' : ''} {`); + IgniteJavaTransformer.commentBlock(sb, ...javadoc); + sb.startBlock(`public static CacheConfiguration ${id}()${dataSources.length ? ' throws Exception' : ''} {`); - JavaTransformer.constructBean(sb, ccfg, [], true); + IgniteJavaTransformer.constructBean(sb, ccfg, [], true); - sb.emptyLine(); - sb.append(`return ${ccfg.id};`); + sb.emptyLine(); + sb.append(`return ${ccfg.id};`); - sb.endBlock('}'); + 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.' - ]; + return sb; + } + }, + 'org.apache.ignite.cache.store.jdbc.JdbcType': { + prefix: 'jdbcType', + name: 'valueType', + 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) {`); + IgniteJavaTransformer.commentBlock(sb, ...javadoc); + sb.startBlock(`private static JdbcType ${name}(String cacheName) {`); - const cacheName = jdbcType.findProperty('cacheName'); + const cacheName = jdbcType.findProperty('cacheName'); - cacheName.clsName = 'var'; - cacheName.value = 'cacheName'; + cacheName.clsName = 'var'; + cacheName.value = 'cacheName'; - JavaTransformer.constructBean(sb, jdbcType); + IgniteJavaTransformer.constructBean(sb, jdbcType); - sb.emptyLine(); - sb.append(`return ${jdbcType.id};`); + sb.emptyLine(); + sb.append(`return ${jdbcType.id};`); - sb.endBlock('}'); + sb.endBlock('}'); - return sb; - } + 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('/**'); + // Append comment line. + static comment(sb, ...lines) { + _.forEach(lines, (line) => sb.append(`// ${line}`)); + } - _.forEach(lines, (line) => sb.append(` * ${line}`)); + // Append comment block. + static commentBlock(sb, ...lines) { + if (lines.length === 1) + sb.append(`/** ${_.head(lines)} **/`); + else { + sb.append('/**'); - 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); - } - }); + /** + * @param {Bean} bean + */ + static _newBean(bean) { + const shortClsName = this.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(', ')})`; + if (bean.factoryMtd) + return `${shortClsName}.${bean.factoryMtd}(${args.join(', ')})`; - return `new ${shortClsName}(${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 {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.} 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); + /** + * @param {StringBuilder} sb + * @param {Array.} 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(); + sb.emptyLine(); - break; - default: - if (this._isBean(arg.clsName) && arg.value.isComplex()) { - this.constructBean(sb, arg.value, vars, limitLines); + break; + default: + if (this._isBean(arg.clsName) && arg.value.isComplex()) { + this.constructBean(sb, arg.value, vars, limitLines); - sb.emptyLine(); - } - } - }); + sb.emptyLine(); + } + } + }); - const clsName = JavaTypes.shortClassName(bean.clsName); + const clsName = this.javaTypes.shortClassName(bean.clsName); - sb.append(`${this.varInit(clsName, id, vars)} = ${this._newBean(bean)};`); + sb.append(`${this.varInit(clsName, id, vars)} = ${this._newBean(bean)};`); - if (_.nonEmpty(bean.properties)) { - sb.emptyLine(); + if (_.nonEmpty(bean.properties)) { + sb.emptyLine(); - this._setProperties(sb, bean, vars, limitLines, id); - } + this._setProperties(sb, bean, vars, limitLines, id); } + } - /** - * @param {StringBuilder} sb - * @param {Bean} bean - * @param {Array.} 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(); + /** + * @param {StringBuilder} sb + * @param {Bean} bean + * @param {Array.} vars + * @param {Boolean} limitLines + * @private + */ + static constructStoreFactory(sb, bean, vars, limitLines = false) { + const shortClsName = this.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.startBlock(`${bean.id}.setDataSourceFactory(new Factory() {`); - this.commentBlock(sb, '{@inheritDoc}'); - sb.startBlock('@Override public DataSource create() {'); + sb.emptyLine(); - sb.append(`return DataSources.INSTANCE_${bean.findProperty('dataSourceBean').id};`); + sb.startBlock(`${bean.id}.setDataSourceFactory(new Factory() {`); + this.commentBlock(sb, '{@inheritDoc}'); + sb.startBlock('@Override public DataSource create() {'); - sb.endBlock('};'); - sb.endBlock('});'); + sb.append(`return DataSources.INSTANCE_${bean.findProperty('dataSourceBean').id};`); - const storeFactory = _.cloneDeep(bean); + sb.endBlock('};'); + sb.endBlock('});'); - _.remove(storeFactory.properties, (p) => _.includes(['dataSourceBean'], p.name)); + const storeFactory = _.cloneDeep(bean); - if (storeFactory.properties.length) { - sb.emptyLine(); + _.remove(storeFactory.properties, (p) => _.includes(['dataSourceBean'], p.name)); - this._setProperties(sb, storeFactory, vars, limitLines); - } - } + if (storeFactory.properties.length) { + sb.emptyLine(); - static _isBean(clsName) { - return JavaTypes.nonBuiltInClass(clsName) && JavaTypes.nonEnum(clsName) && _.includes(clsName, '.'); + this._setProperties(sb, storeFactory, vars, limitLines); } + } - static _toObject(clsName, val) { - const items = _.isArray(val) ? val : [val]; + static _isBean(clsName) { + return this.javaTypes.nonBuiltInClass(clsName) && this.javaTypes.nonEnum(clsName) && _.includes(clsName, '.'); + } - return _.map(items, (item) => { - if (_.isNil(item)) - return 'null'; + 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.replace(/\\/g, '\\\\').replace(/"/g, '\\"')}"`; + case 'PATH': + return `"${item.replace(/\\/g, '\\\\')}"`; + case 'java.lang.Class': + return `${this.javaTypes.shortClassName(item)}.class`; + case 'java.util.UUID': + return `UUID.fromString("${item}")`; + case 'PROPERTY': + return `props.getProperty("${item}")`; + case 'PROPERTY_CHAR': + return `props.getProperty("${item}").toCharArray()`; + case 'PROPERTY_INT': + return `Integer.parseInt(props.getProperty("${item}"))`; + default: + if (this._isBean(clsName)) { + if (item.isComplex()) + return item.id; + + return this._newBean(item); + } - switch (clsName) { - case 'var': + if (this.javaTypes.nonEnum(clsName)) 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.replace(/\\/g, '\\\\').replace(/"/g, '\\"')}"`; - 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': - return `props.getProperty("${item}")`; - case 'PROPERTY_CHAR': - return `props.getProperty("${item}").toCharArray()`; - case 'PROPERTY_INT': - return `Integer.parseInt(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}`; - } - }); - } + return `${this.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]; + static _mapperId(mapper) { + return (item) => this.javaTypes.toJavaName(mapper.prefix, item.findProperty(mapper.name).value); + } - const nextId = mapper ? mapper.id : beenNameSeed(); + 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]; - // Prepare objects refs. - return _.map(items, (item) => { - if (limitLines && mapper) - return mapper.id(item) + (limitLines ? `(${mapper.args})` : ''); + const nextId = mapper ? this._mapperId(mapper) : beanNameSeed(); - if (item.isComplex()) { - const id = nextId(item); + // Prepare objects refs. + return _.map(items, (item) => { + if (limitLines && mapper) + return nextId(item) + (limitLines ? `(${mapper.args})` : ''); - this.constructBean(sb, item, vars, limitLines, id); + if (item.isComplex()) { + const id = nextId(item); - sb.emptyLine(); + this.constructBean(sb, item, vars, limitLines, id); - return id; - } + sb.emptyLine(); - return this._newBean(item); - }); - } + return id; + } - return this._toObject(type, items); + return this._newBean(item); + }); } - /** - * - * @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 ? ',' : '')); - }); + return this._toObject(type, items); + } - sb.endBlock(');'); - } + /** + * + * @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); + /** + * + * @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); + const arrType = this.javaTypes.shortClassName(arrProp.typeClsName); - // Set refs to property. - sb.startBlock(`${parentId}.set${_.upperFirst(arrProp.name)}(new ${arrType}[] {`); + // Set refs to property. + sb.startBlock(`${parentId}.set${_.upperFirst(arrProp.name)}(new ${arrType}[] {`); - const lastIdx = refs.length - 1; + const lastIdx = refs.length - 1; - _.forEach(refs, (ref, idx) => sb.append(ref + (lastIdx !== idx ? ',' : ''))); + _.forEach(refs, (ref, idx) => sb.append(ref + (lastIdx !== idx ? ',' : ''))); - sb.endBlock('});'); - } + sb.endBlock('});'); + } - static _constructMap(sb, map, vars = []) { - const keyClsName = JavaTypes.shortClassName(map.keyClsName); - const valClsName = JavaTypes.shortClassName(map.valClsName); + static _constructMap(sb, map, vars = []) { + const keyClsName = this.javaTypes.shortClassName(map.keyClsName); + const valClsName = this.javaTypes.shortClassName(map.valClsName); - const mapClsName = map.ordered ? 'LinkedHashMap' : 'HashMap'; + const mapClsName = map.ordered ? 'LinkedHashMap' : 'HashMap'; - const type = `${mapClsName}<${keyClsName}, ${valClsName}>`; + const type = `${mapClsName}<${keyClsName}, ${valClsName}>`; - sb.append(`${this.varInit(type, map.id, vars)} = new ${mapClsName}<>();`); + sb.append(`${this.varInit(type, map.id, vars)} = new ${mapClsName}<>();`); - sb.emptyLine(); + sb.emptyLine(); - _.forEach(map.entries, (entry) => { - const key = this._toObject(map.keyClsName, entry[map.keyField]); - const val = entry[map.valField]; + _.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},`); + 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 ? ' +' : ''}`); - }); + _.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))});`); + sb.endBlock(');'); } else - sb.append(`${map.id}.put(${key}, ${this._toObject(map.valClsName, val)});`); - }); - } + 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; + static varInit(type, id, vars) { + if (_.includes(vars, id)) + return id; - vars.push(id); + vars.push(id); - return `${type} ${id}`; - } + return `${type} ${id}`; + } - /** - * - * @param {StringBuilder} sb - * @param {Bean} bean - * @param {String} id - * @param {Array.} 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`); + /** + * + * @param {StringBuilder} sb + * @param {Bean} bean + * @param {String} id + * @param {Array.} 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`); + }); - _.forEach(_.tail(prop.eventTypes), (evtGrp) => { - sb.append(` + ${evtGrp}.length`); - }); + sb.append('];'); - sb.append('];'); + sb.emptyLine(); + sb.append('int k = 0;'); + + _.forEach(prop.eventTypes, (evtGrp, evtIdx) => { sb.emptyLine(); - sb.append('int k = 0;'); + sb.append(`System.arraycopy(${evtGrp}, 0, ${prop.id}, k, ${evtGrp}.length);`); - _.forEach(prop.eventTypes, (evtGrp, evtIdx) => { - sb.emptyLine(); + if (evtIdx < prop.eventTypes.length - 1) + sb.append(`k += ${evtGrp}.length;`); + }); - sb.append(`System.arraycopy(${evtGrp}, 0, ${prop.id}, k, ${evtGrp}.length);`); + sb.emptyLine(); - if (evtIdx < prop.eventTypes.length - 1) - sb.append(`k += ${evtGrp}.length;`); - }); + sb.append(`cfg.setIncludeEventTypes(${prop.id});`); + } - sb.emptyLine(); + break; + case 'ARRAY': + if (prop.varArg) + this._setVarArg(sb, id, prop, vars, limitLines); + else + this._setArray(sb, id, prop, vars, limitLines); - sb.append(`cfg.setIncludeEventTypes(${prop.id});`); - } + break; + case 'COLLECTION': + const nonBean = !this._isBean(prop.typeClsName); - break; - case 'ARRAY': - if (prop.varArg) - this._setVarArg(sb, id, prop, vars, limitLines); - else - this._setArray(sb, id, prop, vars, limitLines); + if (nonBean && prop.implClsName === 'java.util.ArrayList') { + const items = _.map(prop.items, (item) => this._toObject(prop.typeClsName, item)); - break; - case 'COLLECTION': - const nonBean = !this._isBean(prop.typeClsName); + if (items.length > 1) { + sb.startBlock(`${id}.set${_.upperFirst(prop.name)}(Arrays.asList(`); - if (nonBean && prop.implClsName === 'java.util.ArrayList') { - const items = _.map(prop.items, (item) => this._toObject(prop.typeClsName, item)); + _.forEach(items, (item, i) => sb.append(item + (i !== items.length - 1 ? ',' : ''))); - if (items.length > 1) { - sb.startBlock(`${id}.set${_.upperFirst(prop.name)}(Arrays.asList(`); + sb.endBlock('));'); + } + else + this._setProperty(sb, id, prop.name, `Arrays.asList(${items})`); + } + else { + const colTypeClsName = this.javaTypes.shortClassName(prop.typeClsName); + const implClsName = this.javaTypes.shortClassName(prop.implClsName); - _.forEach(items, (item, i) => sb.append(item + (i !== items.length - 1 ? ',' : ''))); + sb.append(`${this.varInit(`${implClsName}<${colTypeClsName}>`, prop.id, vars)} = new ${implClsName}<>();`); - sb.endBlock('));'); - } - else - this._setProperty(sb, id, prop.name, `Arrays.asList(${items})`); + sb.emptyLine(); + + if (nonBean) { + _.forEach(this._toObject(colTypeClsName, prop.items), (item) => { + sb.append(`${prop.id}.add("${item}");`); + + sb.emptyLine(); + }); } else { - const colTypeClsName = JavaTypes.shortClassName(prop.typeClsName); - const implClsName = JavaTypes.shortClassName(prop.implClsName); + _.forEach(prop.items, (item) => { + this.constructBean(sb, item, vars, limitLines); - sb.append(`${this.varInit(`${implClsName}<${colTypeClsName}>`, prop.id, vars)} = new ${implClsName}<>();`); + sb.append(`${prop.id}.add(${item.id});`); - sb.emptyLine(); + sb.emptyLine(); + }); + } - if (nonBean) { - _.forEach(this._toObject(colTypeClsName, prop.items), (item) => { - sb.append(`${prop.id}.add("${item}");`); + this._setProperty(sb, id, prop.name, prop.id); + } - sb.emptyLine(); - }); - } - else { - _.forEach(prop.items, (item) => { - this.constructBean(sb, item, vars, limitLines); + break; + case 'MAP': + this._constructMap(sb, prop, vars); - sb.append(`${prop.id}.add(${item.id});`); + if (_.nonEmpty(prop.entries)) + sb.emptyLine(); - sb.emptyLine(); - }); - } + this._setProperty(sb, id, prop.name, prop.id); - this._setProperty(sb, id, prop.name, prop.id); - } + break; + case 'java.util.Properties': + sb.append(`${this.varInit('Properties', prop.id, vars)} = new Properties();`); - break; - case 'MAP': - this._constructMap(sb, prop, vars); + if (_.nonEmpty(prop.entries)) + sb.emptyLine(); - 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); - this._setProperty(sb, id, prop.name, prop.id); + sb.append(`${prop.id}.setProperty(${key}, ${val});`); + }); - break; - case 'java.util.Properties': - sb.append(`${this.varInit('Properties', prop.id, vars)} = new Properties();`); + sb.emptyLine(); - if (_.nonEmpty(prop.entries)) - sb.emptyLine(); + this._setProperty(sb, id, prop.name, prop.id); - _.forEach(prop.entries, (entry) => { - const key = this._toObject('java.lang.String', entry.name); - const val = this._toObject('java.lang.String', entry.value); + break; + case 'BEAN': + const embedded = prop.value; - sb.append(`${prop.id}.setProperty(${key}, ${val});`); - }); + if (_.includes(STORE_FACTORY, embedded.clsName)) { + this.constructStoreFactory(sb, embedded, vars, limitLines); sb.emptyLine(); - this._setProperty(sb, id, prop.name, prop.id); + this._setProperty(sb, id, prop.name, embedded.id); + } + else if (embedded.isComplex()) { + this.constructBean(sb, embedded, vars, limitLines); - break; - case 'BEAN': - const embedded = prop.value; + sb.emptyLine(); - if (_.includes(STORE_FACTORY, embedded.clsName)) { - this.constructStoreFactory(sb, embedded, vars, limitLines); + this._setProperty(sb, id, prop.name, embedded.id); + } + else + this._setProperty(sb, id, prop.name, this._newBean(embedded)); - sb.emptyLine(); + break; + default: + this._setProperty(sb, id, prop.name, this._toObject(prop.clsName, prop.value)); + } - this._setProperty(sb, id, prop.name, embedded.id); - } - else if (embedded.isComplex()) { - this.constructBean(sb, embedded, vars, limitLines); + this._emptyLineIfNeeded(sb, bean.properties, idx); + }); - sb.emptyLine(); + return sb; + } - this._setProperty(sb, id, prop.name, embedded.id); - } - else - this._setProperty(sb, id, prop.name, this._newBean(embedded)); + static _collectMapImports(prop) { + const imports = []; - break; - default: - this._setProperty(sb, id, prop.name, this._toObject(prop.clsName, prop.value)); - } + imports.push(prop.ordered ? 'java.util.LinkedHashMap' : 'java.util.HashMap'); + imports.push(prop.keyClsName); + imports.push(prop.valClsName); - this._emptyLineIfNeeded(sb, bean.properties, idx); - }); + return imports; + } - return sb; - } + static collectBeanImports(bean) { + const imports = [bean.clsName]; - static collectBeanImports(bean) { - const imports = [bean.clsName]; + _.forEach(bean.arguments, (arg) => { + switch (arg.clsName) { + case 'BEAN': + imports.push(...this.collectPropertiesImports(arg.value.properties)); - _.forEach(bean.arguments, (arg) => { - switch (arg.clsName) { - case 'BEAN': - imports.push(...this.collectPropertiesImports(arg.value.properties)); + break; + case 'java.lang.Class': + imports.push(this.javaTypes.fullClassName(arg.value)); - break; - case 'java.lang.Class': - imports.push(JavaTypes.fullClassName(arg.value)); + break; - break; - default: - imports.push(arg.clsName); - } - }); + case 'MAP': + imports.push(...this._collectMapImports(arg)); - imports.push(...this.collectPropertiesImports(bean.properties)); + break; + default: + imports.push(arg.clsName); + } + }); - if (_.includes(STORE_FACTORY, bean.clsName)) - imports.push('javax.sql.DataSource', 'javax.cache.configuration.Factory'); + imports.push(...this.collectPropertiesImports(bean.properties)); - return imports; - } + if (_.includes(STORE_FACTORY, bean.clsName)) + imports.push('javax.sql.DataSource', 'javax.cache.configuration.Factory'); - /** - * @param {Array.} props - * @returns {Array.} - */ - static collectPropertiesImports(props) { - const imports = []; + return imports; + } - _.forEach(props, (prop) => { - switch (prop.clsName) { - case 'DATA_SOURCE': - imports.push(prop.value.clsName); + /** + * @param {Array.} props + * @returns {Array.} + */ + static collectPropertiesImports(props) { + const imports = []; - break; - case 'PROPERTY': - case 'PROPERTY_CHAR': - case 'PROPERTY_INT': - imports.push('java.io.InputStream', 'java.util.Properties'); + _.forEach(props, (prop) => { + switch (prop.clsName) { + case 'DATA_SOURCE': + imports.push(prop.value.clsName); - break; - case 'BEAN': - imports.push(...this.collectBeanImports(prop.value)); + break; + case 'PROPERTY': + case 'PROPERTY_CHAR': + case 'PROPERTY_INT': + imports.push('java.io.InputStream', 'java.util.Properties'); - break; - case 'ARRAY': - imports.push(prop.typeClsName); + break; + case 'BEAN': + imports.push(...this.collectBeanImports(prop.value)); - if (this._isBean(prop.typeClsName)) - _.forEach(prop.items, (item) => imports.push(...this.collectBeanImports(item))); + break; + case 'ARRAY': + imports.push(prop.typeClsName); - break; - case 'COLLECTION': - imports.push(prop.typeClsName); + if (this._isBean(prop.typeClsName)) + _.forEach(prop.items, (item) => imports.push(...this.collectBeanImports(item))); - if (this._isBean(prop.typeClsName)) { - _.forEach(prop.items, (item) => imports.push(...this.collectBeanImports(item))); + break; + case 'COLLECTION': + imports.push(prop.typeClsName); - 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); - } - }); + if (this._isBean(prop.typeClsName)) { + _.forEach(prop.items, (item) => imports.push(...this.collectBeanImports(item))); - return imports; - } + imports.push(prop.implClsName); + } + else if (prop.implClsName === 'java.util.ArrayList') + imports.push('java.util.Arrays'); + else + imports.push(prop.implClsName); - static _prepareImports(imports) { - return _.sortedUniq(_.sortBy(_.filter(imports, (cls) => !cls.startsWith('java.lang.') && _.includes(cls, '.')))); - } + break; + case 'MAP': + imports.push(...this._collectMapImports(prop)); - /** - * @param {Bean} bean - * @returns {Array.} - */ - static collectStaticImports(bean) { - const imports = []; + break; + default: + if (!this.javaTypes.nonEnum(prop.clsName)) + imports.push(prop.clsName); + } + }); - _.forEach(bean.properties, (prop) => { - switch (prop.clsName) { - case 'EVENT_TYPES': - _.forEach(prop.eventTypes, (value) => { - const evtGrp = _.find(eventGroups, {value}); + return imports; + } - imports.push(`${evtGrp.class}.${evtGrp.value}`); - }); + static _prepareImports(imports) { + return _.sortedUniq(_.sortBy(_.filter(imports, (cls) => !cls.startsWith('java.lang.') && _.includes(cls, '.')))); + } - break; - default: - // No-op. - } - }); + /** + * @param {Bean} bean + * @returns {Array.} + */ + static collectStaticImports(bean) { + const imports = []; - return imports; - } + _.forEach(bean.properties, (prop) => { + switch (prop.clsName) { + case 'EVENT_TYPES': + _.forEach(prop.eventTypes, (value) => { + const evtGrp = _.find(this.eventGroups, {value}); - /** - * @param {Bean} bean - * @returns {Object} - */ - static collectBeansWithMapping(bean) { - const beans = {}; + imports.push(`${evtGrp.class}.${evtGrp.value}`); + }); - _.forEach(bean.properties, (prop) => { - switch (prop.clsName) { - case 'BEAN': - _.merge(beans, this.collectBeansWithMapping(prop.value)); + break; + default: + // No-op. + } + }); - break; - case 'ARRAY': - if (this._isBean(prop.typeClsName)) { - const mapping = this.METHOD_MAPPING[prop.typeClsName]; + return imports; + } - _.reduce(prop.items, (acc, item) => { - if (mapping) { - acc[mapping.id(item)] = item; + /** + * @param {Bean} bean + * @returns {Object} + */ + static collectBeansWithMapping(bean) { + const beans = {}; - _.merge(acc, this.collectBeansWithMapping(item)); - } - return acc; - }, beans); - } + _.forEach(bean.properties, (prop) => { + switch (prop.clsName) { + case 'BEAN': + _.merge(beans, this.collectBeansWithMapping(prop.value)); - break; - default: - // No-op. - } - }); + break; + case 'ARRAY': + if (this._isBean(prop.typeClsName)) { + const mapper = this.METHOD_MAPPING[prop.typeClsName]; - return beans; - } + const mapperId = mapper ? this._mapperId(mapper) : null; - /** - * 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.} clientNearCaches Is client node. - * @returns {StringBuilder} - */ - static igniteConfiguration(cfg, pkg, clsName, clientNearCaches) { - const sb = new StringBuilder(); - - sb.append(`package ${pkg};`); - sb.emptyLine(); + _.reduce(prop.items, (acc, item) => { + if (mapperId) + acc[mapperId(item)] = item; - const imports = this.collectBeanImports(cfg); + _.merge(acc, this.collectBeansWithMapping(item)); - if (_.nonEmpty(clientNearCaches)) - imports.push('org.apache.ignite.configuration.NearCacheConfiguration'); + return acc; + }, beans); + } - if (_.includes(imports, 'oracle.jdbc.pool.OracleDataSource')) - imports.push('java.sql.SQLException'); + break; + default: + // No-op. + } + }); - const hasProps = this.hasProperties(cfg); + return beans; + } - if (hasProps) - imports.push('java.util.Properties', 'java.io.InputStream'); + /** + * 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.} clientNearCaches Is client node. + * @returns {StringBuilder} + */ + static igniteConfiguration(cfg, pkg, clsName, clientNearCaches) { + const sb = new StringBuilder(); - _.forEach(this._prepareImports(imports), (cls) => sb.append(`import ${cls};`)); + sb.append(`package ${pkg};`); + sb.emptyLine(); - sb.emptyLine(); + const imports = this.collectBeanImports(cfg); - const staticImports = this._prepareImports(this.collectStaticImports(cfg)); + const nearCacheBeans = []; - if (staticImports.length) { - _.forEach(this._prepareImports(staticImports), (cls) => sb.append(`import static ${cls};`)); + if (_.nonEmpty(clientNearCaches)) { + imports.push('org.apache.ignite.configuration.NearCacheConfiguration'); - sb.emptyLine(); - } + _.forEach(clientNearCaches, (cache) => { + const nearCacheBean = this.generator.cacheNearClient(cache); - this.mainComment(sb); - sb.startBlock(`public class ${clsName} {`); + nearCacheBean.cacheName = cache.name; - // 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(); - } + imports.push(...this.collectBeanImports(nearCacheBean)); - // 3. Add data sources. - const dataSources = this.collectDataSources(cfg); + nearCacheBeans.push(nearCacheBean); + }); + } - if (dataSources.length) { - this.commentBlock(sb, 'Helper class for datasource creation.'); - sb.startBlock('public static class DataSources {'); + if (_.includes(imports, 'oracle.jdbc.pool.OracleDataSource')) + imports.push('java.sql.SQLException'); - _.forEach(dataSources, (ds, idx) => { - const dsClsName = JavaTypes.shortClassName(ds.clsName); + const hasProps = this.hasProperties(cfg); - if (idx !== 0) - sb.emptyLine(); + if (hasProps) + imports.push('java.util.Properties', 'java.io.InputStream'); - sb.append(`public static final ${dsClsName} INSTANCE_${ds.id} = create${ds.id}();`); - sb.emptyLine(); + _.forEach(this._prepareImports(imports), (cls) => sb.append(`import ${cls};`)); - sb.startBlock(`private static ${dsClsName} create${ds.id}() {`); + sb.emptyLine(); - if (dsClsName === 'OracleDataSource') - sb.startBlock('try {'); + const staticImports = this._prepareImports(this.collectStaticImports(cfg)); - this.constructBean(sb, ds); + if (staticImports.length) { + _.forEach(this._prepareImports(staticImports), (cls) => sb.append(`import static ${cls};`)); - sb.emptyLine(); - sb.append(`return ${ds.id};`); + sb.emptyLine(); + } - if (dsClsName === 'OracleDataSource') { - sb.endBlock('}'); - sb.startBlock('catch (SQLException ex) {'); - sb.append('throw new Error(ex);'); - sb.endBlock('}'); - } + this.mainComment(sb); + sb.startBlock(`public class ${clsName} {`); - sb.endBlock('}'); - }); + // 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(); + } - sb.endBlock('}'); + // 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 = this.javaTypes.shortClassName(ds.clsName); + if (idx !== 0) + sb.emptyLine(); + + sb.append(`public static final ${dsClsName} INSTANCE_${ds.id} = create${ds.id}();`); 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.' - ); + sb.startBlock(`private static ${dsClsName} create${ds.id}() {`); - const nearCacheBean = generator.cacheNearClient(cache); + if (dsClsName === 'OracleDataSource') + sb.startBlock('try {'); - sb.startBlock(`public static NearCacheConfiguration ${nearCacheBean.id}() throws Exception {`); + this.constructBean(sb, ds); - this.constructBean(sb, nearCacheBean); sb.emptyLine(); + sb.append(`return ${ds.id};`); - sb.append(`return ${nearCacheBean.id};`); - sb.endBlock('}'); + if (dsClsName === 'OracleDataSource') { + sb.endBlock('}'); + sb.startBlock('catch (SQLException ex) {'); + sb.append('throw new Error(ex);'); + sb.endBlock('}'); + } - sb.emptyLine(); + sb.endBlock('}'); }); - this.commentBlock(sb, 'Configure grid.', + sb.endBlock('}'); + + sb.emptyLine(); + } + + _.forEach(nearCacheBeans, (nearCacheBean) => { + this.commentBlock(sb, `Configuration of near cache for cache: ${nearCacheBean.cacheName}.`, '', - '@return Ignite configuration.', - '@throws Exception If failed to construct Ignite configuration instance.' + '@return Near cache configuration.', + '@throws Exception If failed to construct near cache configuration instance.' ); - sb.startBlock('public static IgniteConfiguration createConfiguration() throws Exception {'); - this.constructBean(sb, cfg, [], true); + sb.startBlock(`public static NearCacheConfiguration ${nearCacheBean.id}() throws Exception {`); + this.constructBean(sb, nearCacheBean); sb.emptyLine(); - sb.append(`return ${cfg.id};`); - + sb.append(`return ${nearCacheBean.id};`); sb.endBlock('}'); - const beans = this.collectBeansWithMapping(cfg); + sb.emptyLine(); + }); - _.forEach(beans, (bean, id) => { - 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.METHOD_MAPPING[bean.clsName].generator(sb, id, bean); - }); + this.constructBean(sb, cfg, [], true); - sb.endBlock('}'); + sb.emptyLine(); - return sb; - } + sb.append(`return ${cfg.id};`); - static cluster(cluster, pkg, clsName, client) { - const cfg = this.generator.igniteConfiguration(cluster, client); + sb.endBlock('}'); - const clientNearCaches = client ? _.filter(cluster.caches, (cache) => _.get(cache, 'clientNearConfiguration.enabled')) : []; + const beans = this.collectBeansWithMapping(cfg); - 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('.'); + _.forEach(beans, (bean, id) => { + sb.emptyLine(); - const pkg = fullClsName.substring(0, dotIdx); - const clsName = fullClsName.substring(dotIdx + 1); + this.METHOD_MAPPING[bean.clsName].generator(sb, id, bean); + }); - const sb = new StringBuilder(); + sb.endBlock('}'); - sb.append(`package ${pkg};`); - sb.emptyLine(); - - const imports = ['java.io.Serializable']; + return sb; + } - _.forEach(fields, (field) => imports.push(JavaTypes.fullClassName(field.javaFieldType))); + static cluster(cluster, pkg, clsName, client) { + const cfg = this.generator.igniteConfiguration(cluster, client); - _.forEach(this._prepareImports(imports), (cls) => sb.append(`import ${cls};`)); + const clientNearCaches = client ? _.filter(cluster.caches, (cache) => _.get(cache, 'clientNearConfiguration.enabled')) : []; - sb.emptyLine(); + return this.igniteConfiguration(cfg, pkg, clsName, clientNearCaches); + } - 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 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('.'); - // Generate fields declaration. - _.forEach(fields, (field) => { - const fldName = field.javaFieldName; - const fldType = JavaTypes.shortClassName(field.javaFieldType); + const pkg = fullClsName.substring(0, dotIdx); + const clsName = fullClsName.substring(dotIdx + 1); - sb.append(`/** Value for ${fldName}. */`); - sb.append(`private ${fldType} ${fldName};`); + const sb = new StringBuilder(); - sb.emptyLine(); - }); + sb.append(`package ${pkg};`); + sb.emptyLine(); - // Generate constructors. - if (addConstructor) { - this.commentBlock(sb, 'Empty constructor.'); - sb.startBlock(`public ${clsName}() {`); - this.comment(sb, 'No-op.'); - sb.endBlock('}'); + const imports = ['java.io.Serializable']; - sb.emptyLine(); + _.forEach(fields, (field) => imports.push(this.javaTypes.fullClassName(field.javaFieldType))); - this.commentBlock(sb, 'Full constructor.'); + _.forEach(this._prepareImports(imports), (cls) => sb.append(`import ${cls};`)); - const arg = (field) => { - const fldType = JavaTypes.shortClassName(field.javaFieldType); + sb.emptyLine(); - return `${fldType} ${field.javaFieldName}`; - }; + this.mainComment(sb, + `${clsName} definition.`, + '' + ); + sb.startBlock(`public class ${clsName} implements Serializable {`); + sb.append('/** */'); + sb.append('private static final long serialVersionUID = 0L;'); + sb.emptyLine(); - sb.startBlock(`public ${clsName}(${arg(_.head(fields))}${fields.length === 1 ? ') {' : ','}`); + // Generate fields declaration. + _.forEach(fields, (field) => { + const fldName = field.javaFieldName; + const fldType = this.javaTypes.shortClassName(field.javaFieldType); - _.forEach(_.tail(fields), (field, idx) => { - sb.append(`${arg(field)}${idx !== fields.length - 2 ? ',' : ') {'}`); - }); + sb.append(`/** Value for ${fldName}. */`); + sb.append(`private ${fldType} ${fldName};`); - _.forEach(fields, (field) => sb.append(`this.${field.javaFieldName} = ${field.javaFieldName};`)); + sb.emptyLine(); + }); - sb.endBlock('}'); + // Generate constructors. + if (addConstructor) { + this.commentBlock(sb, 'Empty constructor.'); + sb.startBlock(`public ${clsName}() {`); + this.comment(sb, 'No-op.'); + sb.endBlock('}'); - sb.emptyLine(); - } + sb.emptyLine(); - // Generate getters and setters methods. - _.forEach(fields, (field) => { - const fldType = JavaTypes.shortClassName(field.javaFieldType); - const fldName = field.javaFieldName; + this.commentBlock(sb, 'Full constructor.'); - this.commentBlock(sb, - `Gets ${fldName}`, - '', - `@return Value for ${fldName}.` - ); - sb.startBlock(`public ${fldType} ${JavaTypes.toJavaName('get', fldName)}() {`); - sb.append('return ' + fldName + ';'); - sb.endBlock('}'); + const arg = (field) => { + const fldType = this.javaTypes.shortClassName(field.javaFieldType); - sb.emptyLine(); + return `${fldType} ${field.javaFieldName}`; + }; - 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.startBlock(`public ${clsName}(${arg(_.head(fields))}${fields.length === 1 ? ') {' : ','}`); - sb.emptyLine(); + _.forEach(_.tail(fields), (field, idx) => { + sb.append(`${arg(field)}${idx !== fields.length - 2 ? ',' : ') {'}`); }); - // Generate equals() method. - this.commentBlock(sb, '{@inheritDoc}'); - sb.startBlock('@Override public boolean equals(Object o) {'); - sb.startBlock('if (this == o)'); - sb.append('return true;'); + _.forEach(fields, (field) => sb.append(`this.${field.javaFieldName} = ${field.javaFieldName};`)); - sb.endBlock(''); + sb.endBlock('}'); - sb.startBlock(`if (!(o instanceof ${clsName}))`); - sb.append('return false;'); + sb.emptyLine(); + } - sb.endBlock(''); + // Generate getters and setters methods. + _.forEach(fields, (field) => { + const fldType = this.javaTypes.shortClassName(field.javaFieldType); + const fldName = field.javaFieldName; - sb.append(`${clsName} that = (${clsName})o;`); + this.commentBlock(sb, + `Gets ${fldName}`, + '', + `@return Value for ${fldName}.` + ); + sb.startBlock(`public ${fldType} ${this.javaTypes.toJavaName('get', fldName)}() {`); + sb.append('return ' + fldName + ';'); + sb.endBlock('}'); - _.forEach(fields, (field) => { - sb.emptyLine(); + sb.emptyLine(); - const javaName = field.javaFieldName; - const javaType = field.javaFieldType; + this.commentBlock(sb, + `Sets ${fldName}`, + '', + `@param ${fldName} New value for ${fldName}.` + ); + sb.startBlock(`public void ${this.javaTypes.toJavaName('set', fldName)}(${fldType} ${fldName}) {`); + sb.append(`this.${fldName} = ${fldName};`); + sb.endBlock('}'); - switch (javaType) { - case 'float': - sb.startBlock(`if (Float.compare(${javaName}, that.${javaName}) != 0)`); + sb.emptyLine(); + }); - break; - case 'double': - sb.startBlock(`if (Double.compare(${javaName}, that.${javaName}) != 0)`); + // Generate equals() method. + this.commentBlock(sb, '{@inheritDoc}'); + sb.startBlock('@Override public boolean equals(Object o) {'); + sb.startBlock('if (this == o)'); + sb.append('return true;'); - 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.endBlock(''); - sb.append('return false;'); + sb.startBlock(`if (!(o instanceof ${clsName}))`); + sb.append('return false;'); - sb.endBlock(''); - }); + sb.endBlock(''); - sb.append('return true;'); - sb.endBlock('}'); + sb.append(`${clsName} that = (${clsName})o;`); + _.forEach(fields, (field) => { sb.emptyLine(); - // Generate hashCode() method. - this.commentBlock(sb, '{@inheritDoc}'); - sb.startBlock('@Override public int hashCode() {'); + const javaName = field.javaFieldName; + const javaType = field.javaFieldType; - let first = true; - let tempVar = false; + switch (javaType) { + case 'float': + sb.startBlock(`if (Float.compare(${javaName}, that.${javaName}) != 0)`); - _.forEach(fields, (field) => { - const javaName = field.javaFieldName; - const javaType = field.javaFieldType; + break; + case 'double': + sb.startBlock(`if (Double.compare(${javaName}, that.${javaName}) != 0)`); - let fldHashCode; + break; + default: + if (this.javaTypes.isPrimitive(javaType)) + sb.startBlock('if (' + javaName + ' != that.' + javaName + ')'); + else + sb.startBlock('if (' + javaName + ' != null ? !' + javaName + '.equals(that.' + javaName + ') : that.' + javaName + ' != null)'); + } - switch (javaType) { - case 'boolean': - fldHashCode = `${javaName} ? 1 : 0`; + sb.append('return false;'); - break; - case 'byte': - case 'short': - fldHashCode = `(int)${javaName}`; + sb.endBlock(''); + }); - break; - case 'int': - fldHashCode = `${javaName}`; + sb.append('return true;'); + sb.endBlock('}'); - break; - case 'long': - fldHashCode = `(int)(${javaName} ^ (${javaName} >>> 32))`; + sb.emptyLine(); - break; - case 'float': - fldHashCode = `${javaName} != +0.0f ? Float.floatToIntBits(${javaName}) : 0`; + // Generate hashCode() method. + this.commentBlock(sb, '{@inheritDoc}'); + sb.startBlock('@Override public int hashCode() {'); - break; - case 'double': - sb.append(`${tempVar ? 'ig_hash_temp' : 'long ig_hash_temp'} = Double.doubleToLongBits(${javaName});`); + let first = true; + let tempVar = false; - tempVar = true; + _.forEach(fields, (field) => { + const javaName = field.javaFieldName; + const javaType = field.javaFieldType; - fldHashCode = `${javaName} != +0.0f ? Float.floatToIntBits(${javaName}) : 0`; + let fldHashCode; - break; - default: - fldHashCode = `${javaName} != null ? ${javaName}.hashCode() : 0`; - } + switch (javaType) { + case 'boolean': + fldHashCode = `${javaName} ? 1 : 0`; - sb.append(first ? `int res = ${fldHashCode};` : `res = 31 * res + ${fldHashCode.startsWith('(') ? fldHashCode : `(${fldHashCode})`};`); + break; + case 'byte': + case 'short': + fldHashCode = `(int)${javaName}`; - first = false; + break; + case 'int': + fldHashCode = `${javaName}`; - sb.emptyLine(); - }); + break; + case 'long': + fldHashCode = `(int)(${javaName} ^ (${javaName} >>> 32))`; - sb.append('return res;'); - sb.endBlock('}'); + break; + case 'float': + fldHashCode = `${javaName} != +0.0f ? Float.floatToIntBits(${javaName}) : 0`; - sb.emptyLine(); + break; + case 'double': + sb.append(`${tempVar ? 'ig_hash_temp' : 'long ig_hash_temp'} = Double.doubleToLongBits(${javaName});`); - this.commentBlock(sb, '{@inheritDoc}'); - sb.startBlock('@Override public String toString() {'); - sb.startBlock(`return "${clsName} [" + `); + tempVar = true; - _.forEach(fields, (field, idx) => { - sb.append(`"${field.javaFieldName}=" + ${field.javaFieldName}${idx < fields.length - 1 ? ' + ", " + ' : ' +'}`); - }); + fldHashCode = `${javaName} != +0.0f ? Float.floatToIntBits(${javaName}) : 0`; - sb.endBlock('"]";'); - sb.endBlock('}'); + break; + default: + fldHashCode = `${javaName} != null ? ${javaName}.hashCode() : 0`; + } - sb.endBlock('}'); + sb.append(first ? `int res = ${fldHashCode};` : `res = 31 * res + ${fldHashCode.startsWith('(') ? fldHashCode : `(${fldHashCode})`};`); - return sb.asString(); - } + first = false; - /** - * 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); - } + sb.emptyLine(); + }); - const valueFields = _.clone(domain.valueFields); + sb.append('return res;'); + sb.endBlock('}'); - if (includeKeyFields) { - _.forEach(domain.keyFields, (fld) => { - if (!_.find(valueFields, {javaFieldName: fld.javaFieldName})) - valueFields.push(fld); - }); - } + sb.emptyLine(); - pojo.valueType = domain.valueType; - pojo.valueClass = this.pojo(domain.valueType, valueFields, addConstructor); + this.commentBlock(sb, '{@inheritDoc}'); + sb.startBlock('@Override public String toString() {'); + sb.startBlock(`return "${clsName} [" + `); - pojos.push(pojo); - } - }); - }); + _.forEach(fields, (field, idx) => { + sb.append(`"${field.javaFieldName}=" + ${field.javaFieldName}${idx < fields.length - 1 ? ' + ", " + ' : ' +'}`); + }); - return pojos; - } + sb.endBlock('"]";'); + sb.endBlock('}'); - // Generate creation and execution of cache query. - static _multilineQuery(sb, query, prefix, postfix) { - if (_.isEmpty(query)) - return; + sb.endBlock('}'); - _.forEach(query, (line, ix) => { - if (ix === 0) { - if (query.length === 1) - sb.append(`${prefix}"${line}"${postfix}`); - else - sb.startBlock(`${prefix}"${line}" +`); + 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 = { + keyType: domain.keyType, + valueType: domain.valueType + }; + + // Key class generation only if key is not build in java class. + if (this.javaTypes.nonBuiltInClass(domain.keyType) && _.nonEmpty(domain.keyFields)) + pojo.keyClass = this.pojo(domain.keyType, domain.keyFields, addConstructor); + + const valueFields = _.clone(domain.valueFields); + + if (includeKeyFields) { + _.forEach(domain.keyFields, (fld) => { + if (!_.find(valueFields, {javaFieldName: fld.javaFieldName})) + valueFields.push(fld); + }); + } + + pojo.valueClass = this.pojo(domain.valueType, valueFields, addConstructor); + + pojos.push(pojo); } - else - sb.append(`"${line}"${ix === query.length - 1 ? postfix : ' +'}`); }); + }); - if (query.length > 1) - sb.endBlock(''); - else - sb.emptyLine(); - } + return pojos; + } - // Generate creation and execution of prepared statement. - static _prepareStatement(sb, conVar, query) { - this._multilineQuery(sb, query, `${conVar}.prepareStatement(`, ').executeUpdate();'); - } + // Generate creation and execution of cache query. + static _multilineQuery(sb, query, prefix, postfix) { + if (_.isEmpty(query)) + return; - static demoStartup(sb, cluster, shortFactoryCls) { - const cachesWithDataSource = _.filter(cluster.caches, (cache) => { - const kind = _.get(cache, 'cacheStoreFactory.kind'); + _.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 (kind) { - const store = cache.cacheStoreFactory[kind]; + if (query.length > 1) + sb.endBlock(''); + else + sb.emptyLine(); + } - return (store.connectVia === 'DataSource' || _.isNil(store.connectVia)) && store.dialect; - } + // Generate creation and execution of prepared statement. + static _prepareStatement(sb, conVar, query) { + this._multilineQuery(sb, query, `${conVar}.prepareStatement(`, ').executeUpdate();'); + } - return false; - }); + static demoStartup(sb, cluster, shortFactoryCls) { + const cachesWithDataSource = _.filter(cluster.caches, (cache) => { + const kind = _.get(cache, 'cacheStoreFactory.kind'); - const uniqDomains = []; + if (kind) { + const store = cache.cacheStoreFactory[kind]; - // 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)); + return (store.connectVia === 'DataSource' || _.isNil(store.connectVia)) && store.dialect; + } - if (_.nonEmpty(domains)) { - uniqDomains.push(...domains); + return false; + }); - acc.push({ - cache, - domains - }); - } + const uniqDomains = []; - return acc; - }, []); + // 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(demoTypes)) { - // Group domain modes by data source - const typeByDs = _.groupBy(demoTypes, ({cache}) => cache.cacheStoreFactory[cache.cacheStoreFactory.kind].dataSourceBean); + if (_.nonEmpty(domains)) { + uniqDomains.push(...domains); - let rndNonDefined = true; + acc.push({ + cache, + domains + }); + } - const generatedConsts = []; + return acc; + }, []); - _.forEach(typeByDs, (types) => { - _.forEach(types, (type) => { - _.forEach(type.domains, (domain) => { - const valType = domain.valueType.toUpperCase(); + if (_.nonEmpty(demoTypes)) { + // Group domain modes by data source + const typeByDs = _.groupBy(demoTypes, ({cache}) => cache.cacheStoreFactory[cache.cacheStoreFactory.kind].dataSourceBean); - const desc = _.find(PREDEFINED_QUERIES, (qry) => valType.endsWith(qry.type)); + let rndNonDefined = true; - if (desc) { - if (rndNonDefined && desc.rndRequired) { - this.commentBlock(sb, 'Random generator for demo data.'); - sb.append('private static final Random rnd = new Random();'); + const generatedConsts = []; - sb.emptyLine(); + _.forEach(typeByDs, (types) => { + _.forEach(types, (type) => { + _.forEach(type.domains, (domain) => { + const valType = domain.valueType.toUpperCase(); - rndNonDefined = false; - } + const desc = _.find(PREDEFINED_QUERIES, (qry) => valType.endsWith(qry.type)); - _.forEach(desc.insertCntConsts, (cnt) => { - if (!_.includes(generatedConsts, cnt.name)) { - this.commentBlock(sb, cnt.comment); - sb.append(`private static final int ${cnt.name} = ${cnt.val};`); + 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(); + sb.emptyLine(); - generatedConsts.push(cnt.name); - } - }); + rndNonDefined = false; } - }); - }); - }); - // Generation of fill database method - this.commentBlock(sb, 'Fill data for Demo.'); - sb.startBlock('private static void prepareDemoData() throws SQLException {'); + _.forEach(desc.insertCntConsts, (cnt) => { + if (!_.includes(generatedConsts, cnt.name)) { + this.commentBlock(sb, cnt.comment); + sb.append(`private static final int ${cnt.name} = ${cnt.val};`); - let firstDs = true; + sb.emptyLine(); - _.forEach(typeByDs, (types, ds) => { - const conVar = ds + 'Con'; + generatedConsts.push(cnt.name); + } + }); + } + }); + }); + }); - if (firstDs) - firstDs = false; - else - sb.emptyLine(); + // Generation of fill database method + this.commentBlock(sb, 'Fill data for Demo.'); + sb.startBlock('private static void prepareDemoData() throws SQLException {'); - sb.startBlock(`try (Connection ${conVar} = ${shortFactoryCls}.DataSources.INSTANCE_${ds}.getConnection()) {`); + let firstDs = true; - let first = true; - let stmtFirst = true; + _.forEach(typeByDs, (types, ds) => { + const conVar = ds + 'Con'; - _.forEach(types, (type) => { - _.forEach(type.domains, (domain) => { - const valType = domain.valueType.toUpperCase(); + if (firstDs) + firstDs = false; + else + sb.emptyLine(); - const desc = _.find(PREDEFINED_QUERIES, (qry) => valType.endsWith(qry.type)); + sb.startBlock(`try (Connection ${conVar} = ${shortFactoryCls}.DataSources.INSTANCE_${ds}.getConnection()) {`); - if (desc) { - if (first) - first = false; - else - sb.emptyLine(); + let first = true; + let stmtFirst = true; - this.comment(sb, `Generate ${desc.type}.`); + _.forEach(types, (type) => { + _.forEach(type.domains, (domain) => { + const valType = domain.valueType.toUpperCase(); - if (desc.schema) - this._prepareStatement(sb, conVar, [`CREATE SCHEMA IF NOT EXISTS ${desc.schema}`]); + const desc = _.find(PREDEFINED_QUERIES, (qry) => valType.endsWith(qry.type)); - this._prepareStatement(sb, conVar, desc.create); + if (desc) { + if (first) + first = false; + else + sb.emptyLi