Browse Source

Ability to change Root rule chain.

pull/804/head
Igor Kulikov 8 years ago
parent
commit
bce5d9332e
  1. 17
      application/src/main/java/org/thingsboard/server/actors/ruleChain/DefaultTbContext.java
  2. 2
      application/src/main/java/org/thingsboard/server/actors/shared/EntityActorsManager.java
  3. 2
      application/src/main/java/org/thingsboard/server/actors/shared/rulechain/RuleChainManager.java
  4. 6
      application/src/main/java/org/thingsboard/server/actors/shared/rulechain/SystemRuleChainManager.java
  5. 8
      application/src/main/java/org/thingsboard/server/actors/tenant/TenantActor.java
  6. 13
      application/src/main/java/org/thingsboard/server/controller/BaseController.java
  7. 94
      application/src/main/java/org/thingsboard/server/controller/RuleChainController.java
  8. 16
      dao/src/main/java/org/thingsboard/server/dao/nosql/CassandraAbstractDao.java
  9. 79
      dao/src/main/java/org/thingsboard/server/dao/rule/BaseRuleChainService.java
  10. 11
      dao/src/main/java/org/thingsboard/server/dao/rule/CassandraRuleChainDao.java
  11. 9
      dao/src/main/java/org/thingsboard/server/dao/rule/RuleChainDao.java
  12. 6
      dao/src/main/java/org/thingsboard/server/dao/rule/RuleChainService.java
  13. 11
      dao/src/main/java/org/thingsboard/server/dao/sql/rule/JpaRuleChainDao.java
  14. 8
      dao/src/main/java/org/thingsboard/server/dao/sql/rule/RuleChainRepository.java
  15. 6
      rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/TbContext.java
  16. 6
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbAbstractAlarmNode.java
  17. 52
      ui/src/app/api/rule-chain.service.js
  18. 4
      ui/src/app/locale/locale.constant.js
  19. 2
      ui/src/app/rulechain/rulechain-card.tpl.html
  20. 5
      ui/src/app/rulechain/rulechain-fieldset.tpl.html
  21. 1
      ui/src/app/rulechain/rulechain.directive.js
  22. 2
      ui/src/app/rulechain/rulechain.routes.js
  23. 53
      ui/src/app/rulechain/rulechains.controller.js
  24. 4
      ui/src/app/rulechain/rulechains.tpl.html

17
application/src/main/java/org/thingsboard/server/actors/ruleChain/DefaultTbContext.java

@ -84,21 +84,6 @@ class DefaultTbContext implements TbContext {
mainCtx.getScheduler().scheduleOnce(Duration.create(delayInMs, TimeUnit.MILLISECONDS), target, msg, mainCtx.getActorSystem().dispatcher(), nodeCtx.getSelfActor());
}
@Override
public void tellOthers(TbMsg msg) {
throw new RuntimeException("Not Implemented!");
}
@Override
public void tellSibling(TbMsg msg, ServerAddress address) {
throw new RuntimeException("Not Implemented!");
}
@Override
public void ack(TbMsg msg) {
}
@Override
public void tellError(TbMsg msg, Throwable th) {
if (nodeCtx.getSelf().isDebugMode()) {
@ -119,7 +104,7 @@ class DefaultTbContext implements TbContext {
@Override
public TbMsg transformMsg(TbMsg origMsg, String type, EntityId originator, TbMsgMetaData metaData, String data) {
return new TbMsg(origMsg.getId(), type, originator, metaData.copy(), data, nodeCtx.getSelf().getRuleChainId(), nodeCtx.getSelf().getId(), 0L);
return new TbMsg(origMsg.getId(), type, originator, metaData.copy(), data, origMsg.getRuleChainId(), origMsg.getRuleNodeId(), 0L);
}
@Override

2
application/src/main/java/org/thingsboard/server/actors/shared/EntityActorsManager.java

@ -67,7 +67,7 @@ public abstract class EntityActorsManager<T extends EntityId, A extends UntypedA
}
}
protected void visit(M entity, ActorRef actorRef) {}
public void visit(M entity, ActorRef actorRef) {}
public ActorRef getOrCreateActor(ActorContext context, T entityId) {
return actors.computeIfAbsent(entityId, eId ->

2
application/src/main/java/org/thingsboard/server/actors/shared/rulechain/RuleChainManager.java

@ -49,7 +49,7 @@ public abstract class RuleChainManager extends EntityActorsManager<RuleChainId,
}
@Override
protected void visit(RuleChain entity, ActorRef actorRef) {
public void visit(RuleChain entity, ActorRef actorRef) {
if (entity.isRoot()) {
rootChain = entity;
rootChainActor = actorRef;

6
application/src/main/java/org/thingsboard/server/actors/shared/rulechain/SystemRuleChainManager.java

@ -20,10 +20,14 @@ import org.thingsboard.server.actors.service.DefaultActorService;
import org.thingsboard.server.actors.shared.plugin.PluginManager;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.page.PageDataIterable.FetchFunction;
import org.thingsboard.server.common.data.page.TextPageData;
import org.thingsboard.server.common.data.page.TextPageLink;
import org.thingsboard.server.common.data.plugin.PluginMetaData;
import org.thingsboard.server.common.data.rule.RuleChain;
import org.thingsboard.server.dao.plugin.BasePluginService;
import java.util.Collections;
public class SystemRuleChainManager extends RuleChainManager {
public SystemRuleChainManager(ActorSystemContext systemContext) {
@ -32,7 +36,7 @@ public class SystemRuleChainManager extends RuleChainManager {
@Override
protected FetchFunction<RuleChain> getFetchEntitiesFunction() {
return service::findSystemRuleChains;
return link -> new TextPageData<>(Collections.emptyList(), link);
}
@Override

8
application/src/main/java/org/thingsboard/server/actors/tenant/TenantActor.java

@ -30,8 +30,11 @@ import org.thingsboard.server.actors.service.ContextBasedCreator;
import org.thingsboard.server.actors.service.DefaultActorService;
import org.thingsboard.server.actors.shared.plugin.TenantPluginManager;
import org.thingsboard.server.actors.shared.rulechain.TenantRuleChainManager;
import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.id.DeviceId;
import org.thingsboard.server.common.data.id.RuleChainId;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.rule.RuleChain;
import org.thingsboard.server.common.msg.TbActorMsg;
import org.thingsboard.server.common.msg.aware.DeviceAwareMsg;
import org.thingsboard.server.common.msg.device.DeviceToDeviceActorMsg;
@ -130,6 +133,11 @@ public class TenantActor extends RuleChainManagerActor {
private void onComponentLifecycleMsg(ComponentLifecycleMsg msg) {
ActorRef target = getEntityActorRef(msg.getEntityId());
if (target != null) {
if (msg.getEntityId().getEntityType() == EntityType.RULE_CHAIN) {
RuleChain ruleChain = systemContext.getRuleChainService().
findRuleChainById(new RuleChainId(msg.getEntityId().getId()));
ruleChainManager.visit(ruleChain, target);
}
target.tell(msg, ActorRef.noSender());
} else {
logger.debug("Invalid component lifecycle msg: {}", msg);

13
application/src/main/java/org/thingsboard/server/controller/BaseController.java

@ -558,15 +558,10 @@ public abstract class BaseController {
SecurityUser authUser = getCurrentUser();
TenantId tenantId = ruleChain.getTenantId();
validateId(tenantId, INCORRECT_TENANT_ID + tenantId);
if (authUser.getAuthority() != Authority.SYS_ADMIN) {
if (authUser.getTenantId() == null ||
!tenantId.getId().equals(ModelConstants.NULL_UUID) && !authUser.getTenantId().equals(tenantId)) {
throw new ThingsboardException(YOU_DON_T_HAVE_PERMISSION_TO_PERFORM_THIS_OPERATION,
ThingsboardErrorCode.PERMISSION_DENIED);
} else if (tenantId.getId().equals(ModelConstants.NULL_UUID)) {
ruleChain.setConfiguration(null);
}
if (authUser.getAuthority() != Authority.TENANT_ADMIN ||
!authUser.getTenantId().equals(tenantId)) {
throw new ThingsboardException(YOU_DON_T_HAVE_PERMISSION_TO_PERFORM_THIS_OPERATION,
ThingsboardErrorCode.PERMISSION_DENIED);
}
return ruleChain;
}

94
application/src/main/java/org/thingsboard/server/controller/RuleChainController.java

@ -64,7 +64,7 @@ public class RuleChainController extends BaseController {
@Autowired
private EventService eventService;
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')")
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN')")
@RequestMapping(value = "/ruleChain/{ruleChainId}", method = RequestMethod.GET)
@ResponseBody
public RuleChain getRuleChainById(@PathVariable(RULE_CHAIN_ID) String strRuleChainId) throws ThingsboardException {
@ -77,7 +77,7 @@ public class RuleChainController extends BaseController {
}
}
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')")
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN')")
@RequestMapping(value = "/ruleChain/{ruleChainId}/metadata", method = RequestMethod.GET)
@ResponseBody
public RuleChainMetaData getRuleChainMetaData(@PathVariable(RULE_CHAIN_ID) String strRuleChainId) throws ThingsboardException {
@ -92,7 +92,7 @@ public class RuleChainController extends BaseController {
}
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')")
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN')")
@RequestMapping(value = "/ruleChain", method = RequestMethod.POST)
@ResponseBody
public RuleChain saveRuleChain(@RequestBody RuleChain ruleChain) throws ThingsboardException {
@ -118,7 +118,46 @@ public class RuleChainController extends BaseController {
}
}
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')")
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN')")
@RequestMapping(value = "/ruleChain/{ruleChainId}/root", method = RequestMethod.POST)
@ResponseBody
public RuleChain setRootRuleChain(@PathVariable(RULE_CHAIN_ID) String strRuleChainId) throws ThingsboardException {
checkParameter(RULE_CHAIN_ID, strRuleChainId);
try {
RuleChainId ruleChainId = new RuleChainId(toUUID(strRuleChainId));
RuleChain ruleChain = checkRuleChain(ruleChainId);
TenantId tenantId = getCurrentUser().getTenantId();
RuleChain previousRootRuleChain = ruleChainService.getRootTenantRuleChain(tenantId);
if (ruleChainService.setRootRuleChain(ruleChainId)) {
previousRootRuleChain = ruleChainService.findRuleChainById(previousRootRuleChain.getId());
actorService.onEntityStateChange(previousRootRuleChain.getTenantId(), previousRootRuleChain.getId(),
ComponentLifecycleEvent.UPDATED);
logEntityAction(previousRootRuleChain.getId(), previousRootRuleChain,
null, ActionType.UPDATED, null);
ruleChain = ruleChainService.findRuleChainById(ruleChainId);
actorService.onEntityStateChange(ruleChain.getTenantId(), ruleChain.getId(),
ComponentLifecycleEvent.UPDATED);
logEntityAction(ruleChain.getId(), ruleChain,
null, ActionType.UPDATED, null);
}
return ruleChain;
} catch (Exception e) {
logEntityAction(emptyId(EntityType.RULE_CHAIN),
null,
null,
ActionType.UPDATED, e, strRuleChainId);
throw handleException(e);
}
}
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN')")
@RequestMapping(value = "/ruleChain/metadata", method = RequestMethod.POST)
@ResponseBody
public RuleChainMetaData saveRuleChainMetaData(@RequestBody RuleChainMetaData ruleChainMetaData) throws ThingsboardException {
@ -142,7 +181,7 @@ public class RuleChainController extends BaseController {
}
}
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')")
@PreAuthorize("hasAuthority('TENANT_ADMIN')")
@RequestMapping(value = "/ruleChains", params = {"limit"}, method = RequestMethod.GET)
@ResponseBody
public TextPageData<RuleChain> getRuleChains(
@ -150,48 +189,6 @@ public class RuleChainController extends BaseController {
@RequestParam(required = false) String textSearch,
@RequestParam(required = false) String idOffset,
@RequestParam(required = false) String textOffset) throws ThingsboardException {
try {
TextPageLink pageLink = createPageLink(limit, textSearch, idOffset, textOffset);
if (getCurrentUser().getAuthority() == Authority.SYS_ADMIN) {
return checkNotNull(ruleChainService.findSystemRuleChains(pageLink));
} else {
TenantId tenantId = getCurrentUser().getTenantId();
TextPageData<RuleChain> ruleChainsData = checkNotNull(ruleChainService.findAllTenantRuleChainsByTenantIdAndPageLink(tenantId, pageLink));
List<RuleChain> ruleChains = ruleChainsData.getData();
ruleChains.stream()
.filter(ruleChain -> ruleChain.getTenantId().getId().equals(ModelConstants.NULL_UUID))
.forEach(ruleChain -> ruleChain.setConfiguration(null));
return ruleChainsData;
}
} catch (Exception e) {
throw handleException(e);
}
}
@PreAuthorize("hasAuthority('SYS_ADMIN')")
@RequestMapping(value = "/system/ruleChains", params = {"limit"}, method = RequestMethod.GET)
@ResponseBody
public TextPageData<RuleChain> getSystemRuleChains(
@RequestParam int limit,
@RequestParam(required = false) String textSearch,
@RequestParam(required = false) String idOffset,
@RequestParam(required = false) String textOffset) throws ThingsboardException {
try {
TextPageLink pageLink = createPageLink(limit, textSearch, idOffset, textOffset);
return checkNotNull(ruleChainService.findSystemRuleChains(pageLink));
} catch (Exception e) {
throw handleException(e);
}
}
@PreAuthorize("hasAuthority('TENANT_ADMIN')")
@RequestMapping(value = "/tenant/ruleChains", params = {"limit"}, method = RequestMethod.GET)
@ResponseBody
public TextPageData<RuleChain> getTenantRuleChains(
@RequestParam int limit,
@RequestParam(required = false) String textSearch,
@RequestParam(required = false) String idOffset,
@RequestParam(required = false) String textOffset) throws ThingsboardException {
try {
TenantId tenantId = getCurrentUser().getTenantId();
TextPageLink pageLink = createPageLink(limit, textSearch, idOffset, textOffset);
@ -201,7 +198,7 @@ public class RuleChainController extends BaseController {
}
}
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')")
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN')")
@RequestMapping(value = "/ruleChain/{ruleChainId}", method = RequestMethod.DELETE)
@ResponseStatus(value = HttpStatus.OK)
public void deleteRuleChain(@PathVariable(RULE_CHAIN_ID) String strRuleChainId) throws ThingsboardException {
@ -209,6 +206,7 @@ public class RuleChainController extends BaseController {
try {
RuleChainId ruleChainId = new RuleChainId(toUUID(strRuleChainId));
RuleChain ruleChain = checkRuleChain(ruleChainId);
ruleChainService.deleteRuleChainById(ruleChainId);
actorService.onEntityStateChange(ruleChain.getTenantId(), ruleChain.getId(), ComponentLifecycleEvent.DELETED);

16
dao/src/main/java/org/thingsboard/server/dao/nosql/CassandraAbstractDao.java

@ -88,15 +88,27 @@ public abstract class CassandraAbstractDao {
}
private ResultSet execute(Statement statement, ConsistencyLevel level) {
log.debug("Execute cassandra statement {}", statement);
if (log.isDebugEnabled()) {
log.debug("Execute cassandra statement {}", statementToString(statement));
}
return executeAsync(statement, level).getUninterruptibly();
}
private ResultSetFuture executeAsync(Statement statement, ConsistencyLevel level) {
log.debug("Execute cassandra async statement {}", statement);
if (log.isDebugEnabled()) {
log.debug("Execute cassandra async statement {}", statementToString(statement));
}
if (statement.getConsistencyLevel() == null) {
statement.setConsistencyLevel(level);
}
return new RateLimitedResultSetFuture(getSession(), rateLimiter, statement);
}
private static String statementToString(Statement statement) {
if (statement instanceof BoundStatement) {
return ((BoundStatement)statement).preparedStatement().getQueryString();
} else {
return statement.toString();
}
}
}

79
dao/src/main/java/org/thingsboard/server/dao/rule/BaseRuleChainService.java

@ -57,8 +57,6 @@ import java.util.stream.Collectors;
@Slf4j
public class BaseRuleChainService extends AbstractEntityService implements RuleChainService {
public static final TenantId SYSTEM_TENANT = new TenantId(ModelConstants.NULL_UUID);
@Autowired
private RuleChainDao ruleChainDao;
@ -71,12 +69,8 @@ public class BaseRuleChainService extends AbstractEntityService implements RuleC
@Override
public RuleChain saveRuleChain(RuleChain ruleChain) {
ruleChainValidator.validate(ruleChain);
if (ruleChain.getTenantId() == null) {
log.trace("Save system rule chain with predefined id {}", SYSTEM_TENANT);
ruleChain.setTenantId(SYSTEM_TENANT);
}
RuleChain savedRuleChain = ruleChainDao.save(ruleChain);
if (ruleChain.isRoot() && ruleChain.getTenantId() != null && ruleChain.getId() == null) {
if (ruleChain.isRoot() && ruleChain.getId() == null) {
try {
createRelation(new EntityRelation(savedRuleChain.getTenantId(), savedRuleChain.getId(),
EntityRelation.CONTAINS_TYPE, RelationTypeGroup.RULE_CHAIN));
@ -89,6 +83,31 @@ public class BaseRuleChainService extends AbstractEntityService implements RuleC
return savedRuleChain;
}
@Override
public boolean setRootRuleChain(RuleChainId ruleChainId) {
RuleChain ruleChain = ruleChainDao.findById(ruleChainId.getId());
if (!ruleChain.isRoot()) {
RuleChain previousRootRuleChain = getRootTenantRuleChain(ruleChain.getTenantId());
if (!previousRootRuleChain.getId().equals(ruleChain.getId())) {
try {
deleteRelation(new EntityRelation(previousRootRuleChain.getTenantId(), previousRootRuleChain.getId(),
EntityRelation.CONTAINS_TYPE, RelationTypeGroup.RULE_CHAIN));
previousRootRuleChain.setRoot(false);
ruleChainDao.save(previousRootRuleChain);
createRelation(new EntityRelation(ruleChain.getTenantId(), ruleChain.getId(),
EntityRelation.CONTAINS_TYPE, RelationTypeGroup.RULE_CHAIN));
ruleChain.setRoot(true);
ruleChainDao.save(ruleChain);
return true;
} catch (ExecutionException | InterruptedException e) {
log.warn("[{}] Failed to set root rule chain, ruleChainId: [{}]", ruleChainId);
throw new RuntimeException(e);
}
}
}
return false;
}
@Override
public RuleChainMetaData saveRuleChainMetaData(RuleChainMetaData ruleChainMetaData) {
Validator.validateId(ruleChainMetaData.getRuleChainId(), "Incorrect rule chain id.");
@ -266,13 +285,6 @@ public class BaseRuleChainService extends AbstractEntityService implements RuleC
return relationService.findByFrom(ruleNodeId, RelationTypeGroup.RULE_NODE);
}
@Override
public TextPageData<RuleChain> findSystemRuleChains(TextPageLink pageLink) {
Validator.validatePageLink(pageLink, "Incorrect PageLink object for search system rule chain request.");
List<RuleChain> ruleChains = ruleChainDao.findRuleChainsByTenantId(SYSTEM_TENANT.getId(), pageLink);
return new TextPageData<>(ruleChains, pageLink);
}
@Override
public TextPageData<RuleChain> findTenantRuleChains(TenantId tenantId, TextPageLink pageLink) {
Validator.validateId(tenantId, "Incorrect tenant id for search rule chain request.");
@ -281,18 +293,13 @@ public class BaseRuleChainService extends AbstractEntityService implements RuleC
return new TextPageData<>(ruleChains, pageLink);
}
@Override
public TextPageData<RuleChain> findAllTenantRuleChainsByTenantIdAndPageLink(TenantId tenantId, TextPageLink pageLink) {
log.trace("Executing findAllTenantRuleChainsByTenantIdAndPageLink, tenantId [{}], pageLink [{}]", tenantId, pageLink);
Validator.validateId(tenantId, "Incorrect tenantId " + tenantId);
Validator.validatePageLink(pageLink, "Incorrect page link " + pageLink);
List<RuleChain> ruleChains = ruleChainDao.findAllRuleChainsByTenantId(tenantId.getId(), pageLink);
return new TextPageData<>(ruleChains, pageLink);
}
@Override
public void deleteRuleChainById(RuleChainId ruleChainId) {
Validator.validateId(ruleChainId, "Incorrect rule chain id for delete request.");
RuleChain ruleChain = ruleChainDao.findById(ruleChainId.getId());
if (ruleChain != null && ruleChain.isRoot()) {
throw new DataValidationException("Deletion of Root Tenant Rule Chain is prohibited!");
}
checkRuleNodesAndDelete(ruleChainId);
}
@ -325,6 +332,11 @@ public class BaseRuleChainService extends AbstractEntityService implements RuleC
relationService.saveRelation(relation);
}
private void deleteRelation(EntityRelation relation) throws ExecutionException, InterruptedException {
log.debug("Deleting relation: {}", relation);
relationService.deleteRelation(relation);
}
private DataValidator<RuleChain> ruleChainValidator =
new DataValidator<RuleChain>() {
@Override
@ -332,16 +344,17 @@ public class BaseRuleChainService extends AbstractEntityService implements RuleC
if (StringUtils.isEmpty(ruleChain.getName())) {
throw new DataValidationException("Rule chain name should be specified!.");
}
if (ruleChain.getTenantId() != null && !ruleChain.getTenantId().isNullUid()) {
Tenant tenant = tenantDao.findById(ruleChain.getTenantId().getId());
if (tenant == null) {
throw new DataValidationException("Rule chain is referencing to non-existent tenant!");
}
if (ruleChain.isRoot()) {
RuleChain rootRuleChain = getRootTenantRuleChain(ruleChain.getTenantId());
if (rootRuleChain != null && !rootRuleChain.getId().equals(ruleChain.getId())) {
throw new DataValidationException("Another root rule chain is present in scope of current tenant!");
}
if (ruleChain.getTenantId() == null || ruleChain.getTenantId().isNullUid()) {
throw new DataValidationException("Rule chain should be assigned to tenant!");
}
Tenant tenant = tenantDao.findById(ruleChain.getTenantId().getId());
if (tenant == null) {
throw new DataValidationException("Rule chain is referencing to non-existent tenant!");
}
if (ruleChain.isRoot()) {
RuleChain rootRuleChain = getRootTenantRuleChain(ruleChain.getTenantId());
if (rootRuleChain != null && !rootRuleChain.getId().equals(ruleChain.getId())) {
throw new DataValidationException("Another root rule chain is present in scope of current tenant!");
}
}
}

11
dao/src/main/java/org/thingsboard/server/dao/rule/CassandraRuleChainDao.java

@ -60,15 +60,4 @@ public class CassandraRuleChainDao extends CassandraAbstractSearchTextDao<RuleCh
return DaoUtil.convertDataList(ruleChainEntities);
}
@Override
public List<RuleChain> findAllRuleChainsByTenantId(UUID tenantId, TextPageLink pageLink) {
log.debug("Try to find all rule chains by tenantId [{}] and pageLink [{}]", tenantId, pageLink);
List<RuleChainEntity> ruleChainEntities = findPageWithTextSearch(RULE_CHAIN_BY_TENANT_AND_SEARCH_TEXT_COLUMN_FAMILY_NAME,
Arrays.asList(in(ModelConstants.RULE_CHAIN_TENANT_ID_PROPERTY, Arrays.asList(NULL_UUID, tenantId))),
pageLink);
log.trace("Found rule chains [{}] by tenantId [{}] and pageLink [{}]", ruleChainEntities, tenantId, pageLink);
return DaoUtil.convertDataList(ruleChainEntities);
}
}

9
dao/src/main/java/org/thingsboard/server/dao/rule/RuleChainDao.java

@ -37,13 +37,4 @@ public interface RuleChainDao extends Dao<RuleChain> {
*/
List<RuleChain> findRuleChainsByTenantId(UUID tenantId, TextPageLink pageLink);
/**
* Find all rule chains by tenantId and page link.
*
* @param tenantId the tenantId
* @param pageLink the page link
* @return the list of rule chain objects
*/
List<RuleChain> findAllRuleChainsByTenantId(UUID tenantId, TextPageLink pageLink);
}

6
dao/src/main/java/org/thingsboard/server/dao/rule/RuleChainService.java

@ -36,6 +36,8 @@ public interface RuleChainService {
RuleChain saveRuleChain(RuleChain ruleChain);
boolean setRootRuleChain(RuleChainId ruleChainId);
RuleChainMetaData saveRuleChainMetaData(RuleChainMetaData ruleChainMetaData);
RuleChainMetaData loadRuleChainMetaData(RuleChainId ruleChainId);
@ -54,12 +56,8 @@ public interface RuleChainService {
List<EntityRelation> getRuleNodeRelations(RuleNodeId ruleNodeId);
TextPageData<RuleChain> findSystemRuleChains(TextPageLink pageLink);
TextPageData<RuleChain> findTenantRuleChains(TenantId tenantId, TextPageLink pageLink);
TextPageData<RuleChain> findAllTenantRuleChainsByTenantIdAndPageLink(TenantId tenantId, TextPageLink pageLink);
void deleteRuleChainById(RuleChainId ruleChainId);
void deleteRuleChainsByTenantId(TenantId tenantId);

11
dao/src/main/java/org/thingsboard/server/dao/sql/rule/JpaRuleChainDao.java

@ -63,15 +63,4 @@ public class JpaRuleChainDao extends JpaAbstractSearchTextDao<RuleChainEntity, R
new PageRequest(0, pageLink.getLimit())));
}
@Override
public List<RuleChain> findAllRuleChainsByTenantId(UUID tenantId, TextPageLink pageLink) {
return DaoUtil.convertDataList(ruleChainRepository
.findAllTenantRuleChainsByTenantId(
UUIDConverter.fromTimeUUID(tenantId),
NULL_UUID_STR,
Objects.toString(pageLink.getTextSearch(), ""),
pageLink.getIdOffset() == null ? NULL_UUID_STR : UUIDConverter.fromTimeUUID(pageLink.getIdOffset()),
new PageRequest(0, pageLink.getLimit())));
}
}

8
dao/src/main/java/org/thingsboard/server/dao/sql/rule/RuleChainRepository.java

@ -35,12 +35,4 @@ public interface RuleChainRepository extends CrudRepository<RuleChainEntity, Str
@Param("idOffset") String idOffset,
Pageable pageable);
@Query("SELECT rc FROM RuleChainEntity rc WHERE rc.tenantId IN (:tenantId, :nullTenantId) " +
"AND LOWER(rc.searchText) LIKE LOWER(CONCAT(:searchText, '%')) " +
"AND rc.id > :idOffset ORDER BY rc.id")
List<RuleChainEntity> findAllTenantRuleChainsByTenantId(@Param("tenantId") String tenantId,
@Param("nullTenantId") String nullTenantId,
@Param("searchText") String searchText,
@Param("idOffset") String idOffset,
Pageable pageable);
}

6
rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/TbContext.java

@ -48,12 +48,6 @@ public interface TbContext {
void tellSelf(TbMsg msg, long delayMs);
void tellOthers(TbMsg msg);
void tellSibling(TbMsg msg, ServerAddress address);
void ack(TbMsg msg);
void tellError(TbMsg msg, Throwable th);
void updateSelf(RuleNode self);

6
rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbAbstractAlarmNode.java

@ -69,13 +69,13 @@ public abstract class TbAbstractAlarmNode<C extends TbAbstractAlarmNodeConfigura
protected ListenableFuture<JsonNode> buildAlarmDetails(TbContext ctx, TbMsg msg, JsonNode previousDetails) {
return ctx.getJsExecutor().executeAsync(() -> {
TbMsg theMsg = msg;
TbMsg dummyMsg = msg;
if (previousDetails != null) {
TbMsgMetaData metaData = msg.getMetaData().copy();
metaData.putValue(PREV_ALARM_DETAILS, mapper.writeValueAsString(previousDetails));
theMsg = ctx.newMsg(msg.getType(), msg.getOriginator(), metaData, msg.getData());
dummyMsg = ctx.transformMsg(msg, msg.getType(), msg.getOriginator(), metaData, msg.getData());
}
return buildDetailsJsEngine.executeJson(theMsg);
return buildDetailsJsEngine.executeJson(dummyMsg);
});
}

52
ui/src/app/api/rule-chain.service.js

@ -22,11 +22,10 @@ function RuleChainService($http, $q, $filter, $ocLazyLoad, $translate, types, co
var ruleNodeComponents = null;
var service = {
getSystemRuleChains: getSystemRuleChains,
getTenantRuleChains: getTenantRuleChains,
getRuleChains: getRuleChains,
getRuleChain: getRuleChain,
saveRuleChain: saveRuleChain,
setRootRuleChain: setRootRuleChain,
deleteRuleChain: deleteRuleChain,
getRuleChainMetaData: getRuleChainMetaData,
saveRuleChainMetaData: saveRuleChainMetaData,
@ -40,29 +39,9 @@ function RuleChainService($http, $q, $filter, $ocLazyLoad, $translate, types, co
return service;
function getSystemRuleChains (pageLink, config) {
var deferred = $q.defer();
var url = '/api/system/ruleChains?limit=' + pageLink.limit;
if (angular.isDefined(pageLink.textSearch)) {
url += '&textSearch=' + pageLink.textSearch;
}
if (angular.isDefined(pageLink.idOffset)) {
url += '&idOffset=' + pageLink.idOffset;
}
if (angular.isDefined(pageLink.textOffset)) {
url += '&textOffset=' + pageLink.textOffset;
}
$http.get(url, config).then(function success(response) {
deferred.resolve(response.data);
}, function fail() {
deferred.reject();
});
return deferred.promise;
}
function getTenantRuleChains (pageLink, config) {
function getRuleChains (pageLink, config) {
var deferred = $q.defer();
var url = '/api/tenant/ruleChains?limit=' + pageLink.limit;
var url = '/api/ruleChains?limit=' + pageLink.limit;
if (angular.isDefined(pageLink.textSearch)) {
url += '&textSearch=' + pageLink.textSearch;
}
@ -80,18 +59,9 @@ function RuleChainService($http, $q, $filter, $ocLazyLoad, $translate, types, co
return deferred.promise;
}
function getRuleChains (pageLink, config) {
function getRuleChain(ruleChainId, config) {
var deferred = $q.defer();
var url = '/api/ruleChains?limit=' + pageLink.limit;
if (angular.isDefined(pageLink.textSearch)) {
url += '&textSearch=' + pageLink.textSearch;
}
if (angular.isDefined(pageLink.idOffset)) {
url += '&idOffset=' + pageLink.idOffset;
}
if (angular.isDefined(pageLink.textOffset)) {
url += '&textOffset=' + pageLink.textOffset;
}
var url = '/api/ruleChain/' + ruleChainId;
$http.get(url, config).then(function success(response) {
deferred.resolve(response.data);
}, function fail() {
@ -100,10 +70,10 @@ function RuleChainService($http, $q, $filter, $ocLazyLoad, $translate, types, co
return deferred.promise;
}
function getRuleChain(ruleChainId, config) {
function saveRuleChain(ruleChain) {
var deferred = $q.defer();
var url = '/api/ruleChain/' + ruleChainId;
$http.get(url, config).then(function success(response) {
var url = '/api/ruleChain';
$http.post(url, ruleChain).then(function success(response) {
deferred.resolve(response.data);
}, function fail() {
deferred.reject();
@ -111,10 +81,10 @@ function RuleChainService($http, $q, $filter, $ocLazyLoad, $translate, types, co
return deferred.promise;
}
function saveRuleChain(ruleChain) {
function setRootRuleChain(ruleChainId) {
var deferred = $q.defer();
var url = '/api/ruleChain';
$http.post(url, ruleChain).then(function success(response) {
var url = '/api/ruleChain/' + ruleChainId + '/root';
$http.post(url).then(function success(response) {
deferred.resolve(response.data);
}, function fail() {
deferred.reject();

4
ui/src/app/locale/locale.constant.js

@ -1163,11 +1163,15 @@ export default angular.module('thingsboard.locale', [])
"rulechain": {
"rulechain": "Rule chain",
"rulechains": "Rule chains",
"root": "Root",
"delete": "Delete rule chain",
"name": "Name",
"name-required": "Name is required.",
"description": "Description",
"add": "Add Rule Chain",
"set-root": "Make rule chain root",
"set-root-rulechain-title": "Are you sure you want to make the rule chain '{{ruleChainName}}' root?",
"set-root-rulechain-text": "After the confirmation the rule chain will become root and will handle all incoming transport messages.",
"delete-rulechain-title": "Are you sure you want to delete the rule chain '{{ruleChainName}}'?",
"delete-rulechain-text": "Be careful, after the confirmation the rule chain and all related data will become unrecoverable.",
"delete-rulechains-title": "Are you sure you want to delete { count, select, 1 {1 rule chain} other {# rule chains} }?",

2
ui/src/app/rulechain/rulechain-card.tpl.html

@ -15,4 +15,4 @@
limitations under the License.
-->
<div class="tb-uppercase" ng-if="item && parentCtl.types.id.nullUid === item.tenantId.id" translate>rulechain.system</div>
<div ng-if="item && item.root" translate>rulechain.root</div>

5
ui/src/app/rulechain/rulechain-fieldset.tpl.html

@ -18,8 +18,11 @@
<md-button ng-click="onExportRuleChain({event: $event})"
ng-show="!isEdit"
class="md-raised md-primary">{{ 'rulechain.export' | translate }}</md-button>
<md-button ng-click="onSetRootRuleChain({event: $event})"
ng-show="!isEdit && !ruleChain.root"
class="md-raised md-primary">{{ 'rulechain.set-root' | translate }}</md-button>
<md-button ng-click="onDeleteRuleChain({event: $event})"
ng-show="!isEdit && !isReadOnly"
ng-show="!isEdit && !ruleChain.root"
class="md-raised md-primary">{{ 'rulechain.delete' | translate }}</md-button>
<div layout="row">

1
ui/src/app/rulechain/rulechain.directive.js

@ -40,6 +40,7 @@ export default function RuleChainDirective($compile, $templateCache, $mdDialog,
isEdit: '=',
isReadOnly: '=',
theForm: '=',
onSetRootRuleChain: '&',
onExportRuleChain: '&',
onDeleteRuleChain: '&'
}

2
ui/src/app/rulechain/rulechain.routes.js

@ -81,7 +81,7 @@ export default function RuleChainRoutes($stateProvider, NodeTemplatePathProvider
pageTitle: 'rulechain.rulechain'
},
ncyBreadcrumb: {
label: '{"icon": "settings_ethernet", "label": "{{ vm.ruleChain.name }}", "translate": "false"}'
label: '{"icon": "settings_ethernet", "label": "{{ vm.ruleChain.name + (vm.ruleChain.root ? (\' (\' + (\'rulechain.root\' | translate) + \')\') : \'\') }}", "translate": "false"}'
}
}).state('home.ruleChains.importRuleChain', {
url: '/ruleChain/import',

53
ui/src/app/rulechain/rulechains.controller.js

@ -21,7 +21,8 @@ import ruleChainCard from './rulechain-card.tpl.html';
/* eslint-enable import/no-unresolved, import/default */
/*@ngInject*/
export default function RuleChainsController(ruleChainService, userService, importExport, $state, $stateParams, $filter, $translate, types) {
export default function RuleChainsController(ruleChainService, userService, importExport, $state,
$stateParams, $filter, $translate, $mdDialog, types) {
var ruleChainActionsList = [
{
@ -40,6 +41,15 @@ export default function RuleChainsController(ruleChainService, userService, impo
details: function() { return $translate.instant('rulechain.export') },
icon: "file_download"
},
{
onAction: function ($event, item) {
setRootRuleChain($event, item);
},
name: function() { return $translate.instant('rulechain.set-root') },
details: function() { return $translate.instant('rulechain.set-root') },
icon: "flag",
isEnabled: isNonRootRuleChain
},
{
onAction: function ($event, item) {
vm.grid.deleteItem($event, item);
@ -47,7 +57,7 @@ export default function RuleChainsController(ruleChainService, userService, impo
name: function() { return $translate.instant('action.delete') },
details: function() { return $translate.instant('rulechain.delete') },
icon: "delete",
isEnabled: isRuleChainEditable
isEnabled: isNonRootRuleChain
}
];
@ -107,10 +117,7 @@ export default function RuleChainsController(ruleChainService, userService, impo
addItemText: function() { return $translate.instant('rulechain.add-rulechain-text') },
noItemsText: function() { return $translate.instant('rulechain.no-rulechains-text') },
itemDetailsText: function() { return $translate.instant('rulechain.rulechain-details') },
isSelectionEnabled: isRuleChainEditable,
isDetailsReadOnly: function(ruleChain) {
return !isRuleChainEditable(ruleChain);
}
isSelectionEnabled: isNonRootRuleChain
};
if (angular.isDefined($stateParams.items) && $stateParams.items !== null) {
@ -121,9 +128,11 @@ export default function RuleChainsController(ruleChainService, userService, impo
vm.ruleChainGridConfig.topIndex = $stateParams.topIndex;
}
vm.isRuleChainEditable = isRuleChainEditable;
vm.isRootRuleChain = isRootRuleChain;
vm.isNonRootRuleChain = isNonRootRuleChain;
vm.exportRuleChain = exportRuleChain;
vm.setRootRuleChain = setRootRuleChain;
function deleteRuleChainTitle(ruleChain) {
return $translate.instant('rulechain.delete-rulechain-title', {ruleChainName: ruleChain.name});
@ -172,12 +181,12 @@ export default function RuleChainsController(ruleChainService, userService, impo
return ruleChain ? ruleChain.name : '';
}
function isRuleChainEditable(ruleChain) {
if (userService.getAuthority() === 'TENANT_ADMIN') {
return ruleChain && ruleChain.tenantId.id != types.id.nullUid;
} else {
return userService.getAuthority() === 'SYS_ADMIN';
}
function isRootRuleChain(ruleChain) {
return ruleChain && ruleChain.root;
}
function isNonRootRuleChain(ruleChain) {
return ruleChain && !ruleChain.root;
}
function exportRuleChain($event, ruleChain) {
@ -185,4 +194,22 @@ export default function RuleChainsController(ruleChainService, userService, impo
importExport.exportRuleChain(ruleChain.id.id);
}
function setRootRuleChain($event, ruleChain) {
$event.stopPropagation();
var confirm = $mdDialog.confirm()
.targetEvent($event)
.title($translate.instant('rulechain.set-root-rulechain-title', {ruleChainName: ruleChain.name}))
.htmlContent($translate.instant('rulechain.set-root-rulechain-text'))
.ariaLabel($translate.instant('rulechain.set-root'))
.cancel($translate.instant('action.no'))
.ok($translate.instant('action.yes'));
$mdDialog.show(confirm).then(function () {
ruleChainService.setRootRuleChain(ruleChain.id.id).then(
() => {
vm.grid.refreshList();
}
);
});
}
}

4
ui/src/app/rulechain/rulechains.tpl.html

@ -26,8 +26,10 @@
is-edit="vm.grid.detailsConfig.isDetailsEditMode"
is-read-only="vm.grid.isDetailsReadOnly(vm.grid.operatingItem())"
the-form="vm.grid.detailsForm"
on-set-root-rule-chain="vm.setRootRuleChain(event, vm.grid.detailsConfig.currentItem)"
on-export-rule-chain="vm.exportRuleChain(event, vm.grid.detailsConfig.currentItem)"
on-delete-rule-chain="vm.grid.deleteItem(event, vm.grid.detailsConfig.currentItem)"></tb-rule-chain>
on-delete-rule-chain="vm.grid.deleteItem(event, vm.grid.detailsConfig.currentItem)">
</tb-rule-chain>
</md-tab>
<md-tab ng-if="!vm.grid.detailsConfig.isDetailsEditMode && vm.isRuleChainEditable(vm.grid.operatingItem())" md-on-select="vm.grid.triggerResize()" label="{{ 'attribute.attributes' | translate }}">
<tb-attribute-table flex

Loading…
Cancel
Save