All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.dbflute.dbmeta.info.ForeignInfo Maven / Gradle / Ivy

There is a newer version: 1.2.8
Show newest version
/*
 * 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.info;

import java.lang.reflect.Method;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import org.dbflute.Entity;
import org.dbflute.dbmeta.DBMeta;
import org.dbflute.dbmeta.property.PropertyGateway;
import org.dbflute.dbmeta.property.PropertyMethodFinder;
import org.dbflute.util.DfReflectionUtil;
import org.dbflute.util.Srl;

/**
 * The information of foreign relation.
 * @author jflute
 */
public class ForeignInfo implements RelationInfo {

    // ===================================================================================
    //                                                                           Attribute
    //                                                                           =========
    protected final String _constraintName;
    protected final String _foreignPropertyName;
    protected final DBMeta _localDBMeta;
    protected final DBMeta _foreignDBMeta;
    protected final Map _localForeignColumnInfoMap;
    protected final Map _foreignLocalColumnInfoMap;
    protected final int _relationNo;
    protected final Class _objectNativeType; // always relation entity type, provided by DB meta 
    protected final Class _propertyAccessType; // same as entity type or might be optional
    protected final boolean _oneToOne;
    protected final boolean _bizOneToOne;
    protected final boolean _referrerAsOne;
    protected final boolean _additionalFK;
    protected final String _fixedCondition;
    protected final List _dynamicParameterList;
    protected final boolean _fixedInline;
    protected final String _reversePropertyName;
    protected final boolean _canBeNullObject;
    protected final PropertyGateway _propertyGateway;
    protected final PropertyMethodFinder _propertyMethodFinder;
    protected final Method _readMethod;
    protected final Method _writeMethod;

    // ===================================================================================
    //                                                                         Constructor
    //                                                                         ===========
    public ForeignInfo(String constraintName, String foreignPropertyName // name
            , DBMeta localDBMeta, DBMeta foreignDBMeta // DB meta
            , Map localForeignColumnInfoMap, int relationNo // relation attribute
            , Class propertyAccessType // property info (object native type is provided by DB meta)
            , boolean oneToOne, boolean bizOneToOne, boolean referrerAsOne, boolean additionalFK // relation type
            , String fixedCondition, List dynamicParameterList, boolean fixedInline // fixed condition
            , String reversePropertyName, boolean canBeNullObject, PropertyMethodFinder propertyMethodFinder // various info
    ) { // big constructor
        assertObjectNotNull("constraintName", constraintName);
        assertObjectNotNull("foreignPropertyName", foreignPropertyName);
        assertObjectNotNull("localDBMeta", localDBMeta);
        assertObjectNotNull("foreignDBMeta", foreignDBMeta);
        assertObjectNotNull("localForeignColumnInfoMap", localForeignColumnInfoMap);
        assertObjectNotNull("propertyAccessType", propertyAccessType);
        assertObjectNotNull("propertyMethodFinder", propertyMethodFinder);
        _constraintName = constraintName;
        _foreignPropertyName = foreignPropertyName;
        _localDBMeta = localDBMeta;
        _foreignDBMeta = foreignDBMeta;
        _localForeignColumnInfoMap = Collections.unmodifiableMap(localForeignColumnInfoMap);
        final Map foreignLocalColumnInfoMap = new LinkedHashMap(4);
        for (Entry entry : localForeignColumnInfoMap.entrySet()) {
            foreignLocalColumnInfoMap.put(entry.getValue(), entry.getKey());
        }
        _foreignLocalColumnInfoMap = Collections.unmodifiableMap(foreignLocalColumnInfoMap);
        _relationNo = relationNo;
        _objectNativeType = foreignDBMeta.getEntityType();
        _propertyAccessType = propertyAccessType;
        _oneToOne = oneToOne;
        _bizOneToOne = bizOneToOne;
        _referrerAsOne = referrerAsOne;
        _additionalFK = additionalFK;
        _fixedCondition = fixedCondition;
        _fixedInline = fixedInline;
        if (dynamicParameterList != null) {
            _dynamicParameterList = Collections.unmodifiableList(dynamicParameterList);
        } else {
            _dynamicParameterList = Collections.emptyList();
        }
        _reversePropertyName = reversePropertyName;
        _canBeNullObject = canBeNullObject;
        _propertyGateway = findPropertyGateway();
        _propertyMethodFinder = propertyMethodFinder;
        _readMethod = findReadMethod();
        _writeMethod = findWriteMethod();
    }

    // ===================================================================================
    //                                                                    Column Existence
    //                                                                    ================
    public boolean containsLocalColumn(ColumnInfo localColumn) {
        return doContainsLocalColumn(localColumn.getColumnDbName());
    }

    protected boolean doContainsLocalColumn(String columnName) {
        for (ColumnInfo columnInfo : _localForeignColumnInfoMap.keySet()) {
            if (columnInfo.getColumnDbName().equals(columnName)) {
                return true;
            }
        }
        return false;
    }

    public boolean containsForeignColumn(ColumnInfo foreignColumn) {
        return doContainsForeignColumn(foreignColumn.getColumnDbName());
    }

    protected boolean doContainsForeignColumn(String columnName) {
        for (ColumnInfo columnInfo : _foreignLocalColumnInfoMap.keySet()) {
            if (columnInfo.getColumnDbName().equals(columnName)) {
                return true;
            }
        }
        return false;
    }

    // ===================================================================================
    //                                                                      Column Mapping
    //                                                                      ==============
    public ColumnInfo findLocalByForeign(String foreignColumnDbName) {
        final ColumnInfo keyColumnInfo = _foreignDBMeta.findColumnInfo(foreignColumnDbName);
        final ColumnInfo resultColumnInfo = (ColumnInfo) _foreignLocalColumnInfoMap.get(keyColumnInfo);
        if (resultColumnInfo == null) {
            String msg = "Not found by foreignColumnDbName in foreignLocalColumnInfoMap:";
            msg = msg + " foreignColumnDbName=" + foreignColumnDbName;
            msg = msg + " foreignLocalColumnInfoMap=" + _foreignLocalColumnInfoMap;
            throw new IllegalArgumentException(msg);
        }
        return resultColumnInfo;
    }

    public ColumnInfo findForeignByLocal(String localColumnDbName) {
        final ColumnInfo keyColumnInfo = _localDBMeta.findColumnInfo(localColumnDbName);
        final ColumnInfo resultColumnInfo = (ColumnInfo) _localForeignColumnInfoMap.get(keyColumnInfo);
        if (resultColumnInfo == null) {
            String msg = "Not found by localColumnDbName in localForeignColumnInfoMap:";
            msg = msg + " localColumnDbName=" + localColumnDbName;
            msg = msg + " localForeignColumnInfoMap=" + _localForeignColumnInfoMap;
            throw new IllegalArgumentException(msg);
        }
        return resultColumnInfo;
    }

    // ===================================================================================
    //                                                                          Reflection
    //                                                                          ==========
    // -----------------------------------------------------
    //                                                  Read
    //                                                  ----
    /**
     * Read the value to the entity by its gateway (means no reflection). 
* It returns plain value in entity as property access type. * @param The type of property, might be optional. * @param localEntity The local entity of this column to read. (NotNull) * @return The read instance of foreign entity, might be optional. (NotNull: when optional, NullAllowed: when native type) */ @SuppressWarnings("unchecked") public PROPERTY read(Entity localEntity) { return (PROPERTY) _propertyGateway.read(localEntity); } /** * Get the read method for entity reflection. * @return The read method, cached in this instance. (NotNull) */ public Method getReadMethod() { // basically unused in DBFlute, use gateway instead return _readMethod; } // ----------------------------------------------------- //  Write // ----- /** * Write the value to the entity by its gateway (means no reflection).
* No converting to optional so check the property access type. * @param localEntity The local entity of this column to write. (NotNull) * @param foreignEntity The written instance of foreign entity, might be optional. (NullAllowed: if null, null written) */ public void write(Entity localEntity, Object foreignEntity) { _propertyGateway.write(localEntity, foreignEntity); } /** * Get the write method for entity reflection. * @return The writer method, cached in this instance. (NotNull) */ public Method getWriteMethod() { // basically unused in DBFlute, use gateway instead return _writeMethod; } // ----------------------------------------------------- // Finder // ------ protected PropertyGateway findPropertyGateway() { final PropertyGateway gateway = _localDBMeta.findForeignPropertyGateway(_foreignPropertyName); if (gateway == null) { // no way String msg = "Not found the foreign property gateway by the name: " + _foreignPropertyName; throw new IllegalStateException(msg); } return gateway; } protected Method findReadMethod() { final Class localType = _localDBMeta.getEntityType(); return _propertyMethodFinder.findReadMethod(localType, _foreignPropertyName, _propertyAccessType); } protected Method findWriteMethod() { final Class localType = _localDBMeta.getEntityType(); return _propertyMethodFinder.findWriteMethod(localType, _foreignPropertyName, _propertyAccessType); } // ----------------------------------------------------- // Invoker // ------- protected Object invokeMethod(Method method, Object target, Object[] args) { return DfReflectionUtil.invoke(method, target, args); } // =================================================================================== // Relation Implementation // ======================= public String getRelationPropertyName() { return getForeignPropertyName(); } public DBMeta getTargetDBMeta() { return getForeignDBMeta(); } public Map getLocalTargetColumnInfoMap() { return getLocalForeignColumnInfoMap(); } public boolean isReferrer() { return false; } // =================================================================================== // General Helper // ============== protected String initCap(final String name) { return Srl.initCap(name); } protected void assertObjectNotNull(String variableName, Object value) { if (variableName == null) { String msg = "The value should not be null: variableName=null value=" + value; throw new IllegalArgumentException(msg); } if (value == null) { String msg = "The value should not be null: variableName=" + variableName; throw new IllegalArgumentException(msg); } } // =================================================================================== // Basic Override // ============== @Override public int hashCode() { return _foreignPropertyName.hashCode() + _localDBMeta.hashCode() + _foreignDBMeta.hashCode(); } @Override public boolean equals(Object obj) { if (obj == null || !(obj instanceof ForeignInfo)) { return false; } final ForeignInfo target = (ForeignInfo) obj; if (!this._foreignPropertyName.equals(target.getForeignPropertyName())) { return false; } if (!this._localDBMeta.equals(target.getLocalDBMeta())) { return false; } if (!this._foreignDBMeta.equals(target.getForeignDBMeta())) { return false; } return true; } @Override public String toString() { return "{" + _localDBMeta.getTableDispName() + "." + _foreignPropertyName + "->" + _foreignDBMeta.getTableDbName() + "}"; } // =================================================================================== // Accessor // ======== /** {@inheritDoc} */ public String getConstraintName() { return _constraintName; } /** * Get the property name of the foreign relation.
* This is unique name in the table.
* For example, if the member entity has getMemberStatus(), this returns 'memberStatus'. * @return The string for property name. (NotNull) */ public String getForeignPropertyName() { return _foreignPropertyName; } /** {@inheritDoc} */ public DBMeta getLocalDBMeta() { return _localDBMeta; } /** * Get the DB meta of the foreign table.
* For example, if the relation MEMBER and MEMBER_STATUS, this returns MEMBER_STATUS's one. * @return The DB meta singleton instance. (NotNull) */ public DBMeta getForeignDBMeta() { return _foreignDBMeta; } /** * Get the read-only map, key is a local column info, value is a foreign column info. * @return The read-only map. (NotNull, EmptyAllowed: only when fixedOnlyJoin) */ public Map getLocalForeignColumnInfoMap() { return _localForeignColumnInfoMap; } /** * Get the read-only map, key is a foreign column info, value is a local column info. * @return The read-only map. (NotNull, EmptyAllowed: only when fixedOnlyJoin) */ public Map getForeignLocalColumnInfoMap() { return _foreignLocalColumnInfoMap; } /** * Get the number of a relation. (internal property) * @return The number of a relation. (NotNull, NotMinus) */ public int getRelationNo() { return _relationNo; } /** {@inheritDoc} */ public Class getObjectNativeType() { return _objectNativeType; } /** {@inheritDoc} */ public Class getPropertyAccessType() { return _propertyAccessType; } /** {@inheritDoc} */ public boolean isOneToOne() { return _oneToOne; } /** * Does the relation is biz-one-to-one? * @return The determination, true or false. */ public boolean isBizOneToOne() { return _bizOneToOne; } /** * Does the relation is referrer-as-one? * @return The determination, true or false. */ public boolean isReferrerAsOne() { return _referrerAsOne; } /** * Does the relation is from additional foreign key? * @return The determination, true or false. */ public boolean isAdditionalFK() { return _additionalFK; } /** * Get the fixed-condition if it's additional foreign key. * @return The string of fixed-condition. (NullAllowed) */ public String getFixedCondition() { return _fixedCondition; } /** * Get the read-only list of dynamic parameter name for fixed-condition if it's additional foreign key. * @return The read-only list. (NotNull: if no fixed-condition, returns empty list) */ public List getDynamicParameterList() { return _dynamicParameterList; } /** * Does the fixed condition is for in-line view? * @return The determination, true or false. */ public boolean isFixedInline() { return _fixedInline; } /** {@inheritDoc} */ public RelationInfo getReverseRelation() { return _reversePropertyName != null ? _foreignDBMeta.findRelationInfo(_reversePropertyName) : null; } /** * Can the relation be null object? * @return The determination, true or false. */ public boolean canBeNullObject() { // for future, nobody calls when first return _canBeNullObject; } // ----------------------------------------------------- // Derived // ------- /** {@inheritDoc} */ public boolean isCompoundKey() { return getLocalForeignColumnInfoMap().size() > 1; } /** * Does the relation is from pure foreign key? * @return The determination, true or false. */ public boolean isPureFK() { // derived property return !_additionalFK && !_referrerAsOne; } /** * Do the FK columns have not null constraint? * @return The determination, true or false. */ public boolean isNotNullFKColumn() { for (Entry entry : getLocalForeignColumnInfoMap().entrySet()) { final ColumnInfo localColumnInfo = entry.getKey(); if (!localColumnInfo.isNotNull()) { return false; } } return true; } /** * Does it have fixed-condition for this relation? * @return The determination, true or false. */ public boolean hasFixedCondition() { return _fixedCondition != null && _fixedCondition.trim().length() > 0; } /** * Does it have dynamic parameter of fixed-condition? * @return The determination, true or false. */ public boolean hasFixedConditionDynamicParameter() { return hasFixedCondition() && !_dynamicParameterList.isEmpty(); } /** * Is the dynamic parameters of fixed condition required? * @return The determination, true or false. (true if NOT contains IF comment) */ public boolean isFixedConditionDynamicParameterRequired() { return hasFixedConditionDynamicParameter() && !getFixedCondition().contains("/*IF "); } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy