466 changed files with 14205 additions and 5652 deletions
@ -0,0 +1,90 @@ |
|||
-- |
|||
-- Copyright © 2016-2021 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. |
|||
-- |
|||
|
|||
-- PROCEDURE: public.cleanup_events_by_ttl(bigint, bigint, bigint) |
|||
|
|||
DROP PROCEDURE IF EXISTS public.cleanup_events_by_ttl(bigint, bigint, bigint); |
|||
|
|||
CREATE OR REPLACE PROCEDURE public.cleanup_events_by_ttl( |
|||
ttl bigint, |
|||
debug_ttl bigint, |
|||
INOUT deleted bigint) |
|||
LANGUAGE 'plpgsql' |
|||
AS $BODY$ |
|||
DECLARE |
|||
ttl_ts bigint; |
|||
debug_ttl_ts bigint; |
|||
ttl_deleted_count bigint DEFAULT 0; |
|||
debug_ttl_deleted_count bigint DEFAULT 0; |
|||
BEGIN |
|||
IF ttl > 0 THEN |
|||
ttl_ts := (EXTRACT(EPOCH FROM current_timestamp) * 1000 - ttl::bigint * 1000)::bigint; |
|||
|
|||
DELETE FROM event |
|||
WHERE ts < ttl_ts |
|||
AND NOT event_type IN ('DEBUG_RULE_NODE', 'DEBUG_RULE_CHAIN', 'DEBUG_CONVERTER', 'DEBUG_INTEGRATION'); |
|||
|
|||
GET DIAGNOSTICS ttl_deleted_count = ROW_COUNT; |
|||
END IF; |
|||
|
|||
IF debug_ttl > 0 THEN |
|||
debug_ttl_ts := (EXTRACT(EPOCH FROM current_timestamp) * 1000 - debug_ttl::bigint * 1000)::bigint; |
|||
|
|||
DELETE FROM event |
|||
WHERE ts < debug_ttl_ts |
|||
AND event_type IN ('DEBUG_RULE_NODE', 'DEBUG_RULE_CHAIN', 'DEBUG_CONVERTER', 'DEBUG_INTEGRATION'); |
|||
|
|||
GET DIAGNOSTICS debug_ttl_deleted_count = ROW_COUNT; |
|||
END IF; |
|||
|
|||
RAISE NOTICE 'Events removed by ttl: %', ttl_deleted_count; |
|||
RAISE NOTICE 'Debug Events removed by ttl: %', debug_ttl_deleted_count; |
|||
deleted := ttl_deleted_count + debug_ttl_deleted_count; |
|||
END |
|||
$BODY$; |
|||
|
|||
|
|||
-- Index: idx_event_ts |
|||
|
|||
DROP INDEX IF EXISTS public.idx_event_ts; |
|||
|
|||
-- Hint: add CONCURRENTLY to CREATE INDEX query in case of more then 1 million records or during live update |
|||
-- CREATE INDEX CONCURRENTLY IF NOT EXISTS idx_event_ts |
|||
CREATE INDEX IF NOT EXISTS idx_event_ts |
|||
ON public.event |
|||
(ts DESC NULLS LAST) |
|||
WITH (FILLFACTOR=95); |
|||
|
|||
COMMENT ON INDEX public.idx_event_ts |
|||
IS 'This index helps to delete events by TTL using timestamp'; |
|||
|
|||
|
|||
-- Index: idx_event_tenant_entity_type_entity_event_type_created_time_des |
|||
|
|||
DROP INDEX IF EXISTS public.idx_event_tenant_entity_type_entity_event_type_created_time_des; |
|||
|
|||
-- CREATE INDEX CONCURRENTLY IF NOT EXISTS idx_event_tenant_entity_type_entity_event_type_created_time_des |
|||
CREATE INDEX IF NOT EXISTS idx_event_tenant_entity_type_entity_event_type_created_time_des |
|||
ON public.event |
|||
(tenant_id ASC, entity_type ASC, entity_id ASC, event_type ASC, created_time DESC NULLS LAST) |
|||
WITH (FILLFACTOR=95); |
|||
|
|||
COMMENT ON INDEX public.idx_event_tenant_entity_type_entity_event_type_created_time_des |
|||
IS 'This index helps to open latest events on UI fast'; |
|||
|
|||
-- Index: idx_event_type_entity_id |
|||
-- Description: replaced with more suitable idx_event_tenant_entity_type_entity_event_type_created_time_des |
|||
DROP INDEX IF EXISTS public.idx_event_type_entity_id; |
|||
@ -0,0 +1,32 @@ |
|||
/** |
|||
* Copyright © 2016-2021 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.server.service.edge.rpc; |
|||
|
|||
import com.google.common.util.concurrent.SettableFuture; |
|||
import lombok.Data; |
|||
import org.thingsboard.server.gen.edge.v1.DownlinkMsg; |
|||
|
|||
import java.util.LinkedHashMap; |
|||
import java.util.Map; |
|||
import java.util.concurrent.ScheduledFuture; |
|||
|
|||
@Data |
|||
public class EdgeSessionState { |
|||
|
|||
private final Map<Integer, DownlinkMsg> pendingMsgsMap = new LinkedHashMap<>(); |
|||
private SettableFuture<Void> sendDownlinkMsgsFuture; |
|||
private ScheduledFuture<?> scheduledSendDownlinkTask; |
|||
} |
|||
@ -0,0 +1,74 @@ |
|||
/** |
|||
* Copyright © 2016-2021 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.server.service.edge.rpc; |
|||
|
|||
import org.thingsboard.server.common.data.edge.Edge; |
|||
import org.thingsboard.server.common.data.id.EntityId; |
|||
import org.thingsboard.server.service.edge.EdgeContextComponent; |
|||
import org.thingsboard.server.service.edge.rpc.fetch.AdminSettingsEdgeEventFetcher; |
|||
import org.thingsboard.server.service.edge.rpc.fetch.AssetsEdgeEventFetcher; |
|||
import org.thingsboard.server.service.edge.rpc.fetch.CustomerEdgeEventFetcher; |
|||
import org.thingsboard.server.service.edge.rpc.fetch.CustomerUsersEdgeEventFetcher; |
|||
import org.thingsboard.server.service.edge.rpc.fetch.DashboardsEdgeEventFetcher; |
|||
import org.thingsboard.server.service.edge.rpc.fetch.DeviceProfilesEdgeEventFetcher; |
|||
import org.thingsboard.server.service.edge.rpc.fetch.EdgeEventFetcher; |
|||
import org.thingsboard.server.service.edge.rpc.fetch.RuleChainsEdgeEventFetcher; |
|||
import org.thingsboard.server.service.edge.rpc.fetch.SystemWidgetsBundlesEdgeEventFetcher; |
|||
import org.thingsboard.server.service.edge.rpc.fetch.TenantAdminUsersEdgeEventFetcher; |
|||
import org.thingsboard.server.service.edge.rpc.fetch.TenantWidgetsBundlesEdgeEventFetcher; |
|||
|
|||
import java.util.LinkedList; |
|||
import java.util.List; |
|||
import java.util.NoSuchElementException; |
|||
|
|||
public class EdgeSyncCursor { |
|||
|
|||
List<EdgeEventFetcher> fetchers = new LinkedList<>(); |
|||
|
|||
int currentIdx = 0; |
|||
|
|||
public EdgeSyncCursor(EdgeContextComponent ctx, Edge edge) { |
|||
fetchers.add(new SystemWidgetsBundlesEdgeEventFetcher(ctx.getWidgetsBundleService())); |
|||
fetchers.add(new TenantWidgetsBundlesEdgeEventFetcher(ctx.getWidgetsBundleService())); |
|||
fetchers.add(new DeviceProfilesEdgeEventFetcher(ctx.getDeviceProfileService())); |
|||
fetchers.add(new RuleChainsEdgeEventFetcher(ctx.getRuleChainService())); |
|||
fetchers.add(new TenantAdminUsersEdgeEventFetcher(ctx.getUserService())); |
|||
if (edge.getCustomerId() != null && !EntityId.NULL_UUID.equals(edge.getCustomerId().getId())) { |
|||
fetchers.add(new CustomerEdgeEventFetcher()); |
|||
fetchers.add(new CustomerUsersEdgeEventFetcher(ctx.getUserService(), edge.getCustomerId())); |
|||
} |
|||
fetchers.add(new AdminSettingsEdgeEventFetcher(ctx.getAdminSettingsService())); |
|||
fetchers.add(new AssetsEdgeEventFetcher(ctx.getAssetService())); |
|||
fetchers.add(new DashboardsEdgeEventFetcher(ctx.getDashboardService())); |
|||
} |
|||
|
|||
public boolean hasNext() { |
|||
return fetchers.size() > currentIdx; |
|||
} |
|||
|
|||
public EdgeEventFetcher getNext() { |
|||
if (!hasNext()) { |
|||
throw new NoSuchElementException(); |
|||
} |
|||
EdgeEventFetcher edgeEventFetcher = fetchers.get(currentIdx); |
|||
currentIdx++; |
|||
return edgeEventFetcher; |
|||
} |
|||
|
|||
public int getCurrentIdx() { |
|||
return currentIdx; |
|||
} |
|||
} |
|||
@ -0,0 +1,49 @@ |
|||
/** |
|||
* Copyright © 2016-2021 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.server.service.edge.rpc.fetch; |
|||
|
|||
import lombok.AllArgsConstructor; |
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.thingsboard.server.common.data.edge.Edge; |
|||
import org.thingsboard.server.common.data.edge.EdgeEvent; |
|||
import org.thingsboard.server.common.data.edge.EdgeEventActionType; |
|||
import org.thingsboard.server.common.data.edge.EdgeEventType; |
|||
import org.thingsboard.server.common.data.id.TenantId; |
|||
import org.thingsboard.server.common.data.page.PageData; |
|||
import org.thingsboard.server.common.data.page.PageLink; |
|||
import org.thingsboard.server.service.edge.rpc.EdgeEventUtils; |
|||
|
|||
import java.util.ArrayList; |
|||
import java.util.List; |
|||
|
|||
@AllArgsConstructor |
|||
@Slf4j |
|||
public class CustomerEdgeEventFetcher implements EdgeEventFetcher { |
|||
|
|||
@Override |
|||
public PageLink getPageLink(int pageSize) { |
|||
return null; |
|||
} |
|||
|
|||
@Override |
|||
public PageData<EdgeEvent> fetchEdgeEvents(TenantId tenantId, Edge edge, PageLink pageLink) { |
|||
List<EdgeEvent> result = new ArrayList<>(); |
|||
result.add(EdgeEventUtils.constructEdgeEvent(edge.getTenantId(), edge.getId(), |
|||
EdgeEventType.CUSTOMER, EdgeEventActionType.ADDED, edge.getCustomerId(), null)); |
|||
// @voba - returns PageData object to be in sync with other fetchers
|
|||
return new PageData<>(result, 1, result.size(), false); |
|||
} |
|||
} |
|||
@ -0,0 +1,33 @@ |
|||
/** |
|||
* Copyright © 2016-2021 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.server.service.executors; |
|||
|
|||
import org.springframework.beans.factory.annotation.Value; |
|||
import org.springframework.stereotype.Component; |
|||
import org.thingsboard.common.util.AbstractListeningExecutor; |
|||
|
|||
@Component |
|||
public class GrpcCallbackExecutorService extends AbstractListeningExecutor { |
|||
|
|||
@Value("${edges.grpc_callback_thread_pool_size}") |
|||
private int grpcCallbackExecutorThreadPoolSize; |
|||
|
|||
@Override |
|||
protected int getThreadPollSize() { |
|||
return grpcCallbackExecutorThreadPoolSize; |
|||
} |
|||
|
|||
} |
|||
@ -0,0 +1,45 @@ |
|||
/** |
|||
* Copyright © 2016-2021 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.server.service.queue; |
|||
|
|||
import lombok.Builder; |
|||
import lombok.Data; |
|||
import lombok.Getter; |
|||
import lombok.RequiredArgsConstructor; |
|||
import org.thingsboard.server.common.msg.queue.TopicPartitionInfo; |
|||
import org.thingsboard.server.gen.transport.TransportProtos; |
|||
import org.thingsboard.server.queue.TbQueueConsumer; |
|||
import org.thingsboard.server.queue.common.TbProtoQueueMsg; |
|||
|
|||
import java.util.Collections; |
|||
import java.util.Map; |
|||
import java.util.Queue; |
|||
import java.util.Set; |
|||
import java.util.concurrent.ConcurrentHashMap; |
|||
import java.util.concurrent.ConcurrentLinkedQueue; |
|||
import java.util.concurrent.ConcurrentMap; |
|||
import java.util.concurrent.locks.ReentrantLock; |
|||
|
|||
@RequiredArgsConstructor |
|||
@Data |
|||
public class TbTopicWithConsumerPerPartition { |
|||
private final String topic; |
|||
@Getter |
|||
private final ReentrantLock lock = new ReentrantLock(); //NonfairSync
|
|||
private volatile Set<TopicPartitionInfo> partitions = Collections.emptySet(); |
|||
private final ConcurrentMap<TopicPartitionInfo, TbQueueConsumer<TbProtoQueueMsg<TransportProtos.ToRuleEngineMsg>>> consumers = new ConcurrentHashMap<>(); |
|||
private final Queue<Set<TopicPartitionInfo>> subscribeQueue = new ConcurrentLinkedQueue<>(); |
|||
} |
|||
@ -0,0 +1,77 @@ |
|||
/** |
|||
* Copyright © 2016-2021 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.server.service.rpc; |
|||
|
|||
import com.fasterxml.jackson.databind.JsonNode; |
|||
import lombok.RequiredArgsConstructor; |
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.springframework.stereotype.Service; |
|||
import org.thingsboard.common.util.JacksonUtil; |
|||
import org.thingsboard.server.common.data.id.DeviceId; |
|||
import org.thingsboard.server.common.data.id.RpcId; |
|||
import org.thingsboard.server.common.data.id.TenantId; |
|||
import org.thingsboard.server.common.data.page.PageData; |
|||
import org.thingsboard.server.common.data.page.PageLink; |
|||
import org.thingsboard.server.common.data.rpc.Rpc; |
|||
import org.thingsboard.server.common.data.rpc.RpcStatus; |
|||
import org.thingsboard.server.common.msg.TbMsg; |
|||
import org.thingsboard.server.common.msg.TbMsgMetaData; |
|||
import org.thingsboard.server.dao.rpc.RpcService; |
|||
import org.thingsboard.server.queue.util.TbCoreComponent; |
|||
import org.thingsboard.server.service.queue.TbClusterService; |
|||
|
|||
@TbCoreComponent |
|||
@Service |
|||
@RequiredArgsConstructor |
|||
@Slf4j |
|||
public class TbRpcService { |
|||
private final RpcService rpcService; |
|||
private final TbClusterService tbClusterService; |
|||
|
|||
public Rpc save(TenantId tenantId, Rpc rpc) { |
|||
Rpc saved = rpcService.save(rpc); |
|||
pushRpcMsgToRuleEngine(tenantId, saved); |
|||
return saved; |
|||
} |
|||
|
|||
public void save(TenantId tenantId, RpcId rpcId, RpcStatus newStatus, JsonNode response) { |
|||
Rpc foundRpc = rpcService.findById(tenantId, rpcId); |
|||
if (foundRpc != null) { |
|||
foundRpc.setStatus(newStatus); |
|||
if (response != null) { |
|||
foundRpc.setResponse(response); |
|||
} |
|||
Rpc saved = rpcService.save(foundRpc); |
|||
pushRpcMsgToRuleEngine(tenantId, saved); |
|||
} else { |
|||
log.warn("[{}] Failed to update RPC status because RPC was already deleted", rpcId); |
|||
} |
|||
} |
|||
|
|||
private void pushRpcMsgToRuleEngine(TenantId tenantId, Rpc rpc) { |
|||
TbMsg msg = TbMsg.newMsg("RPC_" + rpc.getStatus().name(), rpc.getDeviceId(), TbMsgMetaData.EMPTY, JacksonUtil.toString(rpc)); |
|||
tbClusterService.pushMsgToRuleEngine(tenantId, rpc.getId(), msg, null); |
|||
} |
|||
|
|||
public Rpc findRpcById(TenantId tenantId, RpcId rpcId) { |
|||
return rpcService.findById(tenantId, rpcId); |
|||
} |
|||
|
|||
public PageData<Rpc> findAllByDeviceIdAndStatus(TenantId tenantId, DeviceId deviceId, RpcStatus rpcStatus, PageLink pageLink) { |
|||
return rpcService.findAllByDeviceIdAndStatus(tenantId, deviceId, rpcStatus, pageLink); |
|||
} |
|||
|
|||
} |
|||
@ -0,0 +1,83 @@ |
|||
/** |
|||
* Copyright © 2016-2021 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.server.service.ttl.rpc; |
|||
|
|||
import lombok.RequiredArgsConstructor; |
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.springframework.beans.factory.annotation.Value; |
|||
import org.springframework.scheduling.annotation.Scheduled; |
|||
import org.springframework.stereotype.Service; |
|||
import org.thingsboard.server.common.data.id.TenantId; |
|||
import org.thingsboard.server.common.data.page.PageData; |
|||
import org.thingsboard.server.common.data.page.PageLink; |
|||
import org.thingsboard.server.common.data.tenant.profile.DefaultTenantProfileConfiguration; |
|||
import org.thingsboard.server.common.msg.queue.ServiceType; |
|||
import org.thingsboard.server.dao.rpc.RpcDao; |
|||
import org.thingsboard.server.dao.tenant.TbTenantProfileCache; |
|||
import org.thingsboard.server.dao.tenant.TenantDao; |
|||
import org.thingsboard.server.queue.discovery.PartitionService; |
|||
import org.thingsboard.server.queue.util.TbCoreComponent; |
|||
|
|||
import java.util.Date; |
|||
import java.util.Optional; |
|||
import java.util.concurrent.TimeUnit; |
|||
|
|||
@TbCoreComponent |
|||
@Service |
|||
@Slf4j |
|||
@RequiredArgsConstructor |
|||
public class RpcCleanUpService { |
|||
@Value("${sql.ttl.rpc.enabled}") |
|||
private boolean ttlTaskExecutionEnabled; |
|||
|
|||
private final TenantDao tenantDao; |
|||
private final PartitionService partitionService; |
|||
private final TbTenantProfileCache tenantProfileCache; |
|||
private final RpcDao rpcDao; |
|||
|
|||
@Scheduled(initialDelayString = "#{T(org.apache.commons.lang3.RandomUtils).nextLong(0, ${sql.ttl.rpc.checking_interval})}", fixedDelayString = "${sql.ttl.rpc.checking_interval}") |
|||
public void cleanUp() { |
|||
if (ttlTaskExecutionEnabled) { |
|||
PageLink tenantsBatchRequest = new PageLink(10_000, 0); |
|||
PageData<TenantId> tenantsIds; |
|||
do { |
|||
tenantsIds = tenantDao.findTenantsIds(tenantsBatchRequest); |
|||
for (TenantId tenantId : tenantsIds.getData()) { |
|||
if (!partitionService.resolve(ServiceType.TB_CORE, tenantId, tenantId).isMyPartition()) { |
|||
continue; |
|||
} |
|||
|
|||
Optional<DefaultTenantProfileConfiguration> tenantProfileConfiguration = tenantProfileCache.get(tenantId).getProfileConfiguration(); |
|||
if (tenantProfileConfiguration.isEmpty() || tenantProfileConfiguration.get().getRpcTtlDays() == 0) { |
|||
continue; |
|||
} |
|||
|
|||
long ttl = TimeUnit.DAYS.toMillis(tenantProfileConfiguration.get().getRpcTtlDays()); |
|||
long expirationTime = System.currentTimeMillis() - ttl; |
|||
|
|||
long totalRemoved = rpcDao.deleteOutdatedRpcByTenantId(tenantId, expirationTime); |
|||
|
|||
if (totalRemoved > 0) { |
|||
log.info("Removed {} outdated rpc(s) for tenant {} older than {}", totalRemoved, tenantId, new Date(expirationTime)); |
|||
} |
|||
} |
|||
|
|||
tenantsBatchRequest = tenantsBatchRequest.nextPageLink(); |
|||
} while (tenantsIds.hasNext()); |
|||
} |
|||
} |
|||
|
|||
} |
|||
@ -1,44 +0,0 @@ |
|||
/** |
|||
* Copyright © 2016-2021 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.server.service.ttl.timeseries; |
|||
|
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.springframework.beans.factory.annotation.Value; |
|||
import org.springframework.stereotype.Service; |
|||
import org.thingsboard.server.dao.model.ModelConstants; |
|||
import org.thingsboard.server.dao.util.PsqlDao; |
|||
import org.thingsboard.server.dao.util.SqlTsDao; |
|||
|
|||
import java.sql.Connection; |
|||
import java.sql.SQLException; |
|||
|
|||
@SqlTsDao |
|||
@PsqlDao |
|||
@Service |
|||
@Slf4j |
|||
public class PsqlTimeseriesCleanUpService extends AbstractTimeseriesCleanUpService { |
|||
|
|||
@Value("${sql.postgres.ts_key_value_partitioning}") |
|||
private String partitionType; |
|||
|
|||
@Override |
|||
protected void doCleanUp(Connection connection) throws SQLException { |
|||
long totalPartitionsRemoved = executeQuery(connection, "call drop_partitions_by_max_ttl('" + partitionType + "'," + systemTtl + ", 0);"); |
|||
log.info("Total partitions removed by TTL: [{}]", totalPartitionsRemoved); |
|||
long totalEntitiesTelemetryRemoved = executeQuery(connection, "call cleanup_timeseries_by_ttl('" + ModelConstants.NULL_UUID + "'," + systemTtl + ", 0);"); |
|||
log.info("Total telemetry removed stats by TTL for entities: [{}]", totalEntitiesTelemetryRemoved); |
|||
} |
|||
} |
|||
@ -1,36 +0,0 @@ |
|||
/** |
|||
* Copyright © 2016-2021 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.server.service.ttl.timeseries; |
|||
|
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.springframework.stereotype.Service; |
|||
import org.thingsboard.server.dao.model.ModelConstants; |
|||
import org.thingsboard.server.dao.util.TimescaleDBTsDao; |
|||
|
|||
import java.sql.Connection; |
|||
import java.sql.SQLException; |
|||
|
|||
@TimescaleDBTsDao |
|||
@Service |
|||
@Slf4j |
|||
public class TimescaleTimeseriesCleanUpService extends AbstractTimeseriesCleanUpService { |
|||
|
|||
@Override |
|||
protected void doCleanUp(Connection connection) throws SQLException { |
|||
long totalEntitiesTelemetryRemoved = executeQuery(connection, "call cleanup_timeseries_by_ttl('" + ModelConstants.NULL_UUID + "'," + systemTtl + ", 0);"); |
|||
log.info("Total telemetry removed stats by TTL for entities: [{}]", totalEntitiesTelemetryRemoved); |
|||
} |
|||
} |
|||
@ -0,0 +1,58 @@ |
|||
/** |
|||
* Copyright © 2016-2021 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.server.actors.device; |
|||
|
|||
import org.junit.Before; |
|||
import org.junit.Test; |
|||
import org.thingsboard.common.util.LinkedHashMapRemoveEldest; |
|||
import org.thingsboard.server.actors.ActorSystemContext; |
|||
import org.thingsboard.server.common.data.id.DeviceId; |
|||
import org.thingsboard.server.common.data.id.TenantId; |
|||
import org.thingsboard.server.dao.device.DeviceService; |
|||
|
|||
import static org.hamcrest.CoreMatchers.instanceOf; |
|||
import static org.hamcrest.CoreMatchers.is; |
|||
import static org.hamcrest.CoreMatchers.notNullValue; |
|||
import static org.hamcrest.MatcherAssert.assertThat; |
|||
import static org.mockito.BDDMockito.willReturn; |
|||
import static org.mockito.Mockito.mock; |
|||
|
|||
public class DeviceActorMessageProcessorTest { |
|||
|
|||
public static final long MAX_CONCURRENT_SESSIONS_PER_DEVICE = 10L; |
|||
ActorSystemContext systemContext; |
|||
DeviceService deviceService; |
|||
TenantId tenantId = TenantId.SYS_TENANT_ID; |
|||
DeviceId deviceId = DeviceId.fromString("78bf9b26-74ef-4af2-9cfb-ad6cf24ad2ec"); |
|||
|
|||
DeviceActorMessageProcessor processor; |
|||
|
|||
@Before |
|||
public void setUp() { |
|||
systemContext = mock(ActorSystemContext.class); |
|||
deviceService = mock(DeviceService.class); |
|||
willReturn(MAX_CONCURRENT_SESSIONS_PER_DEVICE).given(systemContext).getMaxConcurrentSessionsPerDevice(); |
|||
willReturn(deviceService).given(systemContext).getDeviceService(); |
|||
processor = new DeviceActorMessageProcessor(systemContext, tenantId, deviceId); |
|||
} |
|||
|
|||
@Test |
|||
public void givenSystemContext_whenNewInstance_thenVerifySessionMapMaxSize() { |
|||
assertThat(processor.sessions, instanceOf(LinkedHashMapRemoveEldest.class)); |
|||
assertThat(processor.sessions.getMaxEntries(), is(MAX_CONCURRENT_SESSIONS_PER_DEVICE)); |
|||
assertThat(processor.sessions.getRemovalConsumer(), notNullValue()); |
|||
} |
|||
} |
|||
@ -0,0 +1,54 @@ |
|||
/** |
|||
* Copyright © 2016-2021 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.server.service.install; |
|||
|
|||
import org.junit.Test; |
|||
|
|||
import static org.mockito.ArgumentMatchers.anyString; |
|||
import static org.mockito.BDDMockito.willDoNothing; |
|||
import static org.mockito.Mockito.spy; |
|||
import static org.mockito.Mockito.times; |
|||
import static org.mockito.Mockito.verify; |
|||
|
|||
public class PsqlEntityDatabaseSchemaServiceTest { |
|||
|
|||
@Test |
|||
public void givenPsqlDbSchemaService_whenCreateDatabaseSchema_thenVerifyPsqlIndexSpecificCall() throws Exception { |
|||
PsqlEntityDatabaseSchemaService service = spy(new PsqlEntityDatabaseSchemaService()); |
|||
willDoNothing().given(service).executeQueryFromFile(anyString()); |
|||
|
|||
service.createDatabaseSchema(); |
|||
|
|||
verify(service, times(1)).createDatabaseIndexes(); |
|||
verify(service, times(1)).executeQueryFromFile(PsqlEntityDatabaseSchemaService.SCHEMA_ENTITIES_SQL); |
|||
verify(service, times(1)).executeQueryFromFile(PsqlEntityDatabaseSchemaService.SCHEMA_ENTITIES_IDX_SQL); |
|||
verify(service, times(1)).executeQueryFromFile(PsqlEntityDatabaseSchemaService.SCHEMA_ENTITIES_IDX_PSQL_ADDON_SQL); |
|||
verify(service, times(3)).executeQueryFromFile(anyString()); |
|||
} |
|||
|
|||
@Test |
|||
public void givenPsqlDbSchemaService_whenCreateDatabaseIndexes_thenVerifyPsqlIndexSpecificCall() throws Exception { |
|||
PsqlEntityDatabaseSchemaService service = spy(new PsqlEntityDatabaseSchemaService()); |
|||
willDoNothing().given(service).executeQueryFromFile(anyString()); |
|||
|
|||
service.createDatabaseIndexes(); |
|||
|
|||
verify(service, times(1)).executeQueryFromFile(PsqlEntityDatabaseSchemaService.SCHEMA_ENTITIES_IDX_SQL); |
|||
verify(service, times(1)).executeQueryFromFile(PsqlEntityDatabaseSchemaService.SCHEMA_ENTITIES_IDX_PSQL_ADDON_SQL); |
|||
verify(service, times(2)).executeQueryFromFile(anyString()); |
|||
} |
|||
|
|||
} |
|||
@ -0,0 +1,83 @@ |
|||
/** |
|||
* Copyright © 2016-2021 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.server.service.state; |
|||
|
|||
import org.junit.Before; |
|||
import org.junit.Test; |
|||
import org.junit.runner.RunWith; |
|||
import org.mockito.Mock; |
|||
import org.mockito.Mockito; |
|||
import org.mockito.junit.MockitoJUnitRunner; |
|||
import org.thingsboard.server.common.data.id.DeviceId; |
|||
import org.thingsboard.server.dao.attributes.AttributesService; |
|||
import org.thingsboard.server.dao.device.DeviceService; |
|||
import org.thingsboard.server.dao.tenant.TenantService; |
|||
import org.thingsboard.server.dao.timeseries.TimeseriesService; |
|||
import org.thingsboard.server.queue.discovery.PartitionService; |
|||
import org.thingsboard.server.service.queue.TbClusterService; |
|||
|
|||
import static org.hamcrest.CoreMatchers.is; |
|||
import static org.hamcrest.MatcherAssert.assertThat; |
|||
import static org.mockito.BDDMockito.willReturn; |
|||
import static org.mockito.Mockito.never; |
|||
import static org.mockito.Mockito.spy; |
|||
import static org.mockito.Mockito.times; |
|||
|
|||
@RunWith(MockitoJUnitRunner.class) |
|||
public class DefaultDeviceStateServiceTest { |
|||
|
|||
@Mock |
|||
TenantService tenantService; |
|||
@Mock |
|||
DeviceService deviceService; |
|||
@Mock |
|||
AttributesService attributesService; |
|||
@Mock |
|||
TimeseriesService tsService; |
|||
@Mock |
|||
TbClusterService clusterService; |
|||
@Mock |
|||
PartitionService partitionService; |
|||
@Mock |
|||
DeviceStateData deviceStateDataMock; |
|||
|
|||
DeviceId deviceId = DeviceId.fromString("00797a3b-7aeb-4b5b-b57a-c2a810d0f112"); |
|||
|
|||
DefaultDeviceStateService service; |
|||
|
|||
@Before |
|||
public void setUp() { |
|||
service = spy(new DefaultDeviceStateService(tenantService, deviceService, attributesService, tsService, clusterService, partitionService)); |
|||
} |
|||
|
|||
@Test |
|||
public void givenDeviceIdFromDeviceStatesMap_whenGetOrFetchDeviceStateData_thenNoStackOverflow() { |
|||
service.deviceStates.put(deviceId, deviceStateDataMock); |
|||
DeviceStateData deviceStateData = service.getOrFetchDeviceStateData(deviceId); |
|||
assertThat(deviceStateData, is(deviceStateDataMock)); |
|||
Mockito.verify(service, never()).fetchDeviceStateData(deviceId); |
|||
} |
|||
|
|||
@Test |
|||
public void givenDeviceIdWithoutDeviceStateInMap_whenGetOrFetchDeviceStateData_thenFetchDeviceStateData() { |
|||
service.deviceStates.clear(); |
|||
willReturn(deviceStateDataMock).given(service).fetchDeviceStateData(deviceId); |
|||
DeviceStateData deviceStateData = service.getOrFetchDeviceStateData(deviceId); |
|||
assertThat(deviceStateData, is(deviceStateDataMock)); |
|||
Mockito.verify(service, times(1)).fetchDeviceStateData(deviceId); |
|||
} |
|||
|
|||
} |
|||
@ -0,0 +1,50 @@ |
|||
/** |
|||
* Copyright © 2016-2021 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.server.service.ttl; |
|||
|
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.junit.Test; |
|||
import org.junit.runner.RunWith; |
|||
import org.springframework.beans.factory.annotation.Value; |
|||
import org.springframework.boot.test.context.SpringBootTest; |
|||
import org.springframework.test.context.junit4.SpringRunner; |
|||
|
|||
import static org.hamcrest.MatcherAssert.assertThat; |
|||
import static org.hamcrest.Matchers.greaterThanOrEqualTo; |
|||
import static org.hamcrest.Matchers.is; |
|||
import static org.hamcrest.Matchers.lessThanOrEqualTo; |
|||
import static org.thingsboard.server.service.ttl.EventsCleanUpService.RANDOM_DELAY_INTERVAL_MS_EXPRESSION; |
|||
|
|||
@RunWith(SpringRunner.class) |
|||
@SpringBootTest(classes = EventsCleanUpServiceTest.class) |
|||
@Slf4j |
|||
public class EventsCleanUpServiceTest { |
|||
|
|||
@Value(RANDOM_DELAY_INTERVAL_MS_EXPRESSION) |
|||
long randomDelayMs; |
|||
@Value("${sql.ttl.events.execution_interval_ms}") |
|||
long executionIntervalMs; |
|||
|
|||
@Test |
|||
public void givenInterval_whenRandomDelay_ThenDelayInInterval() { |
|||
log.info("randomDelay {}", randomDelayMs); |
|||
log.info("executionIntervalMs {}", executionIntervalMs); |
|||
assertThat(executionIntervalMs, is(2220000L)); |
|||
assertThat(randomDelayMs, greaterThanOrEqualTo(0L)); |
|||
assertThat(randomDelayMs, lessThanOrEqualTo(executionIntervalMs)); |
|||
} |
|||
|
|||
} |
|||
@ -0,0 +1,43 @@ |
|||
/** |
|||
* Copyright © 2016-2021 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.server.transport.lwm2m; |
|||
|
|||
import org.eclipse.leshan.client.object.Security; |
|||
import org.eclipse.leshan.core.util.Hex; |
|||
import org.junit.Test; |
|||
import org.thingsboard.server.common.data.device.credentials.lwm2m.PSKClientCredentials; |
|||
|
|||
import java.nio.charset.StandardCharsets; |
|||
|
|||
import static org.eclipse.leshan.client.object.Security.psk; |
|||
|
|||
public class PskLwm2mIntegrationTest extends AbstractLwM2MIntegrationTest { |
|||
|
|||
@Test |
|||
public void testConnectWithPSKAndObserveTelemetry() throws Exception { |
|||
String pskIdentity = "SOME_PSK_ID"; |
|||
String pskKey = "73656372657450534b"; |
|||
PSKClientCredentials clientCredentials = new PSKClientCredentials(); |
|||
clientCredentials.setEndpoint(ENDPOINT); |
|||
clientCredentials.setKey(pskKey); |
|||
clientCredentials.setIdentity(pskIdentity); |
|||
Security security = psk(SECURE_URI, |
|||
123, |
|||
pskIdentity.getBytes(StandardCharsets.UTF_8), |
|||
Hex.decodeHex(pskKey.toCharArray())); |
|||
super.basicTestConnectionObserveTelemetry(security, clientCredentials, SECURE_COAP_CONFIG, ENDPOINT); |
|||
} |
|||
} |
|||
@ -0,0 +1,40 @@ |
|||
/** |
|||
* Copyright © 2016-2021 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.server.transport.lwm2m; |
|||
|
|||
import org.eclipse.leshan.client.object.Security; |
|||
import org.eclipse.leshan.core.util.Hex; |
|||
import org.junit.Test; |
|||
import org.thingsboard.server.common.data.device.credentials.lwm2m.RPKClientCredentials; |
|||
|
|||
import static org.eclipse.leshan.client.object.Security.rpk; |
|||
|
|||
public class RpkLwM2MIntegrationTest extends AbstractLwM2MIntegrationTest { |
|||
|
|||
@Test |
|||
public void testConnectWithRPKAndObserveTelemetry() throws Exception { |
|||
RPKClientCredentials rpkClientCredentials = new RPKClientCredentials(); |
|||
rpkClientCredentials.setEndpoint(ENDPOINT); |
|||
rpkClientCredentials.setKey(Hex.encodeHexString(clientPublicKey.getEncoded())); |
|||
Security security = rpk(SECURE_URI, |
|||
123, |
|||
clientPublicKey.getEncoded(), |
|||
clientPrivateKey.getEncoded(), |
|||
serverX509Cert.getPublicKey().getEncoded()); |
|||
super.basicTestConnectionObserveTelemetry(security, rpkClientCredentials, SECURE_COAP_CONFIG, ENDPOINT); |
|||
} |
|||
|
|||
} |
|||
@ -0,0 +1,155 @@ |
|||
/** |
|||
* Copyright © 2016-2021 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.server.transport.lwm2m.client; |
|||
|
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.eclipse.leshan.client.resource.BaseInstanceEnabler; |
|||
import org.eclipse.leshan.client.servers.ServerIdentity; |
|||
import org.eclipse.leshan.core.model.ObjectModel; |
|||
import org.eclipse.leshan.core.node.LwM2mResource; |
|||
import org.eclipse.leshan.core.response.ExecuteResponse; |
|||
import org.eclipse.leshan.core.response.ReadResponse; |
|||
import org.eclipse.leshan.core.response.WriteResponse; |
|||
|
|||
import javax.security.auth.Destroyable; |
|||
import java.util.Arrays; |
|||
import java.util.List; |
|||
import java.util.concurrent.Executors; |
|||
import java.util.concurrent.ScheduledExecutorService; |
|||
import java.util.concurrent.TimeUnit; |
|||
import java.util.concurrent.atomic.AtomicInteger; |
|||
|
|||
@Slf4j |
|||
public class FwLwM2MDevice extends BaseInstanceEnabler implements Destroyable { |
|||
|
|||
private static final List<Integer> supportedResources = Arrays.asList(0, 1, 2, 3, 5, 6, 7, 9); |
|||
|
|||
private final ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor(); |
|||
|
|||
private final AtomicInteger state = new AtomicInteger(0); |
|||
|
|||
private final AtomicInteger updateResult = new AtomicInteger(0); |
|||
|
|||
@Override |
|||
public ReadResponse read(ServerIdentity identity, int resourceId) { |
|||
if (!identity.isSystem()) |
|||
log.info("Read on Device resource /{}/{}/{}", getModel().id, getId(), resourceId); |
|||
switch (resourceId) { |
|||
case 3: |
|||
return ReadResponse.success(resourceId, getState()); |
|||
case 5: |
|||
return ReadResponse.success(resourceId, getUpdateResult()); |
|||
case 6: |
|||
return ReadResponse.success(resourceId, getPkgName()); |
|||
case 7: |
|||
return ReadResponse.success(resourceId, getPkgVersion()); |
|||
case 9: |
|||
return ReadResponse.success(resourceId, getFirmwareUpdateDeliveryMethod()); |
|||
default: |
|||
return super.read(identity, resourceId); |
|||
} |
|||
} |
|||
|
|||
@Override |
|||
public ExecuteResponse execute(ServerIdentity identity, int resourceId, String params) { |
|||
String withParams = null; |
|||
if (params != null && params.length() != 0) { |
|||
withParams = " with params " + params; |
|||
} |
|||
log.info("Execute on Device resource /{}/{}/{} {}", getModel().id, getId(), resourceId, withParams != null ? withParams : ""); |
|||
|
|||
switch (resourceId) { |
|||
case 2: |
|||
startUpdating(); |
|||
return ExecuteResponse.success(); |
|||
default: |
|||
return super.execute(identity, resourceId, params); |
|||
} |
|||
} |
|||
|
|||
@Override |
|||
public WriteResponse write(ServerIdentity identity, boolean replace, int resourceId, LwM2mResource value) { |
|||
log.info("Write on Device resource /{}/{}/{}", getModel().id, getId(), resourceId); |
|||
|
|||
switch (resourceId) { |
|||
case 0: |
|||
startDownloading(); |
|||
return WriteResponse.success(); |
|||
case 1: |
|||
startDownloading(); |
|||
return WriteResponse.success(); |
|||
default: |
|||
return super.write(identity, replace, resourceId, value); |
|||
} |
|||
} |
|||
|
|||
private int getState() { |
|||
return state.get(); |
|||
} |
|||
|
|||
private int getUpdateResult() { |
|||
return updateResult.get(); |
|||
} |
|||
|
|||
private String getPkgName() { |
|||
return "firmware"; |
|||
} |
|||
|
|||
private String getPkgVersion() { |
|||
return "1.0.0"; |
|||
} |
|||
|
|||
private int getFirmwareUpdateDeliveryMethod() { |
|||
return 1; |
|||
} |
|||
|
|||
@Override |
|||
public List<Integer> getAvailableResourceIds(ObjectModel model) { |
|||
return supportedResources; |
|||
} |
|||
|
|||
@Override |
|||
public void destroy() { |
|||
scheduler.shutdownNow(); |
|||
} |
|||
|
|||
private void startDownloading() { |
|||
scheduler.schedule(() -> { |
|||
try { |
|||
state.set(1); |
|||
fireResourcesChange(3); |
|||
Thread.sleep(100); |
|||
state.set(2); |
|||
fireResourcesChange(3); |
|||
} catch (Exception e) { |
|||
} |
|||
}, 100, TimeUnit.MILLISECONDS); |
|||
} |
|||
|
|||
private void startUpdating() { |
|||
scheduler.schedule(() -> { |
|||
try { |
|||
state.set(3); |
|||
fireResourcesChange(3); |
|||
Thread.sleep(100); |
|||
updateResult.set(1); |
|||
fireResourcesChange(5); |
|||
} catch (Exception e) { |
|||
} |
|||
}, 100, TimeUnit.MILLISECONDS); |
|||
} |
|||
|
|||
} |
|||
@ -0,0 +1,155 @@ |
|||
/** |
|||
* Copyright © 2016-2021 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.server.transport.lwm2m.client; |
|||
|
|||
import lombok.SneakyThrows; |
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.eclipse.leshan.client.resource.BaseInstanceEnabler; |
|||
import org.eclipse.leshan.client.servers.ServerIdentity; |
|||
import org.eclipse.leshan.core.model.ObjectModel; |
|||
import org.eclipse.leshan.core.node.LwM2mResource; |
|||
import org.eclipse.leshan.core.response.ExecuteResponse; |
|||
import org.eclipse.leshan.core.response.ReadResponse; |
|||
import org.eclipse.leshan.core.response.WriteResponse; |
|||
|
|||
import javax.security.auth.Destroyable; |
|||
import java.util.Arrays; |
|||
import java.util.List; |
|||
import java.util.concurrent.Executors; |
|||
import java.util.concurrent.ScheduledExecutorService; |
|||
import java.util.concurrent.TimeUnit; |
|||
import java.util.concurrent.atomic.AtomicInteger; |
|||
|
|||
@Slf4j |
|||
public class SwLwM2MDevice extends BaseInstanceEnabler implements Destroyable { |
|||
|
|||
private static final List<Integer> supportedResources = Arrays.asList(0, 1, 2, 3, 4, 6, 7, 9); |
|||
|
|||
private final ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor(); |
|||
|
|||
private final AtomicInteger state = new AtomicInteger(0); |
|||
|
|||
private final AtomicInteger updateResult = new AtomicInteger(0); |
|||
|
|||
@Override |
|||
public ReadResponse read(ServerIdentity identity, int resourceId) { |
|||
if (!identity.isSystem()) |
|||
log.info("Read on Device resource /{}/{}/{}", getModel().id, getId(), resourceId); |
|||
switch (resourceId) { |
|||
case 0: |
|||
return ReadResponse.success(resourceId, getPkgName()); |
|||
case 1: |
|||
return ReadResponse.success(resourceId, getPkgVersion()); |
|||
case 7: |
|||
return ReadResponse.success(resourceId, getUpdateState()); |
|||
case 9: |
|||
return ReadResponse.success(resourceId, getUpdateResult()); |
|||
default: |
|||
return super.read(identity, resourceId); |
|||
} |
|||
} |
|||
|
|||
@Override |
|||
public ExecuteResponse execute(ServerIdentity identity, int resourceId, String params) { |
|||
String withParams = null; |
|||
if (params != null && params.length() != 0) { |
|||
withParams = " with params " + params; |
|||
} |
|||
log.info("Execute on Device resource /{}/{}/{} {}", getModel().id, getId(), resourceId, withParams != null ? withParams : ""); |
|||
|
|||
switch (resourceId) { |
|||
case 4: |
|||
startUpdating(); |
|||
return ExecuteResponse.success(); |
|||
case 6: |
|||
return ExecuteResponse.success(); |
|||
default: |
|||
return super.execute(identity, resourceId, params); |
|||
} |
|||
} |
|||
|
|||
@Override |
|||
public WriteResponse write(ServerIdentity identity, boolean replace, int resourceId, LwM2mResource value) { |
|||
log.info("Write on Device resource /{}/{}/{}", getModel().id, getId(), resourceId); |
|||
|
|||
switch (resourceId) { |
|||
case 2: |
|||
startDownloading(); |
|||
return WriteResponse.success(); |
|||
case 3: |
|||
startDownloading(); |
|||
return WriteResponse.success(); |
|||
default: |
|||
return super.write(identity, replace, resourceId, value); |
|||
} |
|||
} |
|||
|
|||
private int getUpdateState() { |
|||
return state.get(); |
|||
} |
|||
|
|||
private int getUpdateResult() { |
|||
return updateResult.get(); |
|||
} |
|||
|
|||
private String getPkgName() { |
|||
return "software"; |
|||
} |
|||
|
|||
private String getPkgVersion() { |
|||
return "1.0.0"; |
|||
} |
|||
|
|||
@Override |
|||
public List<Integer> getAvailableResourceIds(ObjectModel model) { |
|||
return supportedResources; |
|||
} |
|||
|
|||
@Override |
|||
public void destroy() { |
|||
scheduler.shutdownNow(); |
|||
} |
|||
|
|||
private void startDownloading() { |
|||
scheduler.schedule(() -> { |
|||
try { |
|||
state.set(1); |
|||
updateResult.set(1); |
|||
fireResourcesChange(7, 9); |
|||
Thread.sleep(100); |
|||
state.set(2); |
|||
fireResourcesChange(7); |
|||
Thread.sleep(100); |
|||
state.set(3); |
|||
fireResourcesChange(7); |
|||
Thread.sleep(100); |
|||
updateResult.set(3); |
|||
fireResourcesChange(9); |
|||
} catch (Exception e) { |
|||
|
|||
} |
|||
}, 100, TimeUnit.MILLISECONDS); |
|||
} |
|||
|
|||
private void startUpdating() { |
|||
scheduler.schedule(() -> { |
|||
state.set(4); |
|||
updateResult.set(2); |
|||
fireResourcesChange(7, 9); |
|||
}, 100, TimeUnit.MILLISECONDS); |
|||
} |
|||
|
|||
} |
|||
Some files were not shown because too many files changed in this diff
Loading…
Reference in new issue