blob: 02f601566fcfa2bf5565ab66fa3338ed4f9556c7 [file] [log] [blame]
/*
* 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 negate from 'lodash/negate';
import isNil from 'lodash/isNil';
import isEmpty from 'lodash/isEmpty';
import mixin from 'lodash/mixin';
const nonNil = negate(isNil);
const nonEmpty = negate(isEmpty);
mixin({
nonNil,
nonEmpty
});
export class EmptyBean {
/**
* @param {String} clsName
*/
constructor(clsName) {
this.properties = [];
this.arguments = [];
this.clsName = clsName;
}
isEmpty() {
return false;
}
nonEmpty() {
return !this.isEmpty();
}
isComplex() {
return nonEmpty(this.properties) || !!_.find(this.arguments, (arg) => arg.clsName === 'MAP');
}
nonComplex() {
return !this.isComplex();
}
findProperty(name) {
return _.find(this.properties, {name});
}
}
export class Bean extends EmptyBean {
/**
* @param {String} clsName
* @param {String} id
* @param {Object} src
* @param {Object} dflts
*/
constructor(clsName, id, src, dflts = {}) {
super(clsName);
this.id = id;
this.src = src;
this.dflts = dflts;
}
factoryMethod(name) {
this.factoryMtd = name;
return this;
}
/**
* @param acc
* @param clsName
* @param model
* @param name
* @param {Function} nonEmpty Non empty function.
* @param {Function} mapper Mapper function.
* @returns {Bean}
* @private
*/
_property(acc, clsName, model, name, nonEmpty = () => true, mapper = (val) => val) {
if (!this.src)
return this;
const value = mapper(_.get(this.src, model));
if (nonEmpty(value) && value !== _.get(this.dflts, model))
acc.push({clsName, name, value});
return this;
}
isEmpty() {
return isEmpty(this.arguments) && isEmpty(this.properties);
}
constructorArgument(clsName, value) {
this.arguments.push({clsName, value});
return this;
}
stringConstructorArgument(model) {
return this._property(this.arguments, 'java.lang.String', model, null, nonEmpty);
}
intConstructorArgument(model) {
return this._property(this.arguments, 'int', model, null, nonNil);
}
boolConstructorArgument(model) {
return this._property(this.arguments, 'boolean', model, null, nonNil);
}
longConstructorArgument(model) {
return this._property(this.arguments, 'long', model, null, nonNil);
}
classConstructorArgument(model) {
return this._property(this.arguments, 'java.lang.Class', model, null, nonEmpty);
}
pathConstructorArgument(model) {
return this._property(this.arguments, 'PATH', model, null, nonEmpty);
}
constantConstructorArgument(model) {
if (!this.src)
return this;
const value = _.get(this.src, model);
const dflt = _.get(this.dflts, model);
if (nonNil(value) && nonNil(dflt) && value !== dflt.value)
this.arguments.push({clsName: dflt.clsName, constant: true, value});
return this;
}
propertyConstructorArgument(value, hint = '') {
this.arguments.push({clsName: 'PROPERTY', value, hint});
return this;
}
/**
* @param {String} id
* @param {EmptyBean|Bean} value
* @returns {Bean}
*/
beanConstructorArgument(id, value) {
this.arguments.push({clsName: 'BEAN', id, value});
return this;
}
/**
* @param {String} id
* @param {String} model
* @param {Array.<Object>} entries
* @returns {Bean}
*/
mapConstructorArgument(id, model, entries) {
if (!this.src)
return this;
const dflt = _.get(this.dflts, model);
if (nonEmpty(entries) && nonNil(dflt) && entries !== dflt.entries) {
this.arguments.push({
clsName: 'MAP',
id,
keyClsName: dflt.keyClsName,
keyField: dflt.keyField || 'name',
valClsName: dflt.valClsName,
valField: dflt.valField || 'value',
entries
});
}
return this;
}
valueOf(path) {
return _.get(this.src, path) || _.get(this.dflts, path + '.value') || _.get(this.dflts, path);
}
includes(...paths) {
return this.src && _.every(paths, (path) => {
const value = _.get(this.src, path);
const dflt = _.get(this.dflts, path);
return nonNil(value) && value !== dflt;
});
}
prop(clsName, name, value) {
this.properties.push({clsName, name, value});
}
boolProperty(model, name = model) {
return this._property(this.properties, 'boolean', model, name, nonNil);
}
byteProperty(model, name = model) {
return this._property(this.properties, 'byte', model, name, nonNil);
}
intProperty(model, name = model) {
return this._property(this.properties, 'int', model, name, nonNil);
}
longProperty(model, name = model) {
return this._property(this.properties, 'long', model, name, nonNil);
}
floatProperty(model, name = model) {
return this._property(this.properties, 'float', model, name, nonNil);
}
doubleProperty(model, name = model) {
return this._property(this.properties, 'double', model, name, nonNil);
}
property(name, value, hint) {
this.properties.push({clsName: 'PROPERTY', name, value, hint});
return this;
}
propertyChar(name, value, hint) {
this.properties.push({clsName: 'PROPERTY_CHAR', name, value, hint});
return this;
}
propertyInt(name, value, hint) {
this.properties.push({clsName: 'PROPERTY_INT', name, value, hint});
return this;
}
stringProperty(model, name = model, mapper) {
return this._property(this.properties, 'java.lang.String', model, name, nonEmpty, mapper);
}
pathProperty(model, name = model) {
return this._property(this.properties, 'PATH', model, name, nonEmpty);
}
pathArrayProperty(id, name, items, varArg) {
if (items && items.length)
this.properties.push({clsName: 'PATH_ARRAY', id, name, items, varArg, typeClsName: 'PATH'});
return this;
}
classProperty(model, name = model) {
return this._property(this.properties, 'java.lang.Class', model, name, nonEmpty);
}
enumProperty(model, name = model) {
if (!this.src)
return this;
const value = _.get(this.src, model);
const dflt = _.get(this.dflts, model);
if (nonNil(value) && nonNil(dflt) && value !== dflt.value)
this.properties.push({clsName: dflt.clsName, name, value: dflt.mapper ? dflt.mapper(value) : value});
return this;
}
emptyBeanProperty(model, name = model) {
if (!this.src)
return this;
const cls = _.get(this.src, model);
const dflt = _.get(this.dflts, model);
if (nonEmpty(cls) && cls !== dflt)
this.properties.push({clsName: 'BEAN', name, value: new EmptyBean(cls)});
return this;
}
/**
* @param {String} name
* @param {EmptyBean|Bean} value
* @returns {Bean}
*/
beanProperty(name, value) {
this.properties.push({clsName: 'BEAN', name, value});
return this;
}
/**
* @param {String} id
* @param {String} name
* @param {Array} items
* @param {String} typeClsName
* @returns {Bean}
*/
arrayProperty(id, name, items, typeClsName = 'java.lang.String') {
if (items && items.length)
this.properties.push({clsName: 'ARRAY', id, name, items, typeClsName});
return this;
}
/**
* @param {String} id
* @param {String} name
* @param {Array} items
* @param {String} typeClsName
* @returns {Bean}
*/
varArgProperty(id, name, items, typeClsName = 'java.lang.String') {
if (items && items.length)
this.properties.push({clsName: 'ARRAY', id, name, items, typeClsName, varArg: true});
return this;
}
/**
* @param {String} id
* @param {String} name
* @param {Array} items
* @param {String} typeClsName
* @param {String} implClsName
* @returns {Bean}
*/
collectionProperty(id, name, items, typeClsName = 'java.lang.String', implClsName = 'java.util.ArrayList') {
if (items && items.length)
this.properties.push({id, name, items, clsName: 'COLLECTION', typeClsName, implClsName});
return this;
}
/**
* @param {String} id
* @param {String} model
* @param {String} [name]
* @param {Boolean} [ordered]
* @returns {Bean}
*/
mapProperty(id, model, name = model, ordered = false) {
if (!this.src)
return this;
const entries = _.isString(model) ? _.get(this.src, model) : model;
const dflt = _.isString(model) ? _.get(this.dflts, model) : _.get(this.dflts, name);
if (nonEmpty(entries) && nonNil(dflt) && entries !== dflt.entries) {
this.properties.push({
clsName: 'MAP',
id,
name,
ordered,
keyClsName: dflt.keyClsName,
keyField: dflt.keyField || 'name',
valClsName: dflt.valClsName,
valClsNameShow: dflt.valClsNameShow,
valField: dflt.valField || 'value',
entries,
keyClsGenericType: dflt.keyClsGenericType,
isKeyClsGenericTypeExtended: dflt.isKeyClsGenericTypeExtended
});
}
return this;
}
propsProperty(id, model, name = model) {
if (!this.src)
return this;
const entries = _.get(this.src, model);
if (nonEmpty(entries))
this.properties.push({clsName: 'java.util.Properties', id, name, entries});
return this;
}
/**
* @param {String} id
* @param {String} name
* @param {EmptyBean|Bean} value
*/
dataSource(id, name, value) {
if (value)
this.properties.push({clsName: 'DATA_SOURCE', id, name, value});
return this;
}
/**
* @param {String} id
* @param {String} name
* @param {Array<String>} eventTypes
*/
eventTypes(id, name, eventTypes) {
this.properties.push({clsName: 'EVENT_TYPES', id, name, eventTypes});
}
}