45 changed files with 2320 additions and 1137 deletions
@ -0,0 +1,222 @@ |
|||
/** |
|||
* Copyright © 2016-2018 The Thingsboard 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.thingsboard.rule.engine.action; |
|||
|
|||
import com.google.common.cache.CacheBuilder; |
|||
import com.google.common.cache.CacheLoader; |
|||
import com.google.common.cache.LoadingCache; |
|||
import com.google.common.util.concurrent.Futures; |
|||
import com.google.common.util.concurrent.ListenableFuture; |
|||
import lombok.AllArgsConstructor; |
|||
import lombok.Data; |
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.thingsboard.rule.engine.api.TbContext; |
|||
import org.thingsboard.rule.engine.api.TbNode; |
|||
import org.thingsboard.rule.engine.api.TbNodeConfiguration; |
|||
import org.thingsboard.rule.engine.api.TbNodeException; |
|||
import org.thingsboard.rule.engine.api.util.TbNodeUtils; |
|||
import org.thingsboard.rule.engine.util.EntityContainer; |
|||
import org.thingsboard.server.common.data.Customer; |
|||
import org.thingsboard.server.common.data.DashboardInfo; |
|||
import org.thingsboard.server.common.data.Device; |
|||
import org.thingsboard.server.common.data.EntityType; |
|||
import org.thingsboard.server.common.data.EntityView; |
|||
import org.thingsboard.server.common.data.asset.Asset; |
|||
import org.thingsboard.server.common.data.id.EntityId; |
|||
import org.thingsboard.server.common.data.id.EntityIdFactory; |
|||
import org.thingsboard.server.common.data.page.TextPageData; |
|||
import org.thingsboard.server.common.data.page.TextPageLink; |
|||
import org.thingsboard.server.common.data.relation.EntitySearchDirection; |
|||
import org.thingsboard.server.common.msg.TbMsg; |
|||
import org.thingsboard.server.dao.asset.AssetService; |
|||
import org.thingsboard.server.dao.customer.CustomerService; |
|||
import org.thingsboard.server.dao.dashboard.DashboardService; |
|||
import org.thingsboard.server.dao.device.DeviceService; |
|||
import org.thingsboard.server.dao.entityview.EntityViewService; |
|||
|
|||
import java.util.Optional; |
|||
import java.util.concurrent.TimeUnit; |
|||
|
|||
import static org.thingsboard.rule.engine.api.TbRelationTypes.FAILURE; |
|||
import static org.thingsboard.rule.engine.api.TbRelationTypes.SUCCESS; |
|||
import static org.thingsboard.rule.engine.api.util.DonAsynchron.withCallback; |
|||
|
|||
@Slf4j |
|||
public abstract class TbAbstractRelationActionNode<C extends TbAbstractRelationActionNodeConfiguration> implements TbNode { |
|||
|
|||
protected C config; |
|||
protected EntityId fromId; |
|||
protected EntityId toId; |
|||
|
|||
private LoadingCache<Entitykey, EntityContainer> entityIdCache; |
|||
|
|||
@Override |
|||
public void init(TbContext ctx, TbNodeConfiguration configuration) throws TbNodeException { |
|||
this.config = loadEntityNodeActionConfig(configuration); |
|||
CacheBuilder cacheBuilder = CacheBuilder.newBuilder(); |
|||
if (this.config.getEntityCacheExpiration() > 0) { |
|||
cacheBuilder.expireAfterWrite(this.config.getEntityCacheExpiration(), TimeUnit.SECONDS); |
|||
} |
|||
entityIdCache = cacheBuilder |
|||
.build(new EntityCacheLoader(ctx, createEntityIfNotExists())); |
|||
} |
|||
|
|||
@Override |
|||
public void onMsg(TbContext ctx, TbMsg msg) { |
|||
withCallback(processEntityRelationAction(ctx, msg), |
|||
filterResult -> ctx.tellNext(msg, filterResult ? SUCCESS : FAILURE), t -> ctx.tellFailure(msg, t), ctx.getDbCallbackExecutor()); |
|||
} |
|||
|
|||
@Override |
|||
public void destroy() { |
|||
} |
|||
|
|||
private ListenableFuture<Boolean> processEntityRelationAction(TbContext ctx, TbMsg msg) { |
|||
return Futures.transformAsync(getEntity(ctx, msg), entityContainer -> doProcessEntityRelationAction(ctx, msg, entityContainer)); |
|||
} |
|||
|
|||
protected abstract boolean createEntityIfNotExists(); |
|||
|
|||
protected abstract ListenableFuture<Boolean> doProcessEntityRelationAction(TbContext ctx, TbMsg msg, EntityContainer entityContainer); |
|||
|
|||
protected abstract C loadEntityNodeActionConfig(TbNodeConfiguration configuration) throws TbNodeException; |
|||
|
|||
protected ListenableFuture<EntityContainer> getEntity(TbContext ctx, TbMsg msg) { |
|||
String entityName = TbNodeUtils.processPattern(this.config.getEntityNamePattern(), msg.getMetaData()); |
|||
String type = null; |
|||
if (this.config.getEntityTypePattern() != null) { |
|||
type = TbNodeUtils.processPattern(this.config.getEntityTypePattern(), msg.getMetaData()); |
|||
} |
|||
EntityType entityType = EntityType.valueOf(this.config.getEntityType()); |
|||
Entitykey key = new Entitykey(entityName, type, entityType); |
|||
return ctx.getDbCallbackExecutor().executeAsync(() -> { |
|||
EntityContainer entityContainer = entityIdCache.get(key); |
|||
if (entityContainer.getEntityId() == null) { |
|||
throw new RuntimeException("No entity found with type '" + key.getEntityType() + " ' and name '" + key.getEntityName() + "'."); |
|||
} |
|||
return entityContainer; |
|||
}); |
|||
} |
|||
|
|||
protected void processSearchDirection(TbMsg msg, EntityContainer entityContainer) { |
|||
if (EntitySearchDirection.FROM.name().equals(config.getDirection())) { |
|||
fromId = EntityIdFactory.getByTypeAndId(entityContainer.getEntityType().name(), entityContainer.getEntityId().toString()); |
|||
toId = msg.getOriginator(); |
|||
} else { |
|||
toId = EntityIdFactory.getByTypeAndId(entityContainer.getEntityType().name(), entityContainer.getEntityId().toString()); |
|||
fromId = msg.getOriginator(); |
|||
} |
|||
} |
|||
|
|||
@Data |
|||
@AllArgsConstructor |
|||
private static class Entitykey { |
|||
private String entityName; |
|||
private String type; |
|||
private EntityType entityType; |
|||
} |
|||
|
|||
private static class EntityCacheLoader extends CacheLoader<Entitykey, EntityContainer> { |
|||
|
|||
private final TbContext ctx; |
|||
private final boolean createIfNotExists; |
|||
|
|||
private EntityCacheLoader(TbContext ctx, boolean createIfNotExists) { |
|||
this.ctx = ctx; |
|||
this.createIfNotExists = createIfNotExists; |
|||
} |
|||
|
|||
@Override |
|||
public EntityContainer load(Entitykey key) { |
|||
return loadEntity(key); |
|||
} |
|||
|
|||
private EntityContainer loadEntity(Entitykey entitykey) { |
|||
EntityType type = entitykey.getEntityType(); |
|||
EntityContainer targetEntity = new EntityContainer(); |
|||
targetEntity.setEntityType(type); |
|||
switch (type) { |
|||
case DEVICE: |
|||
DeviceService deviceService = ctx.getDeviceService(); |
|||
Device device = deviceService.findDeviceByTenantIdAndName(ctx.getTenantId(), entitykey.getEntityName()); |
|||
if (device != null) { |
|||
targetEntity.setEntityId(device.getId()); |
|||
} else if (createIfNotExists) { |
|||
Device newDevice = new Device(); |
|||
newDevice.setName(entitykey.getEntityName()); |
|||
newDevice.setType(entitykey.getType()); |
|||
newDevice.setTenantId(ctx.getTenantId()); |
|||
Device savedDevice = deviceService.saveDevice(newDevice); |
|||
targetEntity.setEntityId(savedDevice.getId()); |
|||
} |
|||
break; |
|||
case ASSET: |
|||
AssetService assetService = ctx.getAssetService(); |
|||
Asset asset = assetService.findAssetByTenantIdAndName(ctx.getTenantId(), entitykey.getEntityName()); |
|||
if (asset != null) { |
|||
targetEntity.setEntityId(asset.getId()); |
|||
} else if (createIfNotExists) { |
|||
Asset newAsset = new Asset(); |
|||
newAsset.setName(entitykey.getEntityName()); |
|||
newAsset.setType(entitykey.getType()); |
|||
newAsset.setTenantId(ctx.getTenantId()); |
|||
Asset savedAsset = assetService.saveAsset(newAsset); |
|||
targetEntity.setEntityId(savedAsset.getId()); |
|||
} |
|||
break; |
|||
case CUSTOMER: |
|||
CustomerService customerService = ctx.getCustomerService(); |
|||
Optional<Customer> customerOptional = customerService.findCustomerByTenantIdAndTitle(ctx.getTenantId(), entitykey.getEntityName()); |
|||
if (customerOptional.isPresent()) { |
|||
targetEntity.setEntityId(customerOptional.get().getId()); |
|||
} else if (createIfNotExists) { |
|||
Customer newCustomer = new Customer(); |
|||
newCustomer.setTitle(entitykey.getEntityName()); |
|||
newCustomer.setTenantId(ctx.getTenantId()); |
|||
Customer savedCustomer = customerService.saveCustomer(newCustomer); |
|||
targetEntity.setEntityId(savedCustomer.getId()); |
|||
} |
|||
break; |
|||
case TENANT: |
|||
targetEntity.setEntityId(ctx.getTenantId()); |
|||
break; |
|||
case ENTITY_VIEW: |
|||
EntityViewService entityViewService = ctx.getEntityViewService(); |
|||
EntityView entityView = entityViewService.findEntityViewByTenantIdAndName(ctx.getTenantId(), entitykey.getEntityName()); |
|||
if (entityView != null) { |
|||
targetEntity.setEntityId(entityView.getId()); |
|||
} |
|||
break; |
|||
case DASHBOARD: |
|||
DashboardService dashboardService = ctx.getDashboardService(); |
|||
TextPageData<DashboardInfo> dashboardInfoTextPageData = dashboardService.findDashboardsByTenantId(ctx.getTenantId(), new TextPageLink(200, entitykey.getEntityName())); |
|||
for (DashboardInfo dashboardInfo : dashboardInfoTextPageData.getData()) { |
|||
if (dashboardInfo.getTitle().equals(entitykey.getEntityName())) { |
|||
targetEntity.setEntityId(dashboardInfo.getId()); |
|||
} |
|||
} |
|||
break; |
|||
default: |
|||
return targetEntity; |
|||
} |
|||
return targetEntity; |
|||
} |
|||
|
|||
|
|||
} |
|||
|
|||
|
|||
} |
|||
@ -0,0 +1,32 @@ |
|||
/** |
|||
* Copyright © 2016-2018 The Thingsboard 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.thingsboard.rule.engine.action; |
|||
|
|||
import lombok.Data; |
|||
|
|||
@Data |
|||
public abstract class TbAbstractRelationActionNodeConfiguration { |
|||
|
|||
private String direction; |
|||
private String relationType; |
|||
|
|||
private String entityType; |
|||
private String entityNamePattern; |
|||
private String entityTypePattern; |
|||
|
|||
private long entityCacheExpiration; |
|||
|
|||
} |
|||
@ -0,0 +1,156 @@ |
|||
/** |
|||
* Copyright © 2016-2018 The Thingsboard 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.thingsboard.rule.engine.action; |
|||
|
|||
import com.google.common.util.concurrent.Futures; |
|||
import com.google.common.util.concurrent.ListenableFuture; |
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.thingsboard.rule.engine.api.RuleNode; |
|||
import org.thingsboard.rule.engine.api.TbContext; |
|||
import org.thingsboard.rule.engine.api.TbNodeConfiguration; |
|||
import org.thingsboard.rule.engine.api.TbNodeException; |
|||
import org.thingsboard.rule.engine.api.util.TbNodeUtils; |
|||
import org.thingsboard.rule.engine.util.EntityContainer; |
|||
import org.thingsboard.server.common.data.id.AssetId; |
|||
import org.thingsboard.server.common.data.id.CustomerId; |
|||
import org.thingsboard.server.common.data.id.DashboardId; |
|||
import org.thingsboard.server.common.data.id.DeviceId; |
|||
import org.thingsboard.server.common.data.id.EntityViewId; |
|||
import org.thingsboard.server.common.data.id.TenantId; |
|||
import org.thingsboard.server.common.data.plugin.ComponentType; |
|||
import org.thingsboard.server.common.data.relation.EntityRelation; |
|||
import org.thingsboard.server.common.data.relation.RelationTypeGroup; |
|||
import org.thingsboard.server.common.msg.TbMsg; |
|||
|
|||
@Slf4j |
|||
@RuleNode( |
|||
type = ComponentType.ACTION, |
|||
name = "create relation", |
|||
configClazz = TbCreateRelationNodeConfiguration.class, |
|||
nodeDescription = "Finds target Entity by entity name pattern and (entity type pattern for Asset, Device) and then create a relation to Originator Entity by type and direction." + |
|||
" If Selected entity type: Asset, Device or Customer will create new Entity if it doesn't exist and 'Create new entity if not exists' is set to true.", |
|||
nodeDetails = "If the relation already exists or successfully created - Message send via <b>Success</b> chain, otherwise <b>Failure</b> chain will be used.", |
|||
uiResources = {"static/rulenode/rulenode-core-config.js"}, |
|||
configDirective = "tbActionNodeCreateRelationConfig", |
|||
icon = "add_circle" |
|||
) |
|||
public class TbCreateRelationNode extends TbAbstractRelationActionNode<TbCreateRelationNodeConfiguration> { |
|||
|
|||
@Override |
|||
protected TbCreateRelationNodeConfiguration loadEntityNodeActionConfig(TbNodeConfiguration configuration) throws TbNodeException { |
|||
return TbNodeUtils.convert(configuration, TbCreateRelationNodeConfiguration.class); |
|||
} |
|||
|
|||
@Override |
|||
protected boolean createEntityIfNotExists() { |
|||
return config.isCreateEntityIfNotExists(); |
|||
} |
|||
|
|||
@Override |
|||
protected ListenableFuture<Boolean> doProcessEntityRelationAction(TbContext ctx, TbMsg msg, EntityContainer entity) { |
|||
return createIfAbsent(ctx, msg, entity); |
|||
} |
|||
|
|||
private ListenableFuture<Boolean> createIfAbsent(TbContext ctx, TbMsg msg, EntityContainer entityContainer) { |
|||
processSearchDirection(msg, entityContainer); |
|||
return Futures.transformAsync(ctx.getRelationService().checkRelation(ctx.getTenantId(), fromId, toId, config.getRelationType(), RelationTypeGroup.COMMON), |
|||
result -> { |
|||
if (!result) { |
|||
return processCreateRelation(ctx, entityContainer); |
|||
} |
|||
return Futures.immediateFuture(true); |
|||
}); |
|||
} |
|||
|
|||
private ListenableFuture<Boolean> processCreateRelation(TbContext ctx, EntityContainer entityContainer) { |
|||
switch (entityContainer.getEntityType()) { |
|||
case ASSET: |
|||
return processAsset(ctx, entityContainer); |
|||
case DEVICE: |
|||
return processDevice(ctx, entityContainer); |
|||
case CUSTOMER: |
|||
return processCustomer(ctx, entityContainer); |
|||
case DASHBOARD: |
|||
return processDashboard(ctx, entityContainer); |
|||
case ENTITY_VIEW: |
|||
return processView(ctx, entityContainer); |
|||
case TENANT: |
|||
return processTenant(ctx, entityContainer); |
|||
} |
|||
return Futures.immediateFuture(true); |
|||
} |
|||
|
|||
private ListenableFuture<Boolean> processView(TbContext ctx, EntityContainer entityContainer) { |
|||
return Futures.transformAsync(ctx.getEntityViewService().findEntityViewByIdAsync(ctx.getTenantId(), new EntityViewId(entityContainer.getEntityId().getId())), entityView -> { |
|||
if (entityView != null) { |
|||
return ctx.getRelationService().saveRelationAsync(ctx.getTenantId(), new EntityRelation(fromId, toId, config.getRelationType(), RelationTypeGroup.COMMON)); |
|||
} else { |
|||
return Futures.immediateFuture(true); |
|||
} |
|||
}); |
|||
} |
|||
|
|||
private ListenableFuture<Boolean> processDevice(TbContext ctx, EntityContainer entityContainer) { |
|||
return Futures.transformAsync(ctx.getDeviceService().findDeviceByIdAsync(ctx.getTenantId(), new DeviceId(entityContainer.getEntityId().getId())), device -> { |
|||
if (device != null) { |
|||
return ctx.getRelationService().saveRelationAsync(ctx.getTenantId(), new EntityRelation(fromId, toId, config.getRelationType(), RelationTypeGroup.COMMON)); |
|||
} else { |
|||
return Futures.immediateFuture(true); |
|||
} |
|||
}); |
|||
} |
|||
|
|||
private ListenableFuture<Boolean> processAsset(TbContext ctx, EntityContainer entityContainer) { |
|||
return Futures.transformAsync(ctx.getAssetService().findAssetByIdAsync(ctx.getTenantId(), new AssetId(entityContainer.getEntityId().getId())), asset -> { |
|||
if (asset != null) { |
|||
return ctx.getRelationService().saveRelationAsync(ctx.getTenantId(), new EntityRelation(fromId, toId, config.getRelationType(), RelationTypeGroup.COMMON)); |
|||
} else { |
|||
return Futures.immediateFuture(true); |
|||
} |
|||
}); |
|||
} |
|||
|
|||
private ListenableFuture<Boolean> processCustomer(TbContext ctx, EntityContainer entityContainer) { |
|||
return Futures.transformAsync(ctx.getCustomerService().findCustomerByIdAsync(ctx.getTenantId(), new CustomerId(entityContainer.getEntityId().getId())), customer -> { |
|||
if (customer != null) { |
|||
return ctx.getRelationService().saveRelationAsync(ctx.getTenantId(), new EntityRelation(fromId, toId, config.getRelationType(), RelationTypeGroup.COMMON)); |
|||
} else { |
|||
return Futures.immediateFuture(true); |
|||
} |
|||
}); |
|||
} |
|||
|
|||
private ListenableFuture<Boolean> processDashboard(TbContext ctx, EntityContainer entityContainer) { |
|||
return Futures.transformAsync(ctx.getDashboardService().findDashboardByIdAsync(ctx.getTenantId(), new DashboardId(entityContainer.getEntityId().getId())), dashboard -> { |
|||
if (dashboard != null) { |
|||
return ctx.getRelationService().saveRelationAsync(ctx.getTenantId(), new EntityRelation(fromId, toId, config.getRelationType(), RelationTypeGroup.COMMON)); |
|||
} else { |
|||
return Futures.immediateFuture(true); |
|||
} |
|||
}); |
|||
} |
|||
|
|||
private ListenableFuture<Boolean> processTenant(TbContext ctx, EntityContainer entityContainer) { |
|||
return Futures.transformAsync(ctx.getTenantService().findTenantByIdAsync(ctx.getTenantId(), new TenantId(entityContainer.getEntityId().getId())), tenant -> { |
|||
if (tenant != null) { |
|||
return ctx.getRelationService().saveRelationAsync(ctx.getTenantId(), new EntityRelation(fromId, toId, config.getRelationType(), RelationTypeGroup.COMMON)); |
|||
} else { |
|||
return Futures.immediateFuture(true); |
|||
} |
|||
}); |
|||
} |
|||
|
|||
} |
|||
@ -0,0 +1,37 @@ |
|||
/** |
|||
* Copyright © 2016-2018 The Thingsboard 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.thingsboard.rule.engine.action; |
|||
|
|||
import lombok.Data; |
|||
import org.thingsboard.rule.engine.api.NodeConfiguration; |
|||
import org.thingsboard.server.common.data.relation.EntitySearchDirection; |
|||
|
|||
@Data |
|||
public class TbCreateRelationNodeConfiguration extends TbAbstractRelationActionNodeConfiguration implements NodeConfiguration<TbCreateRelationNodeConfiguration> { |
|||
|
|||
private boolean createEntityIfNotExists; |
|||
|
|||
@Override |
|||
public TbCreateRelationNodeConfiguration defaultConfiguration() { |
|||
TbCreateRelationNodeConfiguration configuration = new TbCreateRelationNodeConfiguration(); |
|||
configuration.setDirection(EntitySearchDirection.FROM.name()); |
|||
configuration.setRelationType("Contains"); |
|||
configuration.setEntityNamePattern(""); |
|||
configuration.setEntityCacheExpiration(300); |
|||
configuration.setCreateEntityIfNotExists(false); |
|||
return configuration; |
|||
} |
|||
} |
|||
@ -0,0 +1,74 @@ |
|||
/** |
|||
* Copyright © 2016-2018 The Thingsboard 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.thingsboard.rule.engine.action; |
|||
|
|||
import com.google.common.util.concurrent.Futures; |
|||
import com.google.common.util.concurrent.ListenableFuture; |
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.thingsboard.rule.engine.api.RuleNode; |
|||
import org.thingsboard.rule.engine.api.TbContext; |
|||
import org.thingsboard.rule.engine.api.TbNodeConfiguration; |
|||
import org.thingsboard.rule.engine.api.TbNodeException; |
|||
import org.thingsboard.rule.engine.api.util.TbNodeUtils; |
|||
import org.thingsboard.rule.engine.util.EntityContainer; |
|||
import org.thingsboard.server.common.data.plugin.ComponentType; |
|||
import org.thingsboard.server.common.data.relation.RelationTypeGroup; |
|||
import org.thingsboard.server.common.msg.TbMsg; |
|||
|
|||
@Slf4j |
|||
@RuleNode( |
|||
type = ComponentType.ACTION, |
|||
name = "delete relation", |
|||
configClazz = TbDeleteRelationNodeConfiguration.class, |
|||
nodeDescription = "Finds target Entity by entity name pattern and then delete a relation to Originator Entity by type and direction.", |
|||
nodeDetails = "If the relation successfully deleted - Message send via <b>Success</b> chain, otherwise <b>Failure</b> chain will be used.", |
|||
uiResources = {"static/rulenode/rulenode-core-config.js"}, |
|||
configDirective = "tbActionNodeDeleteRelationConfig", |
|||
icon = "remove_circle" |
|||
) |
|||
public class TbDeleteRelationNode extends TbAbstractRelationActionNode<TbDeleteRelationNodeConfiguration> { |
|||
|
|||
@Override |
|||
protected TbDeleteRelationNodeConfiguration loadEntityNodeActionConfig(TbNodeConfiguration configuration) throws TbNodeException { |
|||
return TbNodeUtils.convert(configuration, TbDeleteRelationNodeConfiguration.class); |
|||
} |
|||
|
|||
@Override |
|||
protected boolean createEntityIfNotExists() { |
|||
return false; |
|||
} |
|||
|
|||
@Override |
|||
protected ListenableFuture<Boolean> doProcessEntityRelationAction(TbContext ctx, TbMsg msg, EntityContainer entityContainer) { |
|||
return deleteIfExist(ctx, msg, entityContainer); |
|||
} |
|||
|
|||
private ListenableFuture<Boolean> deleteIfExist(TbContext ctx, TbMsg msg, EntityContainer entityContainer) { |
|||
processSearchDirection(msg, entityContainer); |
|||
return Futures.transformAsync(ctx.getRelationService().checkRelation(ctx.getTenantId(), fromId, toId, config.getRelationType(), RelationTypeGroup.COMMON), |
|||
result -> { |
|||
if (result) { |
|||
return processDeleteRelation(ctx); |
|||
} |
|||
return Futures.immediateFuture(true); |
|||
}); |
|||
} |
|||
|
|||
private ListenableFuture<Boolean> processDeleteRelation(TbContext ctx) { |
|||
return ctx.getRelationService().deleteRelationAsync(ctx.getTenantId(), fromId, toId, config.getRelationType(), RelationTypeGroup.COMMON); |
|||
} |
|||
|
|||
} |
|||
@ -0,0 +1,35 @@ |
|||
/** |
|||
* Copyright © 2016-2018 The Thingsboard 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.thingsboard.rule.engine.action; |
|||
|
|||
import lombok.Data; |
|||
import org.thingsboard.rule.engine.api.NodeConfiguration; |
|||
import org.thingsboard.server.common.data.relation.EntitySearchDirection; |
|||
|
|||
@Data |
|||
public class TbDeleteRelationNodeConfiguration extends TbAbstractRelationActionNodeConfiguration implements NodeConfiguration<TbDeleteRelationNodeConfiguration> { |
|||
|
|||
|
|||
@Override |
|||
public TbDeleteRelationNodeConfiguration defaultConfiguration() { |
|||
TbDeleteRelationNodeConfiguration configuration = new TbDeleteRelationNodeConfiguration(); |
|||
configuration.setDirection(EntitySearchDirection.FROM.name()); |
|||
configuration.setRelationType("Contains"); |
|||
configuration.setEntityNamePattern(""); |
|||
configuration.setEntityCacheExpiration(300); |
|||
return configuration; |
|||
} |
|||
} |
|||
@ -0,0 +1,28 @@ |
|||
/** |
|||
* Copyright © 2016-2018 The Thingsboard 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.thingsboard.rule.engine.util; |
|||
|
|||
import lombok.Data; |
|||
import org.thingsboard.server.common.data.EntityType; |
|||
import org.thingsboard.server.common.data.id.EntityId; |
|||
|
|||
@Data |
|||
public class EntityContainer { |
|||
|
|||
private EntityId entityId; |
|||
private EntityType entityType; |
|||
|
|||
} |
|||
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
File diff suppressed because it is too large
Loading…
Reference in new issue