Merge pull request #2735 from volodymyr-babak/bug/relation-concurrent-fix
Bug/relation concurrent fix
This commit is contained in:
		
						commit
						1c82df42e2
					
				@ -78,7 +78,8 @@ public abstract class TbAbstractRelationActionNode<C extends TbAbstractRelationA
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void onMsg(TbContext ctx, TbMsg msg) {
 | 
			
		||||
        withCallback(processEntityRelationAction(ctx, msg),
 | 
			
		||||
        String relationType = processPattern(msg, config.getRelationType());
 | 
			
		||||
        withCallback(processEntityRelationAction(ctx, msg, relationType),
 | 
			
		||||
                filterResult -> ctx.tellNext(filterResult.getMsg(), filterResult.isResult() ? SUCCESS : FAILURE), t -> ctx.tellFailure(msg, t), ctx.getDbCallbackExecutor());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -86,13 +87,13 @@ public abstract class TbAbstractRelationActionNode<C extends TbAbstractRelationA
 | 
			
		||||
    public void destroy() {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    protected ListenableFuture<RelationContainer> processEntityRelationAction(TbContext ctx, TbMsg msg) {
 | 
			
		||||
        return Futures.transformAsync(getEntity(ctx, msg), entityContainer -> doProcessEntityRelationAction(ctx, msg, entityContainer), MoreExecutors.directExecutor());
 | 
			
		||||
    protected ListenableFuture<RelationContainer> processEntityRelationAction(TbContext ctx, TbMsg msg, String relationType) {
 | 
			
		||||
        return Futures.transformAsync(getEntity(ctx, msg), entityContainer -> doProcessEntityRelationAction(ctx, msg, entityContainer, relationType), MoreExecutors.directExecutor());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    protected abstract boolean createEntityIfNotExists();
 | 
			
		||||
 | 
			
		||||
    protected abstract ListenableFuture<RelationContainer> doProcessEntityRelationAction(TbContext ctx, TbMsg msg, EntityContainer entityContainer);
 | 
			
		||||
    protected abstract ListenableFuture<RelationContainer> doProcessEntityRelationAction(TbContext ctx, TbMsg msg, EntityContainer entityContainer, String relationType);
 | 
			
		||||
 | 
			
		||||
    protected abstract C loadEntityNodeActionConfig(TbNodeConfiguration configuration) throws TbNodeException;
 | 
			
		||||
 | 
			
		||||
@ -120,11 +121,11 @@ public abstract class TbAbstractRelationActionNode<C extends TbAbstractRelationA
 | 
			
		||||
        if (EntitySearchDirection.FROM.name().equals(this.config.getDirection())) {
 | 
			
		||||
            searchDirectionIds.setFromId(EntityIdFactory.getByTypeAndId(entityContainer.getEntityType().name(), entityContainer.getEntityId().toString()));
 | 
			
		||||
            searchDirectionIds.setToId(msg.getOriginator());
 | 
			
		||||
            searchDirectionIds.setOrignatorDirectionFrom(false);
 | 
			
		||||
            searchDirectionIds.setOriginatorDirectionFrom(false);
 | 
			
		||||
        } else {
 | 
			
		||||
            searchDirectionIds.setToId(EntityIdFactory.getByTypeAndId(entityContainer.getEntityType().name(), entityContainer.getEntityId().toString()));
 | 
			
		||||
            searchDirectionIds.setFromId(msg.getOriginator());
 | 
			
		||||
            searchDirectionIds.setOrignatorDirectionFrom(true);
 | 
			
		||||
            searchDirectionIds.setOriginatorDirectionFrom(true);
 | 
			
		||||
        }
 | 
			
		||||
        return searchDirectionIds;
 | 
			
		||||
    }
 | 
			
		||||
@ -153,7 +154,7 @@ public abstract class TbAbstractRelationActionNode<C extends TbAbstractRelationA
 | 
			
		||||
    protected static class SearchDirectionIds {
 | 
			
		||||
        private EntityId fromId;
 | 
			
		||||
        private EntityId toId;
 | 
			
		||||
        private boolean orignatorDirectionFrom;
 | 
			
		||||
        private boolean originatorDirectionFrom;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private static class EntityCacheLoader extends CacheLoader<EntityKey, EntityContainer> {
 | 
			
		||||
 | 
			
		||||
@ -57,8 +57,6 @@ import java.util.List;
 | 
			
		||||
)
 | 
			
		||||
public class TbCreateRelationNode extends TbAbstractRelationActionNode<TbCreateRelationNodeConfiguration> {
 | 
			
		||||
 | 
			
		||||
    private String relationType;
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    protected TbCreateRelationNodeConfiguration loadEntityNodeActionConfig(TbNodeConfiguration configuration) throws TbNodeException {
 | 
			
		||||
        return TbNodeUtils.convert(configuration, TbCreateRelationNodeConfiguration.class);
 | 
			
		||||
@ -70,8 +68,8 @@ public class TbCreateRelationNode extends TbAbstractRelationActionNode<TbCreateR
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    protected ListenableFuture<RelationContainer> doProcessEntityRelationAction(TbContext ctx, TbMsg msg, EntityContainer entity) {
 | 
			
		||||
        ListenableFuture<Boolean> future = createIfAbsent(ctx, msg, entity);
 | 
			
		||||
    protected ListenableFuture<RelationContainer> doProcessEntityRelationAction(TbContext ctx, TbMsg msg, EntityContainer entity, String relationType) {
 | 
			
		||||
        ListenableFuture<Boolean> future = createIfAbsent(ctx, msg, entity, relationType);
 | 
			
		||||
        return Futures.transform(future, result -> {
 | 
			
		||||
            RelationContainer container = new RelationContainer();
 | 
			
		||||
            if (result && config.isChangeOriginatorToRelatedEntity()) {
 | 
			
		||||
@ -85,13 +83,12 @@ public class TbCreateRelationNode extends TbAbstractRelationActionNode<TbCreateR
 | 
			
		||||
        }, MoreExecutors.directExecutor());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private ListenableFuture<Boolean> createIfAbsent(TbContext ctx, TbMsg msg, EntityContainer entityContainer) {
 | 
			
		||||
        relationType = processPattern(msg, config.getRelationType());
 | 
			
		||||
    private ListenableFuture<Boolean> createIfAbsent(TbContext ctx, TbMsg msg, EntityContainer entityContainer, String relationType) {
 | 
			
		||||
        SearchDirectionIds sdId = processSingleSearchDirection(msg, entityContainer);
 | 
			
		||||
        ListenableFuture<Boolean> checkRelationFuture = Futures.transformAsync(ctx.getRelationService().checkRelation(ctx.getTenantId(), sdId.getFromId(), sdId.getToId(), relationType, RelationTypeGroup.COMMON), result -> {
 | 
			
		||||
            if (!result) {
 | 
			
		||||
                if (config.isRemoveCurrentRelations()) {
 | 
			
		||||
                    return processDeleteRelations(ctx, processFindRelations(ctx, msg, sdId));
 | 
			
		||||
                    return processDeleteRelations(ctx, processFindRelations(ctx, msg, sdId, relationType));
 | 
			
		||||
                }
 | 
			
		||||
                return Futures.immediateFuture(false);
 | 
			
		||||
            }
 | 
			
		||||
@ -100,14 +97,14 @@ public class TbCreateRelationNode extends TbAbstractRelationActionNode<TbCreateR
 | 
			
		||||
 | 
			
		||||
        return Futures.transformAsync(checkRelationFuture, result -> {
 | 
			
		||||
            if (!result) {
 | 
			
		||||
                return processCreateRelation(ctx, entityContainer, sdId);
 | 
			
		||||
                return processCreateRelation(ctx, entityContainer, sdId, relationType);
 | 
			
		||||
            }
 | 
			
		||||
            return Futures.immediateFuture(true);
 | 
			
		||||
        }, ctx.getDbCallbackExecutor());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private ListenableFuture<List<EntityRelation>> processFindRelations(TbContext ctx, TbMsg msg, SearchDirectionIds sdId) {
 | 
			
		||||
        if (sdId.isOrignatorDirectionFrom()) {
 | 
			
		||||
    private ListenableFuture<List<EntityRelation>> processFindRelations(TbContext ctx, TbMsg msg, SearchDirectionIds sdId, String relationType) {
 | 
			
		||||
        if (sdId.isOriginatorDirectionFrom()) {
 | 
			
		||||
            return ctx.getRelationService().findByFromAndTypeAsync(ctx.getTenantId(), msg.getOriginator(), relationType, RelationTypeGroup.COMMON);
 | 
			
		||||
        } else {
 | 
			
		||||
            return ctx.getRelationService().findByToAndTypeAsync(ctx.getTenantId(), msg.getOriginator(), relationType, RelationTypeGroup.COMMON);
 | 
			
		||||
@ -127,85 +124,85 @@ public class TbCreateRelationNode extends TbAbstractRelationActionNode<TbCreateR
 | 
			
		||||
        }, ctx.getDbCallbackExecutor());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private ListenableFuture<Boolean> processCreateRelation(TbContext ctx, EntityContainer entityContainer, SearchDirectionIds sdId) {
 | 
			
		||||
    private ListenableFuture<Boolean> processCreateRelation(TbContext ctx, EntityContainer entityContainer, SearchDirectionIds sdId, String relationType) {
 | 
			
		||||
        switch (entityContainer.getEntityType()) {
 | 
			
		||||
            case ASSET:
 | 
			
		||||
                return processAsset(ctx, entityContainer, sdId);
 | 
			
		||||
                return processAsset(ctx, entityContainer, sdId, relationType);
 | 
			
		||||
            case DEVICE:
 | 
			
		||||
                return processDevice(ctx, entityContainer, sdId);
 | 
			
		||||
                return processDevice(ctx, entityContainer, sdId, relationType);
 | 
			
		||||
            case CUSTOMER:
 | 
			
		||||
                return processCustomer(ctx, entityContainer, sdId);
 | 
			
		||||
                return processCustomer(ctx, entityContainer, sdId, relationType);
 | 
			
		||||
            case DASHBOARD:
 | 
			
		||||
                return processDashboard(ctx, entityContainer, sdId);
 | 
			
		||||
                return processDashboard(ctx, entityContainer, sdId, relationType);
 | 
			
		||||
            case ENTITY_VIEW:
 | 
			
		||||
                return processView(ctx, entityContainer, sdId);
 | 
			
		||||
                return processView(ctx, entityContainer, sdId, relationType);
 | 
			
		||||
            case TENANT:
 | 
			
		||||
                return processTenant(ctx, entityContainer, sdId);
 | 
			
		||||
                return processTenant(ctx, entityContainer, sdId, relationType);
 | 
			
		||||
        }
 | 
			
		||||
        return Futures.immediateFuture(true);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private ListenableFuture<Boolean> processView(TbContext ctx, EntityContainer entityContainer, SearchDirectionIds sdId) {
 | 
			
		||||
    private ListenableFuture<Boolean> processView(TbContext ctx, EntityContainer entityContainer, SearchDirectionIds sdId, String relationType) {
 | 
			
		||||
        return Futures.transformAsync(ctx.getEntityViewService().findEntityViewByIdAsync(ctx.getTenantId(), new EntityViewId(entityContainer.getEntityId().getId())), entityView -> {
 | 
			
		||||
            if (entityView != null) {
 | 
			
		||||
                return processSave(ctx, sdId);
 | 
			
		||||
                return processSave(ctx, sdId, relationType);
 | 
			
		||||
            } else {
 | 
			
		||||
                return Futures.immediateFuture(true);
 | 
			
		||||
            }
 | 
			
		||||
        }, ctx.getDbCallbackExecutor());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private ListenableFuture<Boolean> processDevice(TbContext ctx, EntityContainer entityContainer, SearchDirectionIds sdId) {
 | 
			
		||||
    private ListenableFuture<Boolean> processDevice(TbContext ctx, EntityContainer entityContainer, SearchDirectionIds sdId, String relationType) {
 | 
			
		||||
        return Futures.transformAsync(ctx.getDeviceService().findDeviceByIdAsync(ctx.getTenantId(), new DeviceId(entityContainer.getEntityId().getId())), device -> {
 | 
			
		||||
            if (device != null) {
 | 
			
		||||
                return processSave(ctx, sdId);
 | 
			
		||||
                return processSave(ctx, sdId, relationType);
 | 
			
		||||
            } else {
 | 
			
		||||
                return Futures.immediateFuture(true);
 | 
			
		||||
            }
 | 
			
		||||
        }, MoreExecutors.directExecutor());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private ListenableFuture<Boolean> processAsset(TbContext ctx, EntityContainer entityContainer, SearchDirectionIds sdId) {
 | 
			
		||||
    private ListenableFuture<Boolean> processAsset(TbContext ctx, EntityContainer entityContainer, SearchDirectionIds sdId, String relationType) {
 | 
			
		||||
        return Futures.transformAsync(ctx.getAssetService().findAssetByIdAsync(ctx.getTenantId(), new AssetId(entityContainer.getEntityId().getId())), asset -> {
 | 
			
		||||
            if (asset != null) {
 | 
			
		||||
                return processSave(ctx, sdId);
 | 
			
		||||
                return processSave(ctx, sdId, relationType);
 | 
			
		||||
            } else {
 | 
			
		||||
                return Futures.immediateFuture(true);
 | 
			
		||||
            }
 | 
			
		||||
        }, ctx.getDbCallbackExecutor());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private ListenableFuture<Boolean> processCustomer(TbContext ctx, EntityContainer entityContainer, SearchDirectionIds sdId) {
 | 
			
		||||
    private ListenableFuture<Boolean> processCustomer(TbContext ctx, EntityContainer entityContainer, SearchDirectionIds sdId, String relationType) {
 | 
			
		||||
        return Futures.transformAsync(ctx.getCustomerService().findCustomerByIdAsync(ctx.getTenantId(), new CustomerId(entityContainer.getEntityId().getId())), customer -> {
 | 
			
		||||
            if (customer != null) {
 | 
			
		||||
                return processSave(ctx, sdId);
 | 
			
		||||
                return processSave(ctx, sdId, relationType);
 | 
			
		||||
            } else {
 | 
			
		||||
                return Futures.immediateFuture(true);
 | 
			
		||||
            }
 | 
			
		||||
        }, ctx.getDbCallbackExecutor());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private ListenableFuture<Boolean> processDashboard(TbContext ctx, EntityContainer entityContainer, SearchDirectionIds sdId) {
 | 
			
		||||
    private ListenableFuture<Boolean> processDashboard(TbContext ctx, EntityContainer entityContainer, SearchDirectionIds sdId, String relationType) {
 | 
			
		||||
        return Futures.transformAsync(ctx.getDashboardService().findDashboardByIdAsync(ctx.getTenantId(), new DashboardId(entityContainer.getEntityId().getId())), dashboard -> {
 | 
			
		||||
            if (dashboard != null) {
 | 
			
		||||
                return processSave(ctx, sdId);
 | 
			
		||||
                return processSave(ctx, sdId, relationType);
 | 
			
		||||
            } else {
 | 
			
		||||
                return Futures.immediateFuture(true);
 | 
			
		||||
            }
 | 
			
		||||
        }, ctx.getDbCallbackExecutor());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private ListenableFuture<Boolean> processTenant(TbContext ctx, EntityContainer entityContainer, SearchDirectionIds sdId) {
 | 
			
		||||
    private ListenableFuture<Boolean> processTenant(TbContext ctx, EntityContainer entityContainer, SearchDirectionIds sdId, String relationType) {
 | 
			
		||||
        return Futures.transformAsync(ctx.getTenantService().findTenantByIdAsync(ctx.getTenantId(), new TenantId(entityContainer.getEntityId().getId())), tenant -> {
 | 
			
		||||
            if (tenant != null) {
 | 
			
		||||
                return processSave(ctx, sdId);
 | 
			
		||||
                return processSave(ctx, sdId, relationType);
 | 
			
		||||
            } else {
 | 
			
		||||
                return Futures.immediateFuture(true);
 | 
			
		||||
            }
 | 
			
		||||
        }, ctx.getDbCallbackExecutor());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private ListenableFuture<Boolean> processSave(TbContext ctx, SearchDirectionIds sdId) {
 | 
			
		||||
    private ListenableFuture<Boolean> processSave(TbContext ctx, SearchDirectionIds sdId, String relationType) {
 | 
			
		||||
        return ctx.getRelationService().saveRelationAsync(ctx.getTenantId(), new EntityRelation(sdId.getFromId(), sdId.getToId(), relationType, RelationTypeGroup.COMMON));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -48,8 +48,6 @@ import java.util.List;
 | 
			
		||||
)
 | 
			
		||||
public class TbDeleteRelationNode extends TbAbstractRelationActionNode<TbDeleteRelationNodeConfiguration> {
 | 
			
		||||
 | 
			
		||||
    private String relationType;
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    protected TbDeleteRelationNodeConfiguration loadEntityNodeActionConfig(TbNodeConfiguration configuration) throws TbNodeException {
 | 
			
		||||
        return TbNodeUtils.convert(configuration, TbDeleteRelationNodeConfiguration.class);
 | 
			
		||||
@ -61,19 +59,18 @@ public class TbDeleteRelationNode extends TbAbstractRelationActionNode<TbDeleteR
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    protected ListenableFuture<RelationContainer> processEntityRelationAction(TbContext ctx, TbMsg msg) {
 | 
			
		||||
        return getRelationContainerListenableFuture(ctx, msg);
 | 
			
		||||
    protected ListenableFuture<RelationContainer> processEntityRelationAction(TbContext ctx, TbMsg msg, String relationType) {
 | 
			
		||||
        return getRelationContainerListenableFuture(ctx, msg, relationType);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    protected ListenableFuture<RelationContainer> doProcessEntityRelationAction(TbContext ctx, TbMsg msg, EntityContainer entityContainer) {
 | 
			
		||||
        return Futures.transform(processSingle(ctx, msg, entityContainer), result -> new RelationContainer(msg, result), MoreExecutors.directExecutor());
 | 
			
		||||
    protected ListenableFuture<RelationContainer> doProcessEntityRelationAction(TbContext ctx, TbMsg msg, EntityContainer entityContainer, String relationType) {
 | 
			
		||||
        return Futures.transform(processSingle(ctx, msg, entityContainer, relationType), result -> new RelationContainer(msg, result), MoreExecutors.directExecutor());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private ListenableFuture<RelationContainer> getRelationContainerListenableFuture(TbContext ctx, TbMsg msg) {
 | 
			
		||||
        relationType = processPattern(msg, config.getRelationType());
 | 
			
		||||
    private ListenableFuture<RelationContainer> getRelationContainerListenableFuture(TbContext ctx, TbMsg msg, String relationType) {
 | 
			
		||||
        if (config.isDeleteForSingleEntity()) {
 | 
			
		||||
            return Futures.transformAsync(getEntity(ctx, msg), entityContainer -> doProcessEntityRelationAction(ctx, msg, entityContainer), MoreExecutors.directExecutor());
 | 
			
		||||
            return Futures.transformAsync(getEntity(ctx, msg), entityContainer -> doProcessEntityRelationAction(ctx, msg, entityContainer, relationType), MoreExecutors.directExecutor());
 | 
			
		||||
        } else {
 | 
			
		||||
            return Futures.transform(processList(ctx, msg), result -> new RelationContainer(msg, result), MoreExecutors.directExecutor());
 | 
			
		||||
        }
 | 
			
		||||
@ -100,18 +97,18 @@ public class TbDeleteRelationNode extends TbAbstractRelationActionNode<TbDeleteR
 | 
			
		||||
        }, MoreExecutors.directExecutor());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private ListenableFuture<Boolean> processSingle(TbContext ctx, TbMsg msg, EntityContainer entityContainer) {
 | 
			
		||||
    private ListenableFuture<Boolean> processSingle(TbContext ctx, TbMsg msg, EntityContainer entityContainer, String relationType) {
 | 
			
		||||
        SearchDirectionIds sdId = processSingleSearchDirection(msg, entityContainer);
 | 
			
		||||
        return Futures.transformAsync(ctx.getRelationService().checkRelation(ctx.getTenantId(), sdId.getFromId(), sdId.getToId(), relationType, RelationTypeGroup.COMMON),
 | 
			
		||||
                result -> {
 | 
			
		||||
                    if (result) {
 | 
			
		||||
                        return processSingleDeleteRelation(ctx, sdId);
 | 
			
		||||
                        return processSingleDeleteRelation(ctx, sdId, relationType);
 | 
			
		||||
                    }
 | 
			
		||||
                    return Futures.immediateFuture(true);
 | 
			
		||||
                }, MoreExecutors.directExecutor());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private ListenableFuture<Boolean> processSingleDeleteRelation(TbContext ctx, SearchDirectionIds sdId) {
 | 
			
		||||
    private ListenableFuture<Boolean> processSingleDeleteRelation(TbContext ctx, SearchDirectionIds sdId, String relationType) {
 | 
			
		||||
        return ctx.getRelationService().deleteRelationAsync(ctx.getTenantId(), sdId.getFromId(), sdId.getToId(), relationType, RelationTypeGroup.COMMON);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user