Browse Source

new RuleNode 'fetch device credentials'

pull/6999/head
Yuriy Lytvynchuk 4 years ago
parent
commit
4712118ce2
  1. 5
      application/src/main/java/org/thingsboard/server/actors/ActorSystemContext.java
  2. 6
      application/src/main/java/org/thingsboard/server/actors/ruleChain/DefaultTbContext.java
  3. 3
      rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/TbContext.java
  4. 101
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbFetchDeviceCredentialsNode.java
  5. 34
      rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbFetchDeviceCredentialsNodeConfiguration.java
  6. 149
      rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbFetchDeviceCredentialsNodeTest.java

5
application/src/main/java/org/thingsboard/server/actors/ActorSystemContext.java

@ -55,6 +55,7 @@ import org.thingsboard.server.dao.cassandra.CassandraCluster;
import org.thingsboard.server.dao.customer.CustomerService; import org.thingsboard.server.dao.customer.CustomerService;
import org.thingsboard.server.dao.dashboard.DashboardService; import org.thingsboard.server.dao.dashboard.DashboardService;
import org.thingsboard.server.dao.device.ClaimDevicesService; import org.thingsboard.server.dao.device.ClaimDevicesService;
import org.thingsboard.server.dao.device.DeviceCredentialsService;
import org.thingsboard.server.dao.device.DeviceService; import org.thingsboard.server.dao.device.DeviceService;
import org.thingsboard.server.dao.edge.EdgeEventService; import org.thingsboard.server.dao.edge.EdgeEventService;
import org.thingsboard.server.dao.edge.EdgeService; import org.thingsboard.server.dao.edge.EdgeService;
@ -150,6 +151,10 @@ public class ActorSystemContext {
@Getter @Getter
private DeviceService deviceService; private DeviceService deviceService;
@Autowired
@Getter
private DeviceCredentialsService deviceCredentialsService;
@Autowired @Autowired
@Getter @Getter
private TbTenantProfileCache tenantProfileCache; private TbTenantProfileCache tenantProfileCache;

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

@ -65,6 +65,7 @@ import org.thingsboard.server.dao.attributes.AttributesService;
import org.thingsboard.server.dao.cassandra.CassandraCluster; import org.thingsboard.server.dao.cassandra.CassandraCluster;
import org.thingsboard.server.dao.customer.CustomerService; import org.thingsboard.server.dao.customer.CustomerService;
import org.thingsboard.server.dao.dashboard.DashboardService; import org.thingsboard.server.dao.dashboard.DashboardService;
import org.thingsboard.server.dao.device.DeviceCredentialsService;
import org.thingsboard.server.dao.device.DeviceService; import org.thingsboard.server.dao.device.DeviceService;
import org.thingsboard.server.dao.edge.EdgeEventService; import org.thingsboard.server.dao.edge.EdgeEventService;
import org.thingsboard.server.dao.edge.EdgeService; import org.thingsboard.server.dao.edge.EdgeService;
@ -479,6 +480,11 @@ class DefaultTbContext implements TbContext {
return mainCtx.getDeviceService(); return mainCtx.getDeviceService();
} }
@Override
public DeviceCredentialsService getDeviceCredentialsService() {
return mainCtx.getDeviceCredentialsService();
}
@Override @Override
public TbClusterService getClusterService() { public TbClusterService getClusterService() {
return mainCtx.getClusterService(); return mainCtx.getClusterService();

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

@ -44,6 +44,7 @@ import org.thingsboard.server.dao.attributes.AttributesService;
import org.thingsboard.server.dao.cassandra.CassandraCluster; import org.thingsboard.server.dao.cassandra.CassandraCluster;
import org.thingsboard.server.dao.customer.CustomerService; import org.thingsboard.server.dao.customer.CustomerService;
import org.thingsboard.server.dao.dashboard.DashboardService; import org.thingsboard.server.dao.dashboard.DashboardService;
import org.thingsboard.server.dao.device.DeviceCredentialsService;
import org.thingsboard.server.dao.device.DeviceService; import org.thingsboard.server.dao.device.DeviceService;
import org.thingsboard.server.dao.edge.EdgeEventService; import org.thingsboard.server.dao.edge.EdgeEventService;
import org.thingsboard.server.dao.edge.EdgeService; import org.thingsboard.server.dao.edge.EdgeService;
@ -210,6 +211,8 @@ public interface TbContext {
DeviceService getDeviceService(); DeviceService getDeviceService();
DeviceCredentialsService getDeviceCredentialsService();
TbClusterService getClusterService(); TbClusterService getClusterService();
DashboardService getDashboardService(); DashboardService getDashboardService();

101
rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbFetchDeviceCredentialsNode.java

@ -0,0 +1,101 @@
/**
* Copyright © 2016-2022 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.metadata;
import com.fasterxml.jackson.databind.node.ObjectNode;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.BooleanUtils;
import org.thingsboard.common.util.JacksonUtil;
import org.thingsboard.rule.engine.api.RuleNode;
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.server.common.data.EntityType;
import org.thingsboard.server.common.data.id.DeviceId;
import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.common.data.plugin.ComponentType;
import org.thingsboard.server.common.data.security.DeviceCredentials;
import org.thingsboard.server.common.msg.TbMsg;
import org.thingsboard.server.common.msg.TbMsgMetaData;
import java.util.concurrent.ExecutionException;
@Slf4j
@RuleNode(
type = ComponentType.ENRICHMENT,
name = "fetch device credentials",
configClazz = TbFetchDeviceCredentialsNodeConfiguration.class,
nodeDescription = "Adds <b>deviceCredentials</b> property to the message metadata if the configuration parameter <b>fetchToMetadata</b>" +
" is set to <code>true</code> or if it does not exist, otherwise, adds <b>deviceCredentials</b> property to the message data!",
nodeDetails = "Rule node returns transformed messages via <code>Success</code> chain in case that message successfully transformed" +
" otherwise returns the incoming message as outbound message with <code>Failure</code> chain.",
uiResources = {"static/rulenode/rulenode-core-config.js"},
configDirective = "",
icon = "functions"
)
public class TbFetchDeviceCredentialsNode implements TbNode {
private static final String DEVICE_CREDENTIAL = "deviceCredentials";
TbFetchDeviceCredentialsNodeConfiguration config;
boolean fetchToMetadata;
@Override
public void init(TbContext ctx, TbNodeConfiguration configuration) throws TbNodeException {
this.config = TbNodeUtils.convert(configuration, TbFetchDeviceCredentialsNodeConfiguration.class);
fetchToMetadata = BooleanUtils.toBooleanDefaultIfNull(config.isFetchToMetadata(), true);
}
@Override
public void onMsg(TbContext ctx, TbMsg msg) throws ExecutionException, InterruptedException, TbNodeException {
EntityId originator = msg.getOriginator();
if (!EntityType.DEVICE.equals(originator.getEntityType())) {
ctx.tellFailure(msg, new RuntimeException("Unsupported originator type: " + originator.getEntityType() + "!"));
return;
}
DeviceId deviceId = new DeviceId(msg.getOriginator().getId());
DeviceCredentials deviceCredentials = ctx.getDeviceCredentialsService().findDeviceCredentialsByDeviceId(ctx.getTenantId(), deviceId);
if (deviceCredentials == null) {
ctx.tellFailure(msg, new RuntimeException("Failed to get Device Credentials for device: " + deviceId + "!"));
return;
}
//TODO -- ask return type data
/*String credentialsId = deviceCredentials.getCredentialsId();
if (StringUtils.isEmpty(credentialsId)) {
ctx.tellFailure(msg, new RuntimeException("Failed to get accessToken for device: " + deviceId + "!"));
return;
}*/
TbMsg transformedMsg;
if (fetchToMetadata) {
TbMsgMetaData metaData = msg.getMetaData();
metaData.putValue(DEVICE_CREDENTIAL, JacksonUtil.toString(deviceCredentials));
transformedMsg = TbMsg.transformMsg(msg, msg.getType(), originator, metaData, msg.getData());
} else {
ObjectNode data = (ObjectNode) JacksonUtil.toJsonNode(msg.getData());
data.set(DEVICE_CREDENTIAL, JacksonUtil.valueToTree(deviceCredentials));
transformedMsg = TbMsg.transformMsg(msg, msg.getType(), originator, msg.getMetaData(), JacksonUtil.toString(data));
}
ctx.tellSuccess(transformedMsg);
}
@Override
public void destroy() {
}
}

34
rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbFetchDeviceCredentialsNodeConfiguration.java

@ -0,0 +1,34 @@
/**
* Copyright © 2016-2022 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.metadata;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import lombok.Data;
import org.thingsboard.rule.engine.api.NodeConfiguration;
@Data
@JsonIgnoreProperties(ignoreUnknown = true)
public class TbFetchDeviceCredentialsNodeConfiguration implements NodeConfiguration<TbFetchDeviceCredentialsNodeConfiguration> {
private boolean fetchToMetadata;
@Override
public TbFetchDeviceCredentialsNodeConfiguration defaultConfiguration() {
TbFetchDeviceCredentialsNodeConfiguration configuration = new TbFetchDeviceCredentialsNodeConfiguration();
configuration.setFetchToMetadata(true);
return configuration;
}
}

149
rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/metadata/TbFetchDeviceCredentialsNodeTest.java

@ -0,0 +1,149 @@
/**
* Copyright © 2016-2022 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.metadata;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.ArgumentCaptor;
import org.thingsboard.rule.engine.api.TbContext;
import org.thingsboard.rule.engine.api.TbNodeConfiguration;
import org.thingsboard.rule.engine.api.TbNodeException;
import org.thingsboard.server.common.data.id.CustomerId;
import org.thingsboard.server.common.data.id.DeviceId;
import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.common.data.security.DeviceCredentials;
import org.thingsboard.server.common.msg.TbMsg;
import org.thingsboard.server.common.msg.TbMsgMetaData;
import org.thingsboard.server.common.msg.queue.TbMsgCallback;
import org.thingsboard.server.dao.device.DeviceCredentialsService;
import java.util.Map;
import java.util.UUID;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.BDDMockito.willAnswer;
import static org.mockito.BDDMockito.willReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
public class TbFetchDeviceCredentialsNodeTest {
final ObjectMapper mapper = new ObjectMapper();
DeviceId deviceId;
TbFetchDeviceCredentialsNode node;
TbFetchDeviceCredentialsNodeConfiguration config;
TbNodeConfiguration nodeConfiguration;
TbContext ctx;
TbMsgCallback callback;
DeviceCredentialsService deviceCredentialsService;
@BeforeEach
void setUp() throws TbNodeException {
deviceId = new DeviceId(UUID.randomUUID());
callback = mock(TbMsgCallback.class);
ctx = mock(TbContext.class);
config = new TbFetchDeviceCredentialsNodeConfiguration().defaultConfiguration();
config.setFetchToMetadata(true);
nodeConfiguration = new TbNodeConfiguration(mapper.valueToTree(config));
node = spy(new TbFetchDeviceCredentialsNode());
node.init(ctx, nodeConfiguration);
deviceCredentialsService = mock(DeviceCredentialsService.class);
willReturn(deviceCredentialsService).given(ctx).getDeviceCredentialsService();
willAnswer(invocation -> {
return new DeviceCredentials();
}).given(deviceCredentialsService).findDeviceCredentialsByDeviceId(any(), any());
}
@AfterEach
void tearDown() {
node.destroy();
}
@Test
void givenDefaultConfig_whenInit_thenOK() {
assertThat(node.config).isEqualTo(config);
assertThat(node.fetchToMetadata).isEqualTo(true);
}
@Test
void givenDefaultConfig_whenVerify_thenOK() {
TbFetchDeviceCredentialsNodeConfiguration defaultConfig = new TbFetchDeviceCredentialsNodeConfiguration().defaultConfiguration();
assertThat(defaultConfig.isFetchToMetadata()).isEqualTo(true);
}
@Test
void givenMsg_whenOnMsg_thenVerifyOutput() throws Exception {
node.onMsg(ctx, getTbMsg(deviceId));
ArgumentCaptor<TbMsg> newMsgCaptor = ArgumentCaptor.forClass(TbMsg.class);
verify(ctx, times(1)).tellSuccess(newMsgCaptor.capture());
verify(ctx, never()).tellFailure(any(), any());
verify(deviceCredentialsService, times(1)).findDeviceCredentialsByDeviceId(any(), any());
TbMsg newMsg = newMsgCaptor.getValue();
assertThat(newMsg).isNotNull();
assertThat(newMsg.getMetaData().getData().containsKey("deviceCredentials")).isEqualTo(true);
}
@Test
void givenUnsupportedOriginatorType_whenOnMsg_thenTellFailure() throws Exception {
node.onMsg(ctx, getTbMsg(new CustomerId(UUID.randomUUID())));
ArgumentCaptor<TbMsg> newMsgCaptor = ArgumentCaptor.forClass(TbMsg.class);
ArgumentCaptor<Exception> exceptionCaptor = ArgumentCaptor.forClass(Exception.class);
verify(ctx, never()).tellSuccess(any());
verify(ctx, times(1)).tellFailure(newMsgCaptor.capture(), exceptionCaptor.capture());
assertThat(exceptionCaptor.getValue()).isInstanceOf(RuntimeException.class);
}
@Test
void givenGetDeviceCredentials_whenOnMsg_thenTellFailure() throws Exception {
willAnswer(invocation -> {
return null;
}).given(deviceCredentialsService).findDeviceCredentialsByDeviceId(any(), any());
node.onMsg(ctx, getTbMsg(deviceId));
ArgumentCaptor<TbMsg> newMsgCaptor = ArgumentCaptor.forClass(TbMsg.class);
ArgumentCaptor<Exception> exceptionCaptor = ArgumentCaptor.forClass(Exception.class);
verify(ctx, never()).tellSuccess(any());
verify(ctx, times(1)).tellFailure(newMsgCaptor.capture(), exceptionCaptor.capture());
assertThat(exceptionCaptor.getValue()).isInstanceOf(RuntimeException.class);
}
private TbMsg getTbMsg(EntityId entityId) {
final Map<String, String> mdMap = Map.of(
"country", "US",
"city", "NY"
);
final TbMsgMetaData metaData = new TbMsgMetaData(mdMap);
final String data = "{\"TestAttribute_1\": \"humidity\", \"TestAttribute_2\": \"voltage\"}";
return TbMsg.newMsg("POST_ATTRIBUTES_REQUEST", entityId, metaData, data, callback);
}
}
Loading…
Cancel
Save