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

com.flowcentraltech.flowcentral.system.business.EnvironmentServiceImpl Maven / Gradle / Ivy

There is a newer version: 3.2.1
Show newest version
/*
 * Copyright 2021-2024 FlowCentral Technologies Limited.
 * 
 * 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 com.flowcentraltech.flowcentral.system.business;

import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;

import com.flowcentraltech.flowcentral.common.business.EnvironmentDelegate;
import com.flowcentraltech.flowcentral.common.business.EnvironmentDelegateHolder;
import com.flowcentraltech.flowcentral.common.business.EnvironmentDelegateRegistrar;
import com.flowcentraltech.flowcentral.common.business.EnvironmentService;
import com.flowcentraltech.flowcentral.common.business.SuggestionProvider;
import com.flowcentraltech.flowcentral.common.business.policies.ChildListEditPolicy;
import com.flowcentraltech.flowcentral.common.business.policies.EntityActionContext;
import com.flowcentraltech.flowcentral.common.business.policies.EntityActionPolicy;
import com.flowcentraltech.flowcentral.common.business.policies.EntityActionResult;
import com.flowcentraltech.flowcentral.common.business.policies.EntityListActionContext;
import com.flowcentraltech.flowcentral.common.business.policies.EntityListActionPolicy;
import com.flowcentraltech.flowcentral.common.business.policies.EntityListActionResult;
import com.flowcentraltech.flowcentral.common.business.policies.SweepingCommitPolicy;
import com.flowcentraltech.flowcentral.common.constants.EvaluationMode;
import com.flowcentraltech.flowcentral.common.entities.EntityWrapper;
import com.flowcentraltech.flowcentral.common.entities.WorkEntity;
import com.flowcentraltech.flowcentral.configuration.constants.RecordActionType;
import com.flowcentraltech.flowcentral.system.constants.SystemModuleNameConstants;
import com.tcdng.unify.core.UnifyException;
import com.tcdng.unify.core.annotation.Component;
import com.tcdng.unify.core.annotation.Configurable;
import com.tcdng.unify.core.annotation.Transactional;
import com.tcdng.unify.core.business.AbstractBusinessService;
import com.tcdng.unify.core.constant.TopicEventType;
import com.tcdng.unify.core.criterion.AggregateFunction;
import com.tcdng.unify.core.criterion.GroupingFunction;
import com.tcdng.unify.core.criterion.Update;
import com.tcdng.unify.core.database.Aggregation;
import com.tcdng.unify.core.database.Database;
import com.tcdng.unify.core.database.Entity;
import com.tcdng.unify.core.database.GroupingAggregation;
import com.tcdng.unify.core.database.Query;
import com.tcdng.unify.core.util.DataUtils;
import com.tcdng.unify.core.util.ReflectUtils;
import com.tcdng.unify.core.util.StringUtils;

/**
 * Default implementation of environment service.
 * 
 * @author FlowCentral Technologies Limited
 * @since 1.0
 */
@Transactional
@Component(SystemModuleNameConstants.ENVIRONMENT_SERVICE)
public class EnvironmentServiceImpl extends AbstractBusinessService implements EnvironmentService {

    @Configurable
    private SuggestionProvider suggestionProvider;

    @Configurable
    private EnvironmentDelegateRegistrar environmentDelegateRegistrar;

    @Override
    public Database getDatabase() throws UnifyException {
        return db();
    }

    @Override
    public void clearRollbackTransactions() throws UnifyException {
        super.clearRollbackTransactions();
    }

    @Override
    public void setSavePoint() throws UnifyException {
        super.setSavePoint();
    }

    @Override
    public void clearSavePoint() throws UnifyException {
        super.clearSavePoint();
    }

    @Override
    public void rollbackToSavePoint() throws UnifyException {
        super.rollbackToSavePoint();
    }

    @Override
    public void commitTransactions() throws UnifyException {
        super.commitTransactions();
    }

    @Override
    public List validate(Entity inst, EvaluationMode mode) throws UnifyException {
        Database db = db(inst.getClass());
        if (db instanceof EnvironmentDelegate) {
            return ((EnvironmentDelegate) db).validate(inst, mode);
        }

        return Collections.emptyList();
    }

    @Override
    public EntityActionResult performEntityAction(EntityActionContext ctx) throws UnifyException {
        EntityActionResult result = executeEntityPreActionPolicy(ctx);
        if (result == null) {
            return executeEntityPostActionPolicy(db(ctx.getInst().getClass()), ctx);
        }

        return result;
    }

    @Override
    public EntityListActionResult performEntityAction(EntityListActionContext ctx) throws UnifyException {
        if (ctx.isWithPolicy()) {
            String policy = ctx.getPolicyName();
            String rule = null;
            int index = policy.lastIndexOf(':');
            if (index > 0) {
                rule = policy.substring(index + 1);
                policy = policy.substring(0, index);
            }
            
            return ((EntityListActionPolicy) getComponent(policy)).executeAction(ctx, rule);
        }

        return new EntityListActionResult(ctx);
    }

    @Override
    public Object create(Entity inst) throws UnifyException {
        Object result = db(inst.getClass()).create(inst);
        setOffEntityEvent(TopicEventType.CREATE, inst.getClass(), null);
        return result;
    }

    @Override
    public Object create(EntityWrapper wrapperInst) throws UnifyException {
        final Entity inst = wrapperInst.isIndexed() ? wrapperInst.getValueObjectAtDataIndex()
                : wrapperInst.getValueObject();
        Object result = db(inst.getClass()).create(inst);
        setOffEntityEvent(TopicEventType.CREATE, inst.getClass(), null);
        return result;
    }

    @Override
    public EntityActionResult create(EntityActionContext ctx) throws UnifyException {
        EntityActionResult result = executeEntityPreActionPolicy(ctx);
        if (result == null) { 
            Entity inst = ctx.getInst();
            ctx.setResult(create(inst));
            if (suggestionProvider != null) {
                suggestionProvider.saveSuggestions(ctx.getEntityDef(Object.class), inst);
            }

            if (inst instanceof WorkEntity && ((WorkEntity) inst).getOriginalCopyId() != null) {
                // Update original instance workflow flag
                updateById((Class) inst.getClass(), ((WorkEntity) inst).getOriginalCopyId(),
                        new Update().add("inWorkflow", Boolean.TRUE));
            }

            result = executeEntityPostActionPolicy(db(inst.getClass()), ctx);
            setOffEntityEvent(TopicEventType.CREATE, inst.getClass(), null);
        }

        return result;
    }

    @Override
    public  T find(Class clazz, Object id) throws UnifyException {
        return (T) db(clazz).find(Query.of(clazz).addEquals("id", id));
    }

    @Override
    public  T find(Query query) throws UnifyException {
        return (T) db(query.getEntityClass()).find(query);
    }

    @Override
    public  T findLean(Class clazz, Object id) throws UnifyException {
        return (T) db(clazz).findLean(Query.of(clazz).addEquals("id", id));
    }

    @Override
    public  T findLean(Query query) throws UnifyException {
        return (T) db(query.getEntityClass()).findLean(query);
    }

    @Override
    public  List findAll(Query query) throws UnifyException {
        return db(query.getEntityClass()).findAll(query);
    }

    @Override
    public  List findAllWithChildren(Query query) throws UnifyException {
        return db(query.getEntityClass()).findAllWithChildren(query);
    }

    @Override
    public  Map findAllMap(Class keyClass, String keyName, Query query)
            throws UnifyException {
        return db(query.getEntityClass()).findAllMap(keyClass, keyName, query);
    }

    @Override
    public  Map> findAllListMap(Class keyClass, String keyName, Query query)
            throws UnifyException {
        return db(query.getEntityClass()).findAllListMap(keyClass, keyName, query);
    }

    @Override
    public  void findChildren(T record) throws UnifyException {
        db(record.getClass()).findChildren(record);
    }

    @Override
    public  void findEditableChildren(T record) throws UnifyException {
        db(record.getClass()).findEditableChildren(record);
    }

    @Override
    public  void findReadOnlyChildren(T record) throws UnifyException {
        db(record.getClass()).findReadOnlyChildren(record);
    }

    @Override
    public  T list(Class clazz, Object id) throws UnifyException {
        return (T) db(clazz).list(Query.of(clazz).addEquals("id", id));
    }

    @Override
    public  T list(Query query) throws UnifyException {
        return (T) db(query.getEntityClass()).list(query);
    }

    @Override
    public  T listLean(Class clazz, Object id) throws UnifyException {
        return (T) db(clazz).listLean(Query.of(clazz).addEquals("id", id));
    }

    @Override
    public  T listLean(Query query) throws UnifyException {
        return (T) db(query.getEntityClass()).listLean(query);
    }

    @Override
    public  List listAll(Query query) throws UnifyException {
        return db(query.getEntityClass()).listAll(query);
    }

    @Override
    public  List listAllWithChildren(Query query) throws UnifyException {
        return db(query.getEntityClass()).listAllWithChildren(query);
    }

    @Override
    public  void listChildren(T record) throws UnifyException {
        db(record.getClass()).listChildren(record);
    }

    @Override
    public  void listEditableChildren(T record) throws UnifyException {
        db(record.getClass()).listEditableChildren(record);
    }

    @Override
    public  void listReadOnlyChildren(T record) throws UnifyException {
        db(record.getClass()).listReadOnlyChildren(record);
    }

    @Override
    public  T listValue(Class valueClazz, Class recordClazz, Object id, String property)
            throws UnifyException {
        return db(recordClazz).value(valueClazz, property, Query.of(recordClazz).addEquals("id", id));
    }

    @Override
    public  Map listAllMap(Class keyClass, String keyName, Query query)
            throws UnifyException {
        return db(query.getEntityClass()).listAllMap(keyClass, keyName, query);
    }

    @Override
    public int updateById(Entity record) throws UnifyException {
        int result = db(record.getClass()).updateById(record);
        setOffEntityEvent(TopicEventType.UPDATE, record.getClass(), record.getId());
        return result;
    }

    @Override
    public int updateByIdVersion(Entity record) throws UnifyException {
        int result = db(record.getClass()).updateByIdVersion(record);
        setOffEntityEvent(TopicEventType.UPDATE, record.getClass(), record.getId());
        return result;
    }

    @Override
    public int updateByIdVersionEditableChildren(Entity record) throws UnifyException {
        int result = db(record.getClass()).updateByIdVersionEditableChildren(record);
        setOffEntityEvent(TopicEventType.UPDATE, record.getClass(), record.getId());
        return result;
    }

    @Override
    public int updateLean(Entity record) throws UnifyException {
        int result = db(record.getClass()).updateLeanByIdVersion(record);
        setOffEntityEvent(TopicEventType.UPDATE, record.getClass(), record.getId());
        return result;
    }

    @Override
    public int updateByIdVersion(EntityWrapper wrappedInst) throws UnifyException {
        Entity inst = wrappedInst.isIndexed() ? wrappedInst.getValueObjectAtDataIndex() : wrappedInst.getValueObject();
        int result = db(inst.getClass()).updateByIdVersion(inst);
        setOffEntityEvent(TopicEventType.UPDATE, inst.getClass(), inst.getId());
        return result;
    }

    @Override
    public int updateLean(EntityWrapper wrappedInst) throws UnifyException {
        Entity inst = wrappedInst.isIndexed() ? wrappedInst.getValueObjectAtDataIndex() : wrappedInst.getValueObject();
        int result = db(inst.getClass()).updateLeanByIdVersion(inst);
        setOffEntityEvent(TopicEventType.UPDATE, inst.getClass(), inst.getId());
        return result;
    }

    @Override
    public EntityActionResult updateByIdVersion(EntityActionContext ctx) throws UnifyException {
        EntityActionResult result = executeEntityPreActionPolicy(ctx);
        if (result == null) {
            final Entity inst = ctx.getInst();
            ctx.setResult(db(inst.getClass()).updateByIdVersion(inst));
            if (suggestionProvider != null) {
                suggestionProvider.saveSuggestions(ctx.getEntityDef(Object.class), inst);
            }

            result = executeEntityPostActionPolicy(db(inst.getClass()), ctx);
            setOffEntityEvent(TopicEventType.UPDATE, inst.getClass(), inst.getId());
            return result;
        }

        return result;
    }

    @Override
    public EntityActionResult updateLean(EntityActionContext ctx) throws UnifyException {
        EntityActionResult result = executeEntityPreActionPolicy(ctx);
        if (result == null) {
            final Entity inst = ctx.getInst();
            ctx.setResult(db(inst.getClass()).updateLeanByIdVersion(inst));
            if (suggestionProvider != null) {
                suggestionProvider.saveSuggestions(ctx.getEntityDef(Object.class), inst);
            }

            result = executeEntityPostActionPolicy(db(inst.getClass()), ctx);
            setOffEntityEvent(TopicEventType.UPDATE, inst.getClass(), inst.getId());
            return result;
        }

        return result;
    }

    @Override
    public int updateById(Class clazz, Object id, Update update) throws UnifyException {
        int result = db(clazz).updateById(clazz, id, update);
        setOffEntityEvent(TopicEventType.UPDATE, clazz, id);
        return result;
    }

    @Override
    public int updateAll(Query query, Update update) throws UnifyException {
        int result = db(query.getEntityClass()).updateAll(query, update);
        setOffEntityEvent(TopicEventType.UPDATE, query.getEntityClass(), null);
        return result;
    }

    @Override
    public int updateLeanById(Entity record) throws UnifyException {
        int result = db(record.getClass()).updateLeanById(record);
        setOffEntityEvent(TopicEventType.UPDATE, record.getClass(), record.getId());
        return result;
    }

    @Override
    public int updateLeanByIdVersion(Entity record) throws UnifyException {
        int result = db(record.getClass()).updateLeanByIdVersion(record);
        setOffEntityEvent(TopicEventType.UPDATE, record.getClass(), record.getId());
        return result;
    }

    @Override
    public int updateLeanById(EntityWrapper wrappedInst) throws UnifyException {
        Entity inst = wrappedInst.isIndexed() ? wrappedInst.getValueObjectAtDataIndex() : wrappedInst.getValueObject();
        int result = db(inst.getClass()).updateLeanById(inst);
        setOffEntityEvent(TopicEventType.UPDATE, inst.getClass(), inst.getId());
        return result;
    }

    @Override
    public int updateLeanByIdVersion(EntityWrapper wrappedInst) throws UnifyException {
        Entity inst = wrappedInst.isIndexed() ? wrappedInst.getValueObjectAtDataIndex() : wrappedInst.getValueObject();
        int result = db(inst.getClass()).updateLeanByIdVersion(inst);
        setOffEntityEvent(TopicEventType.UPDATE, inst.getClass(), inst.getId());
        return result;
    }

    @Override
    public  int add(Class fieldClass, String fieldName, T val, Query query)
            throws UnifyException {
        return db(query.getEntityClass()).add(fieldClass, fieldName, val, query);
    }

    @Override
    public  int subtract(Class fieldClass, String fieldName, T val,
            Query query) throws UnifyException {
        return db(query.getEntityClass()).subtract(fieldClass, fieldName, val, query);
    }

    @Override
    public  int multiply(Class fieldClass, String fieldName, T val,
            Query query) throws UnifyException {
        return db(query.getEntityClass()).multiply(fieldClass, fieldName, val, query);
    }

    @Override
    public  int divide(Class fieldClass, String fieldName, T val, Query query)
            throws UnifyException {
        return db(query.getEntityClass()).divide(fieldClass, fieldName, val, query);
    }

    @Override
    public  T min(Class fieldClass, String fieldName, Query query)
            throws UnifyException {
        return db(query.getEntityClass()).min(fieldClass, fieldName, query);
    }

    @Override
    public  T max(Class fieldClass, String fieldName, Query query)
            throws UnifyException {
        return db(query.getEntityClass()).max(fieldClass, fieldName, query);
    }

    @Override
    public int delete(Entity inst) throws UnifyException {
        int result = db(inst.getClass()).deleteByIdVersion(inst);
        setOffEntityEvent(TopicEventType.DELETE, inst.getClass(), inst.getId());
        return result;
    }

    @Override
    public EntityActionResult delete(EntityActionContext ctx) throws UnifyException {
        EntityActionResult result = executeEntityPreActionPolicy(ctx);
        if (result == null) {
            Entity inst = ctx.getInst();
            ctx.setResult(db(inst.getClass()).deleteByIdVersion(inst));
            releaseOriginalCopy(inst);
            result = executeEntityPostActionPolicy(db(inst.getClass()), ctx);
            setOffEntityEvent(TopicEventType.DELETE, inst.getClass(), inst.getId());
            return result;
        }

        return result;
    }

    @Override
    public  int delete(Class clazz, Object id) throws UnifyException {
        // TODO Release original copy
        int result = db(clazz).delete(clazz, id);
        setOffEntityEvent(TopicEventType.DELETE, clazz, id);
        return result;
    }

    @Override
    public int deleteAll(Query query) throws UnifyException {
        int result = db(query.getEntityClass()).deleteAll(query);
        setOffEntityEvent(TopicEventType.DELETE, query.getEntityClass(), null);
        return result;
    }

    @Override
    public int deleteByIdVersion(Entity record) throws UnifyException {
        int result = db(record.getClass()).deleteByIdVersion(record);
        releaseOriginalCopy(record);
        setOffEntityEvent(TopicEventType.DELETE, record.getClass(), record.getId());
        return result;
    }

    @Override
    public int deleteById(Entity record) throws UnifyException {
        int result = db(record.getClass()).deleteById(record);
        releaseOriginalCopy(record);
        setOffEntityEvent(TopicEventType.DELETE, record.getClass(), record.getId());
        return result;
    }

    @Override
    public int deleteById(EntityWrapper wrappedInst) throws UnifyException {
        Entity inst = wrappedInst.isIndexed() ? wrappedInst.getValueObjectAtDataIndex() : wrappedInst.getValueObject();
        int result = db(inst.getClass()).deleteById(inst);
        releaseOriginalCopy(inst);
        setOffEntityEvent(TopicEventType.DELETE, inst.getClass(), inst.getId());
        return result;
    }

    @Override
    public int deleteByIdVersion(EntityWrapper wrappedInst) throws UnifyException {
        Entity inst = wrappedInst.isIndexed() ? wrappedInst.getValueObjectAtDataIndex() : wrappedInst.getValueObject();
        int result = db(inst.getClass()).deleteByIdVersion(inst);
        setOffEntityEvent(TopicEventType.DELETE, inst.getClass(), inst.getId());
        return result;
    }

    private int releaseOriginalCopy(Entity inst) throws UnifyException {
        // TODO Put this in a policy
        if (inst instanceof WorkEntity && ((WorkEntity) inst).getOriginalCopyId() != null) {
            // Update original instance workflow flag
            return updateById((Class) inst.getClass(), ((WorkEntity) inst).getOriginalCopyId(),
                    new Update().add("inWorkflow", Boolean.FALSE));
        }

        return 0;
    }

    @Override
    public Aggregation aggregate(AggregateFunction aggregateFunction, Query query)
            throws UnifyException {
        return db_direct(query.getEntityClass()).aggregate(aggregateFunction, query);
    }

    @Override
    public List aggregate(List aggregateFunction, Query query)
            throws UnifyException {
        return db_direct(query.getEntityClass()).aggregate(aggregateFunction, query);
    }

    @Override
    public List aggregate(AggregateFunction aggregateFunction, Query query,
            GroupingFunction groupingFunction) throws UnifyException {
        return db_direct(query.getEntityClass()).aggregate(aggregateFunction, query, groupingFunction);
    }

    @Override
    public List aggregate(List aggregateFunction, Query query,
            GroupingFunction groupingFunction) throws UnifyException {
        return db_direct(query.getEntityClass()).aggregate(aggregateFunction, query, groupingFunction);
    }

    @Override
    public List aggregate(AggregateFunction aggregateFunction, Query query,
            List groupingFunction) throws UnifyException {
        return db_direct(query.getEntityClass()).aggregate(aggregateFunction, query, groupingFunction);
    }

    @Override
    public List aggregate(List aggregateFunction, Query query,
            List groupingFunction) throws UnifyException {
        return db_direct(query.getEntityClass()).aggregate(aggregateFunction, query, groupingFunction);
    }

    @Override
    public void populateListOnly(Entity record) throws UnifyException {
        db(record.getClass()).populateListOnly(record);
    }

    @Override
    public  int countAll(Query query) throws UnifyException {
        return db(query.getEntityClass()).countAll(query);
    }

    @Override
    public  T findConstraint(T record) throws UnifyException {
        return db(record.getClass()).findConstraint(record);
    }

    @Override
    public  List getAssignedList(Class entityClass, Class valueClass, String baseField,
            Object baseId, String valueField) throws UnifyException {
        return db(entityClass).valueList(valueClass, valueField, Query.of(entityClass).addEquals(baseField, baseId));
    }

    @Override
    public  Set getAssignedSet(Class entityClass, Class valueClass, String baseField,
            Object baseId, String valueField) throws UnifyException {
        return db(entityClass).valueSet(valueClass, valueField, Query.of(entityClass).addEquals(baseField, baseId));
    }

    @Override
    public  int updateAssignedList(SweepingCommitPolicy sweepingCommitPolicy,
            String assignmentUpdatePolicy, Class entityClass, String baseField, Object baseId, String valueField,
            List valueList) throws UnifyException {
        final Database db = db(entityClass);
        int updated = 0;
        db.deleteAll(Query.of(entityClass).addEquals(baseField, baseId));
        if (!DataUtils.isBlank(valueList)) {
            Entity inst = ReflectUtils.newInstance(entityClass); // TODO Get from class manager
            DataUtils.setBeanProperty(inst, baseField, baseId);
            for (T val : valueList) {
                DataUtils.setBeanProperty(inst, valueField, val);
                db.create(inst);
            }

            updated = valueList.size();
        }

        if (sweepingCommitPolicy != null) {
            sweepingCommitPolicy.bumpAllParentVersions(db, RecordActionType.UPDATE);
        }

        if (!StringUtils.isBlank(assignmentUpdatePolicy)) {
            ((ChildListEditPolicy) getComponent(assignmentUpdatePolicy)).postAssignmentUpdate(entityClass, baseField,
                    baseId);
        }

        return updated;
    }

    @Override
    public  int updateAssignedList(SweepingCommitPolicy sweepingCommitPolicy,
            String assignmentUpdatePolicy, Class entityClass, String baseField, Object baseId, List instList,
            boolean fixedAssignment) throws UnifyException {
        final Database db = db(entityClass);
        if (fixedAssignment) {
            if (!DataUtils.isBlank(instList)) {
                for (T inst : instList) {
                    DataUtils.setBeanProperty(inst, baseField, baseId);
                    db.updateByIdVersion((Entity) inst);
                }
            }
        } else {
            db.deleteAll(Query.of(entityClass).addEquals(baseField, baseId));
            if (!DataUtils.isBlank(instList)) {
                for (T inst : instList) {
                    DataUtils.setBeanProperty(inst, baseField, baseId);
                    db.create((Entity) inst);
                }
            }
        }

        if (sweepingCommitPolicy != null) {
            sweepingCommitPolicy.bumpAllParentVersions(db, RecordActionType.UPDATE);
        }

        if (!StringUtils.isBlank(assignmentUpdatePolicy)) {
            ((ChildListEditPolicy) getComponent(assignmentUpdatePolicy)).postAssignmentUpdate(entityClass, baseField,
                    baseId);
        }

        return instList != null ? instList.size() : 0;
    }

    @Override
    public  int updateEntryList(SweepingCommitPolicy sweepingCommitPolicy,
            String entryUpdatePolicy, Class entityClass, String baseField, Object baseId, List instList)
            throws UnifyException {
        final Database db = db(entityClass);
        if (!DataUtils.isBlank(instList)) {
            for (T inst : instList) {
                DataUtils.setBeanProperty(inst, baseField, baseId);
                db.updateByIdVersion((Entity) inst);
            }
        }

        if (sweepingCommitPolicy != null) {
            sweepingCommitPolicy.bumpAllParentVersions(db, RecordActionType.UPDATE);
        }

        if (!StringUtils.isBlank(entryUpdatePolicy)) {
            ((ChildListEditPolicy) getComponent(entryUpdatePolicy)).postEntryUpdate(entityClass, baseField, baseId,
                    instList);
        }

        return instList != null ? instList.size() : 0;
    }

    @Override
    public  T value(Class valueType, String valueFieldName, Query query) throws UnifyException {
        return db(query.getEntityClass()).value(valueType, valueFieldName, query);
    }

    @Override
    public  Optional valueOptional(Class valueType, String valueFieldName, Query query)
            throws UnifyException {
        return db(query.getEntityClass()).valueOptional(valueType, valueFieldName, query);
    }

    @Override
    public  List valueList(Class valueType, String valueFieldName, Query query)
            throws UnifyException {
        return db(query.getEntityClass()).valueList(valueType, valueFieldName, query);
    }

    @Override
    public  Set valueSet(Class fieldClass, String fieldName, Query query)
            throws UnifyException {
        return db(query.getEntityClass()).valueSet(fieldClass, fieldName, query);
    }

    @Override
    public  Map valueMap(Class keyClass, String keyName, Class valueClass,
            String valueName, Query query) throws UnifyException {
        return db(query.getEntityClass()).valueMap(keyClass, keyName, valueClass, valueName, query);
    }

    @Override
    public  Map> valueListMap(Class keyClass, String keyName, Class valueClass,
            String valueName, Query query) throws UnifyException {
        return db(query.getEntityClass()).valueListMap(keyClass, keyName, valueClass, valueName, query);
    }

    @Override
    public  T findFirst(Query query) throws UnifyException {
        return db(query.getEntityClass()).findFirst(query);
    }

    @Override
    public  T findLast(Query query) throws UnifyException {
        return db(query.getEntityClass()).findLast(query);
    }

    @Override
    public  T findLeanFirst(Query query) throws UnifyException {
        return db(query.getEntityClass()).findLeanFirst(query);
    }

    @Override
    public  T findLeanLast(Query query) throws UnifyException {
        return db(query.getEntityClass()).findLeanLast(query);
    }

    @Override
    public  T listFirst(Query query) throws UnifyException {
        return db(query.getEntityClass()).listFirst(query);
    }

    @Override
    public  T listLast(Query query) throws UnifyException {
        return db(query.getEntityClass()).listLast(query);
    }

    @Override
    public  T listLeanFirst(Query query) throws UnifyException {
        return db(query.getEntityClass()).listLeanFirst(query);
    }

    @Override
    public  T listLeanLast(Query query) throws UnifyException {
        return db(query.getEntityClass()).listLeanLast(query);
    }

    @Override
    public String getEntityDataSourceName(String entityLongName) throws UnifyException {
        EnvironmentDelegateHolder delegateInfo = environmentDelegateRegistrar
                .getEnvironmentDelegateInfo(entityLongName);
        return delegateInfo != null ? delegateInfo.getDataSourceName() : db().getDataSourceName();
    }

    @Override
    public String getEntityDataSourceName(Class entityClass) throws UnifyException {
        EnvironmentDelegateHolder delegateInfo = environmentDelegateRegistrar.getEnvironmentDelegateInfo(entityClass);
        return delegateInfo != null ? delegateInfo.getDataSourceName() : db().getDataSourceName();
    }

    @Override
    protected void setOffEntityEvent(TopicEventType eventType, Class entityClass, Object id)
            throws UnifyException {
        if (environmentDelegateRegistrar.isSupportsEntityChangeEvent(entityClass)) {
            super.setOffEntityEvent(eventType, entityClass, id);
        }
    }

    private Database db(Class entityClass) throws UnifyException {
        EnvironmentDelegateHolder delegateInfo = environmentDelegateRegistrar.getEnvironmentDelegateInfo(entityClass);
        return delegateInfo != null ? (delegateInfo.isDirect() ? db(delegateInfo.getDataSourceName())
                : delegateInfo.getEnvironmentDelegate()) : db();
    }

    private Database db_direct(Class entityClass) throws UnifyException {
        EnvironmentDelegateHolder delegateInfo = environmentDelegateRegistrar.getEnvironmentDelegateInfo(entityClass);
        return delegateInfo != null ? db(delegateInfo.getDataSourceName()) : db();
    }

    private EntityActionResult executeEntityPreActionPolicy(EntityActionContext ctx) throws UnifyException {
        if (ctx.isWithActionPolicy()) {
            return ((EntityActionPolicy) getComponent(ctx.getActionPolicyName())).executePreAction(ctx);
        }

        return null;
    }

    private EntityActionResult executeEntityPostActionPolicy(Database tdb, EntityActionContext ctx)
            throws UnifyException {
        if (ctx.isWithSweepingCommitPolicy()) {
            ctx.getSweepingCommitPolicy().bumpAllParentVersions(tdb, ctx.getActionType());
        }

        if (ctx.isWithActionPolicy()) {
            return ((EntityActionPolicy) getComponent(ctx.getActionPolicyName())).executePostAction(ctx);
        }

        return new EntityActionResult(ctx);
    }
}