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

org.dbflute.s2dao.extension.TnRelationRowOptionalHandler Maven / Gradle / Ivy

There is a newer version: 1.2.8
Show newest version
/*
 * Copyright 2014-2015 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.s2dao.extension;

import java.util.Map;

import org.dbflute.Entity;
import org.dbflute.bhv.core.context.ConditionBeanContext;
import org.dbflute.cbean.ConditionBean;
import org.dbflute.dbmeta.DBMeta;
import org.dbflute.exception.RelationEntityNotFoundException;
import org.dbflute.helper.beans.DfPropertyDesc;
import org.dbflute.helper.message.ExceptionMessageBuilder;
import org.dbflute.optional.OptionalThingExceptionThrower;
import org.dbflute.optional.RelationOptionalFactory;
import org.dbflute.outsidesql.OutsideSqlContext;
import org.dbflute.s2dao.metadata.TnRelationPropertyType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * @author jflute
 * @since 1.0.5G (2014/05/20 Tuesday)
 */
public class TnRelationRowOptionalHandler {

    // ===================================================================================
    //                                                                          Definition
    //                                                                          ==========
    private static final Logger _log = LoggerFactory.getLogger(TnRelationRowOptionalHandler.class);

    // ===================================================================================
    //                                                                           Attribute
    //                                                                           =========
    protected final RelationOptionalFactory _relationOptionalFactory;

    // ===================================================================================
    //                                                                         Constructor
    //                                                                         ===========
    public TnRelationRowOptionalHandler(RelationOptionalFactory relationOptionalFactory) {
        _relationOptionalFactory = relationOptionalFactory;
    }

    // ===================================================================================
    //                                                                           Filtering
    //                                                                           =========
    /**
     * Filter the relation row as optional object if it needs.
     * @param row The base point row, which is previous relation row. (NotNull)
     * @param rpt The property type for the relation. (NotNull)
     * @param relationRow The row instance of relation entity. (NullAllowed)
     * @return The filtered instance of relation entity. (NullAllowed)
     */
    public Object filterOptionalRelationRowIfNeeds(Object row, TnRelationPropertyType rpt, Object relationRow) {
        final Class optionalType = getOptionalEntityType();
        final DfPropertyDesc pd = rpt.getPropertyDesc();
        if (optionalType.isAssignableFrom(pd.getPropertyType())) {
            if (relationRow == null) {
                return createOptionalNullEntity(row, rpt);
            }
            if (!optionalType.isInstance(relationRow)) {
                return createOptionalPresentEntity(relationRow);
            }
        }
        return relationRow;
    }

    // ===================================================================================
    //                                                                         Null Entity
    //                                                                         ===========
    /**
     * Create optional null entity.
     * @param row The base point row, which is previous relation row. (NotNull)
     * @param rpt The property type for the relation. (NotNull)
     * @return The optional object for the relation. (NotNull)
     */
    protected Object createOptionalNullEntity(Object row, TnRelationPropertyType rpt) { // object for override
        return _relationOptionalFactory.createOptionalNullEntity(createOptionalNullableThrower(row, rpt));
    }

    protected OptionalThingExceptionThrower createOptionalNullableThrower(final Object row, TnRelationPropertyType rpt) {
        final String propertyName = rpt.getPropertyDesc().getPropertyName();
        final DBMeta localDBMeta = rpt.getMyBeanMetaData().getDBMeta();
        final ConditionBean cb;
        if (ConditionBeanContext.isExistConditionBeanOnThread()) {
            cb = ConditionBeanContext.getConditionBeanOnThread();
        } else {
            cb = null;
        }
        final String outsideSqlPath;
        final Object parameterBean;
        if (OutsideSqlContext.isExistOutsideSqlContextOnThread()) {
            final OutsideSqlContext context = OutsideSqlContext.getOutsideSqlContextOnThread();
            outsideSqlPath = context.getOutsideSqlPath();
            parameterBean = context.getParameterBean();
        } else {
            outsideSqlPath = null;
            parameterBean = null;
        }
        return new OptionalThingExceptionThrower() {
            public void throwNotFoundException() {
                throwRelationEntityNotFoundException(row, propertyName, localDBMeta, cb, outsideSqlPath, parameterBean);
            }
        };
    }

    protected void throwRelationEntityNotFoundException(Object row, String propertyName, DBMeta localDBMeta, ConditionBean cb,
            String outsideSqlPath, Object parameterBean) {
        final ExceptionMessageBuilder br = new ExceptionMessageBuilder();
        br.addNotice("Not found the relation entity.");
        br.addItem("Advice");
        br.addElement("Confirm the existence in your business rule.");
        br.addElement("If the relation entity might not exist, check it.");
        br.addElement("For example:");
        br.addElement("  (x):");
        br.addElement("    List memberList = memberBhv.selectList(cb -> {");
        br.addElement("        cb.setupSelect_MemberServiceAsOne();");
        br.addElement("    });");
        br.addElement("    for (Member member : memberList) {");
        br.addElement("        ... = member.getMemberServiceAsOne().alwaysPresent(...); // *No");
        br.addElement("    }");
        br.addElement("  (o):");
        br.addElement("    List memberList = memberBhv.selectList(cb -> {");
        br.addElement("        cb.setupSelect_MemberServiceAsOne();");
        br.addElement("    });");
        br.addElement("    for (Member member : memberList) {");
        br.addElement("        member.getMemberServiceAsOne().ifPresent(service -> {  // OK");
        br.addElement("            ... = service.getServicePointCount();");
        br.addElement("        });");
        br.addElement("    }");
        br.addItem("Your Operation");
        final String localTable = localDBMeta.getTableDbName();
        final String localSuffix;
        if (row instanceof Entity) { // basically here
            final Map pkMap = localDBMeta.extractPrimaryKeyMap((Entity) row);
            localSuffix = pkMap.toString();
        } else {
            localSuffix = "{" + row + "}";
        }
        br.addElement(localTable + ":" + localSuffix + " => " + propertyName);
        if (row instanceof Entity) { // basically here
            final Entity entity = ((Entity) row);
            br.addItem("Local Entity");
            try {
                br.addElement(entity.toStringWithRelation());
            } catch (RuntimeException continued) {
                final String tableDbName = entity.asTableDbName();
                final String msg = "*Failed to build string from the entity for debug: " + tableDbName;
                if (_log.isDebugEnabled()) {
                    _log.debug(msg);
                }
                br.addElement(msg);
            }
        } else {
            br.addItem("Local Entity");
            br.addElement(row);
        }
        // cannot get it because this exception is after behavior command
        // (thread locals are destroyed at that time)
        //final InvokePathProvider invokePathProvider = InternalMapContext.getInvokePathProvider();
        //if (invokePathProvider != null) {
        //    final String invokePath = invokePathProvider.provide();
        //    br.addItem("Behavior");
        //    br.addElement(invokePath);
        //}
        if (cb != null) {
            br.addItem("ConditionBean");
            try {
                final String displaySql = cb.toDisplaySql();
                br.addElement(displaySql);
            } catch (RuntimeException continued) {
                final String tableDbName = cb.asTableDbName();
                final String msg = "*Failed to get display SQL from the condition-bean for debug: " + tableDbName;
                if (_log.isDebugEnabled()) {
                    _log.debug(msg);
                }
                br.addElement(msg);
            }
        }
        if (outsideSqlPath != null) {
            br.addItem("OutsideSql");
            br.addElement("path : " + outsideSqlPath);
            br.addElement("pmb  : " + parameterBean);
        }
        final String msg = br.buildExceptionMessage();
        throw new RelationEntityNotFoundException(msg);
    }

    // ===================================================================================
    //                                                                      Present Entity
    //                                                                      ==============
    /**
     * Create optional present entity.
     * @param relationRow The row instance of relation entity. (NullAllowed)
     * @return The optional object for the relation. (NotNull)
     */
    protected Object createOptionalPresentEntity(Object relationRow) { // object for override
        return _relationOptionalFactory.createOptionalPresentEntity(relationRow);
    }

    // ===================================================================================
    //                                                                 OptionalEntity Type
    //                                                                 ===================
    /**
     * Get the type of optional entity for relation.
     * @return The class type of optional entity. (NotNull)
     */
    public Class getOptionalEntityType() {
        return _relationOptionalFactory.getOptionalEntityType();
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy