org.dbflute.dbmeta.AbstractDBMeta Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of dbflute-runtime Show documentation
Show all versions of dbflute-runtime Show documentation
The runtime library of DBFlute
/*
* Copyright 2014-2021 the original author or authors.
*
* Licensed 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.
*/
package org.dbflute.dbmeta;
import java.lang.reflect.Method;
import java.math.BigDecimal;
import java.sql.Time;
import java.sql.Timestamp;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Function;
import org.dbflute.Entity;
import org.dbflute.FunCustodial;
import org.dbflute.dbmeta.info.ColumnInfo;
import org.dbflute.dbmeta.info.ForeignInfo;
import org.dbflute.dbmeta.info.PrimaryInfo;
import org.dbflute.dbmeta.info.ReferrerInfo;
import org.dbflute.dbmeta.info.RelationInfo;
import org.dbflute.dbmeta.info.UniqueInfo;
import org.dbflute.dbmeta.property.DelegatingPropertyGateway;
import org.dbflute.dbmeta.property.PropertyGateway;
import org.dbflute.dbmeta.property.PropertyMethodFinder;
import org.dbflute.dbmeta.property.PropertyReader;
import org.dbflute.dbmeta.property.PropertyWriter;
import org.dbflute.dbmeta.valuemap.MetaHandlingEntityToMapMapper;
import org.dbflute.dbmeta.valuemap.MetaHandlingMapToEntityMapper;
import org.dbflute.exception.DBMetaNotFoundException;
import org.dbflute.helper.StringKeyMap;
import org.dbflute.helper.message.ExceptionMessageBuilder;
import org.dbflute.jdbc.Classification;
import org.dbflute.jdbc.ClassificationMeta;
import org.dbflute.jdbc.ClassificationUndefinedHandlingType;
import org.dbflute.optional.OptionalObject;
import org.dbflute.system.DBFluteSystem;
import org.dbflute.util.DfAssertUtil;
import org.dbflute.util.DfCollectionUtil;
import org.dbflute.util.DfReflectionUtil;
import org.dbflute.util.DfTypeUtil;
import org.dbflute.util.Srl;
/**
* The abstract class of DB meta.
* @author jflute
*/
public abstract class AbstractDBMeta implements DBMeta {
// ===================================================================================
// Definition
// ==========
/** The dummy value for internal map value. */
protected static final Object DUMMY_VALUE = new Object();
// ===================================================================================
// Attribute
// =========
// -----------------------------------------------------
// Information Resource
// --------------------
// lazy-initialized at corresponding getters
private volatile List _columnInfoList;
private volatile StringKeyMap _columnInfoFlexibleMap;
private volatile PrimaryInfo _primaryInfo;
private volatile List _uniqueInfoList;
private volatile List _foreignInfoList;
private volatile Map _foreignInfoFlexibleMap;
private volatile Map _foreignInfoRelationNoKeyMap;
private volatile List _referrerInfoList;
private volatile Map _referrerInfoFlexibleMap;
// ===================================================================================
// Resource Initialization
// =======================
protected void initializeInformationResource() { // for instance initializer of subclass.
getColumnInfoList(); // initialize the list of column information
getColumnInfoFlexibleMap(); // initialize the flexible map of column information
if (hasPrimaryKey()) {
getPrimaryInfo(); // initialize the primary unique information
}
// these should not be initialized here
// because the problem 'cyclic reference' occurred
// so these are initialized as lazy
//getForeignInfoList();
//getForeignInfoFlexibleMap();
//getReferrerInfoList();
//getReferrerInfoFlexibleMap();
}
// ===================================================================================
// Property Gateway
// ================
// -----------------------------------------------------
// Column Property
// ---------------
// old style for 1.0.x
//protected void setupEpg(Map propertyGatewayMap, PropertyGateway gateway, String propertyName) {
// propertyGatewayMap.put(propertyName, gateway); // the map should be plain map for performance
//}
protected void setupEpg(Map propertyGatewayMap, PropertyReader reader, PropertyWriter writer,
String propertyName) {
final DelegatingPropertyGateway gateway = new DelegatingPropertyGateway(reader, writer);
propertyGatewayMap.put(propertyName, gateway); // the map should be plain map for performance
}
public PropertyGateway findPropertyGateway(String propertyName) {
return null; // should be overridden
}
protected PropertyGateway doFindEpg(Map propertyGatewayMap, String propertyName) {
return propertyGatewayMap.get(propertyName);
}
// -----------------------------------------------------
// Foreign Property
// ----------------
// old style for 1.0.x
//protected void setupEfpg(Map propertyGatewayMap, PropertyGateway gateway, String foreignPropertyName) {
// propertyGatewayMap.put(foreignPropertyName, gateway); // the map should be plain map for performance
//}
protected void setupEfpg(Map propertyGatewayMap, PropertyReader reader, PropertyWriter writer,
String foreignPropertyName) {
final DelegatingPropertyGateway gateway = new DelegatingPropertyGateway(reader, writer);
propertyGatewayMap.put(foreignPropertyName, gateway); // the map should be plain map for performance
}
public PropertyGateway findForeignPropertyGateway(String propertyName) {
return null; // might be overridden
}
protected PropertyGateway doFindEfpg(Map propertyGatewayMap,
String foreignPropertyName) {
return propertyGatewayMap.get(foreignPropertyName);
}
// -----------------------------------------------------
// Write Converter
// ---------------
// these are static to avoid the FindBugs headache
// (implementations of PropertyGateway can be static class)
protected static void ccls(Entity entity, ColumnInfo columnInfo, Object code) { // checkClassification
// old style, for compatibility, check only on entity after Java8
if (code == null) {
return; // no check null value which means no existence on DB
}
final ClassificationMeta meta = columnInfo.getClassificationMeta();
if (meta == null) { // no way (just in case)
return;
}
final ClassificationUndefinedHandlingType undefinedHandlingType = meta.undefinedHandlingType();
if (!undefinedHandlingType.isChecked()) { // basically no way (not called if no check)
return;
}
final Classification classification = gcls(entity, columnInfo, code);
if (classification == null) {
final String tableDbName = columnInfo.getDBMeta().getTableDbName();
final String columnDbName = columnInfo.getColumnDbName();
final boolean allowedByOption = entity.myundefinedClassificationAccessAllowed();
FunCustodial.handleUndefinedClassificationCode(tableDbName, columnDbName, meta, code, allowedByOption);
}
}
protected static Classification gcls(Entity entity, ColumnInfo columnInfo, Object code) { // getClassification
if (code == null) {
return null;
}
final ClassificationMeta meta = columnInfo.getClassificationMeta();
if (meta == null) { // no way (just in case)
return null;
}
return meta.codeOf(code);
}
protected static Integer cti(Object value) { // convertToInteger
return DfTypeUtil.toInteger(value);
}
protected static Long ctl(Object value) { // convertToLong
return DfTypeUtil.toLong(value);
}
protected static BigDecimal ctb(Object value) { // convertToBigDecimal
return DfTypeUtil.toBigDecimal(value);
}
@SuppressWarnings("unchecked")
protected static NUMBER ctn(Object value, Class type) { // convertToNumber
return (NUMBER) DfTypeUtil.toNumber(value, type);
}
protected static LocalDate ctld(Object value) { // convertToLocalDate
return DfTypeUtil.toLocalDate(value);
}
protected static LocalDateTime ctldt(Object value) { // convertToLocalDateTime
return DfTypeUtil.toLocalDateTime(value);
}
protected static LocalTime ctlt(Object value) { // convertToLocalTime
return DfTypeUtil.toLocalTime(value);
}
protected static Date ctdt(Object value) { // convertToDate
return DfTypeUtil.toDate(value);
}
protected static Timestamp cttp(Object value) { // convertToTimestamp
return DfTypeUtil.toTimestamp(value);
}
protected static Time cttm(Object value) { // convertToTime
return DfTypeUtil.toTime(value);
}
// ===================================================================================
// Table Info
// ==========
// these methods is expected to override if it needs
public String getTableAlias() {
return null;
}
public String getTableComment() {
return null;
}
// ===================================================================================
// Column Info
// ===========
/** {@inheritDoc} */
public boolean hasColumn(String columnFlexibleName) {
assertStringNotNullAndNotTrimmedEmpty("columnFlexibleName", columnFlexibleName);
return getColumnInfoFlexibleMap().containsKey(columnFlexibleName);
}
/** {@inheritDoc} */
public ColumnInfo findColumnInfo(String columnFlexibleName) {
assertStringNotNullAndNotTrimmedEmpty("columnFlexibleName", columnFlexibleName);
final Map flexibleMap = getColumnInfoFlexibleMap();
final ColumnInfo columnInfo = flexibleMap.get(columnFlexibleName);
if (columnInfo == null) {
final String notice = "The column info was not found.";
final String keyName = "Column";
throwDBMetaNotFoundException(notice, keyName, columnFlexibleName, flexibleMap.keySet());
}
return columnInfo;
}
protected ColumnInfo cci(String columnDbName, String columnSqlName, String columnSynonym, String columnAlias // column name
, Class> objectNativeType, String propertyName, Class> propertyAccessType // property info
, boolean primary, boolean autoIncrement, boolean notNull // column basic check
, String columnDbType, Integer columnSize, Integer decimalDigits, Integer datetimePrecision, String defaultValue // column type
, boolean commonColumn, OptimisticLockType optimisticLockType, String columnComment // column others
, String foreignListExp, String referrerListExp // relation property
, ClassificationMeta classificationMeta, boolean canBeNullObject // various info
) { // createColumnInfo()
final Class> realPt = chooseColumnPropertyAccessType(objectNativeType, propertyName, propertyAccessType);
final String delimiter = ",";
List foreignPropList = null;
if (foreignListExp != null && foreignListExp.trim().length() > 0) {
foreignPropList = splitListTrimmed(foreignListExp, delimiter);
}
List referrerPropList = null;
if (referrerListExp != null && referrerListExp.trim().length() > 0) {
referrerPropList = splitListTrimmed(referrerListExp, delimiter);
}
final PropertyMethodFinder propertyMethodFinder = createColumnPropertyMethodFinder();
return new ColumnInfo(this, columnDbName, columnSqlName, columnSynonym, columnAlias, objectNativeType, propertyName, realPt,
primary, autoIncrement, notNull, columnDbType, columnSize, decimalDigits, datetimePrecision, defaultValue, commonColumn,
optimisticLockType, columnComment, foreignPropList, referrerPropList, classificationMeta, canBeNullObject,
propertyMethodFinder);
}
protected Class> chooseColumnPropertyAccessType(Class> objectNativeType, String propertyName, Class> propertyAccessType) {
return propertyAccessType != null ? propertyAccessType : objectNativeType;
}
protected PropertyMethodFinder createColumnPropertyMethodFinder() {
return new PropertyMethodFinder() {
public Method findReadMethod(Class> beanType, String propertyName, Class> propertyAccessType) {
return findPropertyReadMethod(beanType, propertyName, propertyAccessType);
}
public Method findWriteMethod(Class> beanType, String propertyName, Class> propertyAccessType) {
return findPropertyWriteMethod(beanType, propertyName, propertyAccessType);
}
};
}
protected Method findPropertyReadMethod(Class> beanType, String propertyName, Class> propertyAccessType) {
final String methodName = buildPropertyGetterMethodName(propertyName);
final Method method = doFindPropertyMethod(beanType, methodName, new Class>[] {});
if (method == null) {
String msg = "Not found the read method by the name:";
msg = msg + " " + beanType.getName() + "#" + methodName + "()";
throw new IllegalStateException(msg);
}
return method;
}
protected Method findPropertyWriteMethod(Class> beanType, String propertyName, Class> propertyAccessType) {
final String methodName = buildPropertySetterMethodName(propertyName);
final Method method = doFindPropertyMethod(beanType, methodName, new Class>[] { propertyAccessType });
if (method == null) {
String msg = "Not found the write method by the name and type:";
msg = msg + " " + beanType.getName() + "#" + methodName + "(" + propertyAccessType.getName() + ")";
throw new IllegalStateException(msg);
}
return method;
}
protected String buildPropertyGetterMethodName(String propertyName) {
return "get" + initCap(propertyName);
}
protected String buildPropertySetterMethodName(String propertyName) {
return "set" + initCap(propertyName);
}
protected Method doFindPropertyMethod(Class> clazz, String methodName, Class>[] argTypes) {
return DfReflectionUtil.getAccessibleMethod(clazz, methodName, argTypes);
}
/** {@inheritDoc} */
public List getColumnInfoList() {
if (_columnInfoList != null) {
return _columnInfoList;
}
synchronized (this) {
if (_columnInfoList != null) {
return _columnInfoList;
}
_columnInfoList = Collections.unmodifiableList(ccil());
return _columnInfoList;
}
}
protected abstract List ccil(); // createColumnInfoList()
/**
* Get the flexible map of column information.
* @return The flexible map of column information. (NotNull, NotEmpty)
*/
protected Map getColumnInfoFlexibleMap() {
if (_columnInfoFlexibleMap != null) {
return _columnInfoFlexibleMap;
}
final List columnInfoList = getColumnInfoList();
synchronized (this) {
if (_columnInfoFlexibleMap != null) {
return _columnInfoFlexibleMap;
}
_columnInfoFlexibleMap = createFlexibleConcurrentMap();
for (ColumnInfo columnInfo : columnInfoList) {
columnInfo.diveIntoFlexibleMap(_columnInfoFlexibleMap);
}
return _columnInfoFlexibleMap;
}
}
// ===================================================================================
// Unique Info
// ===========
// -----------------------------------------------------
// Primary Key
// -----------
/** {@inheritDoc} */
public PrimaryInfo getPrimaryInfo() {
if (_primaryInfo != null) {
return _primaryInfo;
}
synchronized (this) {
if (_primaryInfo != null) {
return _primaryInfo;
}
_primaryInfo = new PrimaryInfo(cpui());
return _primaryInfo;
}
}
protected abstract UniqueInfo cpui(); // createPrimaryUniqueInfo()
/** {@inheritDoc} */
@SuppressWarnings("deprecation")
public UniqueInfo getPrimaryUniqueInfo() { // old style
return getPrimaryInfo().getUniqueInfo();
}
protected UniqueInfo hpcpui(ColumnInfo uniqueColumnInfo) { // helpCreatePrimaryUniqueInfo()
return hpcpui(Arrays.asList(uniqueColumnInfo));
}
protected UniqueInfo hpcpui(List uniqueColumnInfoList) { // helpCreatePrimaryUniqueInfo()
return new UniqueInfo(this, uniqueColumnInfoList, true);
}
/** {@inheritDoc} */
public OptionalObject searchPrimaryInfo(Collection columnInfoList) {
final PrimaryInfo primaryInfo = getPrimaryInfo(); // exception if no PK
final Set colSet = new HashSet(columnInfoList);
final List pkList = primaryInfo.getPrimaryColumnList();
for (ColumnInfo pk : pkList) {
if (!colSet.contains(pk)) {
return OptionalObject.ofNullable(null, () -> {
throwSpecifiedColumnNotPrimaryException(columnInfoList, pkList);
});
}
}
return OptionalObject.of(primaryInfo);
}
protected void throwSpecifiedColumnNotPrimaryException(Collection columnInfoList, List pkList) {
final ExceptionMessageBuilder br = new ExceptionMessageBuilder();
br.addNotice("Not found the primary key by the columns");
br.addItem("Table");
br.addElement(getTableDbName());
br.addItem("Specified Column List");
br.addElement(columnInfoList);
br.addItem("Existing PrimaryKey");
br.addElement(pkList);
final String msg = br.buildExceptionMessage();
throw new DBMetaNotFoundException(msg); // for compatible and uniformity
}
// -----------------------------------------------------
// Natural Unique
// --------------
/** {@inheritDoc} */
public List getUniqueInfoList() {
if (_uniqueInfoList != null) {
return _uniqueInfoList;
}
synchronized (this) {
if (_uniqueInfoList != null) {
return _uniqueInfoList;
}
final Method[] methods = this.getClass().getMethods();
final List workingList = newArrayListSized(4);
final String prefix = "uniqueOf";
final Class returnType = UniqueInfo.class;
for (Method method : methods) {
if (method.getName().startsWith(prefix) && returnType.equals(method.getReturnType())) {
workingList.add((UniqueInfo) DfReflectionUtil.invoke(method, this, null));
}
}
_uniqueInfoList = Collections.unmodifiableList(workingList);
return _uniqueInfoList;
}
}
protected UniqueInfo hpcui(ColumnInfo uniqueColumnInfo) { // helpCreateUniqueInfo()
return hpcui(Arrays.asList(uniqueColumnInfo));
}
protected UniqueInfo hpcui(java.util.List uniqueColumnInfoList) { // helpCreateUniqueInfo()
return new UniqueInfo(this, uniqueColumnInfoList, false);
}
/** {@inheritDoc} */
public List searchUniqueInfoList(Collection columnInfoList) {
return doSearchMetaInfoList(columnInfoList, getUniqueInfoList(), info -> {
return info.getUniqueColumnList();
});
}
protected List doSearchMetaInfoList(Collection columnInfoList, List infoList,
Function> oneArgLambda) {
if (infoList.isEmpty()) {
return DfCollectionUtil.emptyList();
}
final Set specifiedColSet = new HashSet(columnInfoList);
final List foundInfoList = newArrayListSized(infoList.size());
for (INFO info : infoList) {
final Collection columnList = oneArgLambda.apply(info);
boolean notFound = false;
for (ColumnInfo metaCol : columnList) {
if (!specifiedColSet.contains(metaCol)) {
notFound = true;
break;
}
}
if (!notFound) {
foundInfoList.add(info);
}
}
return Collections.unmodifiableList(foundInfoList);
}
// ===================================================================================
// Relation Info
// =============
/**
* {@inheritDoc}
*/
public RelationInfo findRelationInfo(String relationPropertyName) {
assertStringNotNullAndNotTrimmedEmpty("relationPropertyName", relationPropertyName);
return hasForeign(relationPropertyName) ? findForeignInfo(relationPropertyName) : findReferrerInfo(relationPropertyName);
}
// -----------------------------------------------------
// Foreign Element
// ---------------
/**
* {@inheritDoc}
*/
public boolean hasForeign(String foreignPropertyName) {
assertStringNotNullAndNotTrimmedEmpty("foreignPropertyName", foreignPropertyName);
return getForeignInfoFlexibleMap().containsKey(foreignPropertyName);
}
/** {@inheritDoc} */
public DBMeta findForeignDBMeta(String foreignPropertyName) {
return findForeignInfo(foreignPropertyName).getForeignDBMeta();
}
/** {@inheritDoc} */
public ForeignInfo findForeignInfo(String foreignPropertyName) {
assertStringNotNullAndNotTrimmedEmpty("foreignPropertyName", foreignPropertyName);
final Map flexibleMap = getForeignInfoFlexibleMap();
final ForeignInfo foreignInfo = flexibleMap.get(foreignPropertyName);
if (foreignInfo == null) {
final String notice = "The foreign info was not found.";
final String keyName = "Foreign Property";
throwDBMetaNotFoundException(notice, keyName, foreignPropertyName, flexibleMap.keySet());
}
return foreignInfo;
}
/** {@inheritDoc} */
public ForeignInfo findForeignInfo(int relationNo) {
final Map relationNoKeyMap = getForeignInfoRelationNoKeyMap();
final ForeignInfo foreignInfo = relationNoKeyMap.get(relationNo);
if (foreignInfo == null) {
final String notice = "The foreign info was not found.";
final String keyName = "Relation No";
throwDBMetaNotFoundException(notice, keyName, relationNo, relationNoKeyMap.keySet());
}
return foreignInfo;
}
protected ForeignInfo cfi(String constraintName, String foreignPropertyName // relation name
, DBMeta localDbm, DBMeta foreignDbm // DB meta
, Map localForeignColumnInfoMap, int relationNo, Class> propertyAccessType // relation attribute
, boolean oneToOne, boolean bizOneToOne, boolean referrerAsOne, boolean additionalFK // relation type
, String fixedCondition, List dynamicParameterList, boolean fixedInline // fixed condition
, String reversePropertyName, boolean canBeNullObject // various info
) { // createForeignInfo()
final Class> realPt = chooseForeignPropertyAccessType(foreignDbm, propertyAccessType);
final PropertyMethodFinder propertyMethodFinder = createForeignPropertyMethodFinder();
return new ForeignInfo(constraintName, foreignPropertyName, localDbm, foreignDbm, localForeignColumnInfoMap, relationNo, realPt,
oneToOne, bizOneToOne, referrerAsOne, additionalFK, fixedCondition, dynamicParameterList, fixedInline, reversePropertyName,
canBeNullObject, propertyMethodFinder);
}
protected Class> chooseForeignPropertyAccessType(DBMeta foreignDbm, Class> specifiedType) {
return specifiedType != null ? specifiedType : foreignDbm.getEntityType(); // basically default, or specified Optional
}
protected PropertyMethodFinder createForeignPropertyMethodFinder() {
return new PropertyMethodFinder() {
public Method findReadMethod(Class> beanType, String propertyName, Class> propertyAccessType) {
return findPropertyReadMethod(beanType, propertyName, propertyAccessType);
}
public Method findWriteMethod(Class> beanType, String propertyName, Class> propertyAccessType) {
return findPropertyWriteMethod(beanType, propertyName, propertyAccessType);
}
};
}
/** {@inheritDoc} */
public List getForeignInfoList() {
if (_foreignInfoList != null) {
return _foreignInfoList;
}
synchronized (this) {
if (_foreignInfoList != null) {
return _foreignInfoList;
}
final Method[] methods = this.getClass().getMethods();
final List workingList = newArrayList();
final String prefix = "foreign";
final Class returnType = ForeignInfo.class;
for (Method method : methods) {
if (method.getName().startsWith(prefix) && returnType.equals(method.getReturnType())) {
workingList.add((ForeignInfo) DfReflectionUtil.invoke(method, this, null));
}
}
_foreignInfoList = Collections.unmodifiableList(workingList);
return _foreignInfoList;
}
}
/**
* Get the flexible map of foreign information.
* @return The flexible map of foreign information. (NotNull, EmptyAllowed, ReadOnly)
*/
protected Map getForeignInfoFlexibleMap() {
if (_foreignInfoFlexibleMap != null) {
return _foreignInfoFlexibleMap;
}
final List foreignInfoList = getForeignInfoList();
synchronized (this) {
if (_foreignInfoFlexibleMap != null) {
return _foreignInfoFlexibleMap;
}
final StringKeyMap map = createFlexibleConcurrentMap();
for (ForeignInfo foreignInfo : foreignInfoList) {
map.put(foreignInfo.getForeignPropertyName(), foreignInfo);
}
_foreignInfoFlexibleMap = Collections.unmodifiableMap(map);
return _foreignInfoFlexibleMap;
}
}
/**
* Get the relation-no key map of foreign information.
* @return The unordered map of foreign information. (NotNull, EmptyAllowed, ReadOnly)
*/
protected Map getForeignInfoRelationNoKeyMap() {
if (_foreignInfoRelationNoKeyMap != null) {
return _foreignInfoRelationNoKeyMap;
}
final List foreignInfoList = getForeignInfoList();
synchronized (this) {
if (_foreignInfoRelationNoKeyMap != null) {
return _foreignInfoRelationNoKeyMap;
}
final Map map = newConcurrentHashMap();
for (ForeignInfo foreignInfo : foreignInfoList) {
map.put(foreignInfo.getRelationNo(), foreignInfo);
}
_foreignInfoRelationNoKeyMap = Collections.unmodifiableMap(map);
return _foreignInfoRelationNoKeyMap;
}
}
/** {@inheritDoc} */
public List searchForeignInfoList(Collection columnInfoList) {
return doSearchMetaInfoList(columnInfoList, getForeignInfoList(), info -> {
return info.getLocalForeignColumnInfoMap().keySet();
});
}
// -----------------------------------------------------
// Referrer Element
// ----------------
/** {@inheritDoc} */
public boolean hasReferrer(String referrerPropertyName) {
assertStringNotNullAndNotTrimmedEmpty("referrerPropertyName", referrerPropertyName);
return getReferrerInfoFlexibleMap().containsKey(referrerPropertyName);
}
/** {@inheritDoc} */
public DBMeta findReferrerDBMeta(String referrerPropertyName) {
assertStringNotNullAndNotTrimmedEmpty("referrerPropertyName", referrerPropertyName);
return findReferrerInfo(referrerPropertyName).getReferrerDBMeta();
}
/** {@inheritDoc} */
public ReferrerInfo findReferrerInfo(String referrerPropertyName) {
assertStringNotNullAndNotTrimmedEmpty("referrerPropertyName", referrerPropertyName);
final Map flexibleMap = getReferrerInfoFlexibleMap();
final ReferrerInfo referrerInfo = flexibleMap.get(referrerPropertyName);
if (referrerInfo == null) {
final String notice = "The referrer info was not found.";
final String keyName = "Referrer Property";
throwDBMetaNotFoundException(notice, keyName, referrerPropertyName, flexibleMap.keySet());
}
return referrerInfo;
}
protected ReferrerInfo cri(String constraintName, String referrerPropertyName // relation name
, DBMeta localDbm, DBMeta referrerDbm // DB meta
, Map localReferrerColumnInfoMap // relation attribute
, boolean oneToOne, String reversePropertyName // relation type and various info
) { // createReferrerInfo()
final Class> propertyAccessType = chooseReferrerPropertyAccessType(referrerDbm, oneToOne);
final PropertyMethodFinder propertyMethodFinder = createReferrerPropertyMethodFinder();
return new ReferrerInfo(constraintName, referrerPropertyName, localDbm, referrerDbm, localReferrerColumnInfoMap, propertyAccessType,
oneToOne, reversePropertyName, propertyMethodFinder);
}
protected Class> chooseReferrerPropertyAccessType(DBMeta referrerDbm, boolean oneToOne) {
final Class> propertyType;
if (oneToOne) { // basically no way
propertyType = referrerDbm.getEntityType();
} else {
final Class> listType = getReferrerPropertyListType();
propertyType = listType != null ? listType : List.class;
}
return propertyType;
}
/**
* Get the list type of referrer property in entity.
* @return The class instance of list type. (NullAllowed: if null, Java's List used as default)
*/
protected Class> getReferrerPropertyListType() { // might be overridden
return null; // as default (List)
}
protected PropertyMethodFinder createReferrerPropertyMethodFinder() {
return new PropertyMethodFinder() {
public Method findReadMethod(Class> beanType, String propertyName, Class> propertyAccessType) {
return findPropertyReadMethod(beanType, propertyName, propertyAccessType);
}
public Method findWriteMethod(Class> beanType, String propertyName, Class> propertyAccessType) {
return findPropertyWriteMethod(beanType, propertyName, propertyAccessType);
}
};
}
/** {@inheritDoc} */
public List getReferrerInfoList() {
if (_referrerInfoList != null) {
return _referrerInfoList;
}
synchronized (this) {
if (_referrerInfoList != null) {
return _referrerInfoList;
}
final Method[] methods = this.getClass().getMethods();
final List workingList = newArrayList();
final String prefix = "referrer";
final Class returnType = ReferrerInfo.class;
for (Method method : methods) {
if (method.getName().startsWith(prefix) && returnType.equals(method.getReturnType())) {
workingList.add((ReferrerInfo) DfReflectionUtil.invoke(method, this, null));
}
}
_referrerInfoList = Collections.unmodifiableList(workingList);
return _referrerInfoList;
}
}
/**
* Get the flexible map of referrer information.
* @return The flexible map of referrer information. (NotNull, EmptyAllowed, ReadOnly)
*/
protected Map getReferrerInfoFlexibleMap() {
if (_referrerInfoFlexibleMap != null) {
return _referrerInfoFlexibleMap;
}
final List referrerInfoList = getReferrerInfoList();
synchronized (this) {
if (_referrerInfoFlexibleMap != null) {
return _referrerInfoFlexibleMap;
}
final StringKeyMap map = createFlexibleConcurrentMap();
for (ReferrerInfo referrerInfo : referrerInfoList) {
map.put(referrerInfo.getReferrerPropertyName(), referrerInfo);
}
_referrerInfoFlexibleMap = Collections.unmodifiableMap(map);
return _referrerInfoFlexibleMap;
}
}
/** {@inheritDoc} */
public List searchReferrerInfoList(Collection columnInfoList) {
return doSearchMetaInfoList(columnInfoList, getReferrerInfoList(), info -> {
return info.getLocalReferrerColumnInfoMap().keySet();
});
}
// -----------------------------------------------------
// Common Logic
// ------------
protected String buildRelationInfoGetterMethodNameInitCap(String targetName, String relationPropertyName) {
return targetName + relationPropertyName.substring(0, 1).toUpperCase() + relationPropertyName.substring(1);
}
// ===================================================================================
// Various Info
// ============
// These methods is expected to override if it needs.
public boolean hasIdentity() {
return false;
}
public boolean hasSequence() {
return false;
}
public String getSequenceName() {
return null;
}
public String getSequenceNextValSql() {
if (!hasSequence()) {
return null;
}
return getCurrentDBDef().dbway().buildSequenceNextValSql(getSequenceName());
}
public Integer getSequenceIncrementSize() {
return null;
}
public Integer getSequenceCacheSize() {
return null;
}
public boolean hasOptimisticLock() {
return hasVersionNo() || hasUpdateDate();
}
public boolean hasVersionNo() {
return false;
}
public ColumnInfo getVersionNoColumnInfo() {
return null;
}
public boolean hasUpdateDate() {
return false;
}
public ColumnInfo getUpdateDateColumnInfo() {
return null;
}
public boolean hasCommonColumn() {
return false;
}
public List getCommonColumnInfoList() {
return DfCollectionUtil.emptyList();
}
public List getCommonColumnInfoBeforeInsertList() {
return DfCollectionUtil.emptyList();
}
public List getCommonColumnInfoBeforeUpdateList() {
return DfCollectionUtil.emptyList();
}
// ===================================================================================
// Map Communication
// =================
// -----------------------------------------------------
// Accept
// ------
protected void doAcceptPrimaryKeyMap(ENTITY entity, Map primaryKeyMap) {
assertObjectNotNull("entity", entity);
if (primaryKeyMap == null || primaryKeyMap.isEmpty()) {
String msg = "The argument 'primaryKeyMap' should not be null or empty: primaryKeyMap=" + primaryKeyMap;
throw new IllegalArgumentException(msg);
}
doConvertToEntity(entity, primaryKeyMap, true);
}
protected void doAcceptAllColumnMap(ENTITY entity, Map allColumnMap) {
assertObjectNotNull("entity", entity);
if (allColumnMap == null || allColumnMap.isEmpty()) {
String msg = "The argument 'allColumnMap' should not be null or empty: allColumnMap=" + allColumnMap;
throw new IllegalArgumentException(msg);
}
doConvertToEntity(entity, allColumnMap, false);
}
protected void doConvertToEntity(ENTITY entity, Map columnMap, boolean pkOnly) {
final List columnInfoList = pkOnly ? getPrimaryInfo().getPrimaryColumnList() : getColumnInfoList();
final MetaHandlingMapToEntityMapper mapper = createMetaHandlingMapToEntityMapper(columnMap);
mapper.mappingToEntity(entity, columnMap, columnInfoList);
}
protected MetaHandlingMapToEntityMapper createMetaHandlingMapToEntityMapper(Map columnMap) {
return new MetaHandlingMapToEntityMapper(columnMap);
}
// -----------------------------------------------------
// Extract
// -------
protected Map doExtractPrimaryKeyMap(Entity entity) {
assertObjectNotNull("entity", entity);
return doConvertToColumnValueMap(entity, true);
}
protected Map doExtractAllColumnMap(Entity entity) {
assertObjectNotNull("entity", entity);
return doConvertToColumnValueMap(entity, false);
}
protected Map doConvertToColumnValueMap(Entity entity, boolean pkOnly) {
final List columnInfoList = pkOnly ? getPrimaryInfo().getPrimaryColumnList() : getColumnInfoList();
final MetaHandlingEntityToMapMapper mapper = createMetaHandlingEntityToMapMapper(entity);
return mapper.mappingToColumnValueMap(columnInfoList);
}
protected MetaHandlingEntityToMapMapper createMetaHandlingEntityToMapMapper(Entity entity) {
return new MetaHandlingEntityToMapMapper(entity);
}
// ===================================================================================
// Assist Helper
// =============
@SuppressWarnings("unchecked")
protected ENTITY downcast(Entity entity) {
checkDowncast(entity);
return (ENTITY) entity;
}
protected void checkDowncast(Entity entity) {
assertObjectNotNull("entity", entity);
final Class> entityType = getEntityType();
final Class> targetType = entity.getClass();
if (!entityType.isAssignableFrom(targetType)) {
final String titleName = DfTypeUtil.toClassTitle(entityType);
String msg = "The entity should be " + titleName + " but it was: " + targetType;
throw new IllegalStateException(msg);
}
}
protected Map setupKeyToLowerMap(boolean dbNameKey) {
final Map map;
if (dbNameKey) {
map = newConcurrentHashMap(getTableDbName().toLowerCase(), getTablePropertyName());
} else {
map = newConcurrentHashMap(getTablePropertyName().toLowerCase(), getTableDbName());
}
final Method[] methods = this.getClass().getMethods();
final String columnInfoMethodPrefix = "column";
try {
for (Method method : methods) {
final String name = method.getName();
if (!name.startsWith(columnInfoMethodPrefix)) {
continue;
}
final ColumnInfo columnInfo = (ColumnInfo) method.invoke(this);
final String dbName = columnInfo.getColumnDbName();
final String propertyName = columnInfo.getPropertyName();
if (dbNameKey) {
map.put(dbName.toLowerCase(), propertyName);
} else {
map.put(propertyName.toLowerCase(), dbName);
}
}
return Collections.unmodifiableMap(map);
} catch (Exception e) {
throw new IllegalStateException(e);
}
}
protected void throwDBMetaNotFoundException(String notice, String keyName, Object value, Set extends Object> keySet) {
final ExceptionMessageBuilder br = new ExceptionMessageBuilder();
br.addNotice(notice);
br.addItem("Table");
br.addElement(getTableDbName());
br.addItem(keyName);
br.addElement(value);
br.addItem("Existing KeySet");
br.addElement(keySet);
final String msg = br.buildExceptionMessage();
throw new DBMetaNotFoundException(msg);
}
// ===================================================================================
// General Helper
// ==============
// -----------------------------------------------------
// String Handling
// ---------------
protected final String replaceString(String text, String fromText, String toText) {
return Srl.replace(text, fromText, toText);
}
protected final List splitListTrimmed(String str, String delimiter) {
return Srl.splitListTrimmed(str, delimiter);
}
protected final String initCap(String str) {
return Srl.initCap(str);
}
protected final String initUncap(String str) {
return Srl.initUncap(str);
}
protected final String ln() {
return DBFluteSystem.ln();
}
// -----------------------------------------------------
// Collection Generator
// --------------------
protected HashMap newHashMap() {
return DfCollectionUtil.newHashMap();
}
protected ConcurrentHashMap newConcurrentHashMap() {
return DfCollectionUtil.newConcurrentHashMap();
}
protected ConcurrentHashMap newConcurrentHashMap(KEY key, VALUE value) {
final ConcurrentHashMap map = newConcurrentHashMap();
map.put(key, value);
return map;
}
protected LinkedHashMap newLinkedHashMap() {
return DfCollectionUtil.newLinkedHashMap();
}
protected LinkedHashMap newLinkedHashMap(KEY key, VALUE value) {
final LinkedHashMap map = newLinkedHashMap();
map.put(key, value);
return map;
}
protected LinkedHashMap newLinkedHashMapSized(int size) {
return DfCollectionUtil.newLinkedHashMapSized(size);
}
protected ArrayList newArrayList() {
return DfCollectionUtil.newArrayList();
}
@SafeVarargs
protected final List newArrayList(ELEMENT... elements) {
final List list = newArrayList();
for (ELEMENT element : elements) {
list.add(element);
}
return list;
}
protected ArrayList newArrayList(Collection collection) {
return DfCollectionUtil.newArrayList(collection);
}
protected ArrayList newArrayListSized(int size) {
return DfCollectionUtil.newArrayListSized(size);
}
protected StringKeyMap createFlexibleConcurrentMap() {
return StringKeyMap.createAsFlexibleConcurrent();
}
// -----------------------------------------------------
// Assert Object
// -------------
/**
* Assert that the argument is not null.
* @param variableName The check name of variable for message. (NotNull)
* @param value The checked value. (NotNull)
* @throws IllegalArgumentException When the argument is null.
*/
protected void assertObjectNotNull(String variableName, Object value) {
DfAssertUtil.assertObjectNotNull(variableName, value);
}
// -----------------------------------------------------
// Assert String
// -------------
/**
* Assert that the string is not null and not trimmed empty.
* @param variableName The check name of variable for message. (NotNull)
* @param value The checked value. (NotNull)
* @throws IllegalArgumentException When the argument is null or empty.
*/
protected void assertStringNotNullAndNotTrimmedEmpty(String variableName, String value) {
DfAssertUtil.assertStringNotNullAndNotTrimmedEmpty(variableName, value);
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy