Claiming devices using claimData attribute (#2105)
* Claiming devices using claimData attribute * Fixed license header
This commit is contained in:
parent
25e36583f8
commit
2b7df84ae9
@ -0,0 +1,30 @@
|
|||||||
|
/**
|
||||||
|
* Copyright © 2016-2019 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.dao.device;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
import org.thingsboard.server.dao.device.claim.ClaimData;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public class ClaimDataInfo {
|
||||||
|
|
||||||
|
private final boolean fromCache;
|
||||||
|
private final List<Object> key;
|
||||||
|
private final ClaimData data;
|
||||||
|
|
||||||
|
}
|
||||||
@ -23,12 +23,13 @@ import org.thingsboard.server.common.data.id.TenantId;
|
|||||||
import org.thingsboard.server.dao.device.claim.ClaimResult;
|
import org.thingsboard.server.dao.device.claim.ClaimResult;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.concurrent.ExecutionException;
|
||||||
|
|
||||||
public interface ClaimDevicesService {
|
public interface ClaimDevicesService {
|
||||||
|
|
||||||
ListenableFuture<Void> registerClaimingInfo(TenantId tenantId, DeviceId deviceId, String secretKey, long durationMs);
|
ListenableFuture<Void> registerClaimingInfo(TenantId tenantId, DeviceId deviceId, String secretKey, long durationMs);
|
||||||
|
|
||||||
ListenableFuture<ClaimResult> claimDevice(Device device, CustomerId customerId, String secretKey);
|
ListenableFuture<ClaimResult> claimDevice(Device device, CustomerId customerId, String secretKey) throws ExecutionException, InterruptedException;
|
||||||
|
|
||||||
ListenableFuture<List<Void>> reClaimDevice(TenantId tenantId, Device device);
|
ListenableFuture<List<Void>> reClaimDevice(TenantId tenantId, Device device);
|
||||||
|
|
||||||
|
|||||||
@ -15,6 +15,7 @@
|
|||||||
*/
|
*/
|
||||||
package org.thingsboard.server.dao.device;
|
package org.thingsboard.server.dao.device;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
import com.google.common.util.concurrent.Futures;
|
import com.google.common.util.concurrent.Futures;
|
||||||
import com.google.common.util.concurrent.ListenableFuture;
|
import com.google.common.util.concurrent.ListenableFuture;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
@ -23,6 +24,7 @@ import org.springframework.beans.factory.annotation.Value;
|
|||||||
import org.springframework.cache.Cache;
|
import org.springframework.cache.Cache;
|
||||||
import org.springframework.cache.CacheManager;
|
import org.springframework.cache.CacheManager;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.util.StringUtils;
|
||||||
import org.thingsboard.server.common.data.DataConstants;
|
import org.thingsboard.server.common.data.DataConstants;
|
||||||
import org.thingsboard.server.common.data.Device;
|
import org.thingsboard.server.common.data.Device;
|
||||||
import org.thingsboard.server.common.data.id.CustomerId;
|
import org.thingsboard.server.common.data.id.CustomerId;
|
||||||
@ -37,9 +39,12 @@ import org.thingsboard.server.dao.device.claim.ClaimResponse;
|
|||||||
import org.thingsboard.server.dao.device.claim.ClaimResult;
|
import org.thingsboard.server.dao.device.claim.ClaimResult;
|
||||||
import org.thingsboard.server.dao.model.ModelConstants;
|
import org.thingsboard.server.dao.model.ModelConstants;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
import java.util.concurrent.ExecutionException;
|
||||||
|
|
||||||
import static org.thingsboard.server.common.data.CacheConstants.CLAIM_DEVICES_CACHE;
|
import static org.thingsboard.server.common.data.CacheConstants.CLAIM_DEVICES_CACHE;
|
||||||
|
|
||||||
@ -48,6 +53,8 @@ import static org.thingsboard.server.common.data.CacheConstants.CLAIM_DEVICES_CA
|
|||||||
public class ClaimDevicesServiceImpl implements ClaimDevicesService {
|
public class ClaimDevicesServiceImpl implements ClaimDevicesService {
|
||||||
|
|
||||||
private static final String CLAIM_ATTRIBUTE_NAME = "claimingAllowed";
|
private static final String CLAIM_ATTRIBUTE_NAME = "claimingAllowed";
|
||||||
|
private static final String CLAIM_DATA_ATTRIBUTE_NAME = "claimingData";
|
||||||
|
private static final ObjectMapper mapper = new ObjectMapper();
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private DeviceService deviceService;
|
private DeviceService deviceService;
|
||||||
@ -95,24 +102,45 @@ public class ClaimDevicesServiceImpl implements ClaimDevicesService {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
private ClaimDataInfo getClaimData(Cache cache, Device device) throws ExecutionException, InterruptedException {
|
||||||
public ListenableFuture<ClaimResult> claimDevice(Device device, CustomerId customerId, String secretKey) {
|
|
||||||
List<Object> key = constructCacheKey(device.getId());
|
List<Object> key = constructCacheKey(device.getId());
|
||||||
|
ClaimData claimDataFromCache = cache.get(key, ClaimData.class);
|
||||||
|
if (claimDataFromCache != null) {
|
||||||
|
return new ClaimDataInfo(true, key, claimDataFromCache);
|
||||||
|
} else {
|
||||||
|
Optional<AttributeKvEntry> claimDataAttr = attributesService.find(device.getTenantId(), device.getId(),
|
||||||
|
DataConstants.SERVER_SCOPE, CLAIM_DATA_ATTRIBUTE_NAME).get();
|
||||||
|
if (claimDataAttr.isPresent()) {
|
||||||
|
try {
|
||||||
|
ClaimData claimDataFromAttribute = mapper.readValue(claimDataAttr.get().getValueAsString(), ClaimData.class);
|
||||||
|
return new ClaimDataInfo(false, key, claimDataFromAttribute);
|
||||||
|
} catch (IOException e) {
|
||||||
|
log.warn("Failed to read Claim Data [{}] from attribute!", claimDataAttr, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ListenableFuture<ClaimResult> claimDevice(Device device, CustomerId customerId, String secretKey) throws ExecutionException, InterruptedException {
|
||||||
Cache cache = cacheManager.getCache(CLAIM_DEVICES_CACHE);
|
Cache cache = cacheManager.getCache(CLAIM_DEVICES_CACHE);
|
||||||
ClaimData claimData = cache.get(key, ClaimData.class);
|
ClaimDataInfo claimData = getClaimData(cache, device);
|
||||||
if (claimData != null) {
|
if (claimData != null) {
|
||||||
long currTs = System.currentTimeMillis();
|
long currTs = System.currentTimeMillis();
|
||||||
if (currTs > claimData.getExpirationTime() || !secretKey.equals(claimData.getSecretKey())) {
|
if (currTs > claimData.getData().getExpirationTime() || !secretKeyIsEmptyOrEqual(secretKey, claimData.getData().getSecretKey())) {
|
||||||
log.warn("The claiming timeout occurred or wrong 'secretKey' provided for the device [{}]", device.getName());
|
log.warn("The claiming timeout occurred or wrong 'secretKey' provided for the device [{}]", device.getName());
|
||||||
cache.evict(key);
|
if (claimData.isFromCache()) {
|
||||||
|
cache.evict(claimData.getKey());
|
||||||
|
}
|
||||||
return Futures.immediateFuture(new ClaimResult(null, ClaimResponse.FAILURE));
|
return Futures.immediateFuture(new ClaimResult(null, ClaimResponse.FAILURE));
|
||||||
} else {
|
} else {
|
||||||
if (device.getCustomerId().getId().equals(ModelConstants.NULL_UUID)) {
|
if (device.getCustomerId().getId().equals(ModelConstants.NULL_UUID)) {
|
||||||
device.setCustomerId(customerId);
|
device.setCustomerId(customerId);
|
||||||
Device savedDevice = deviceService.saveDevice(device);
|
Device savedDevice = deviceService.saveDevice(device);
|
||||||
return Futures.transform(removeClaimingSavedData(cache, key, device), result -> new ClaimResult(savedDevice, ClaimResponse.SUCCESS));
|
return Futures.transform(removeClaimingSavedData(cache, claimData, device), result -> new ClaimResult(savedDevice, ClaimResponse.SUCCESS));
|
||||||
}
|
}
|
||||||
return Futures.transform(removeClaimingSavedData(cache, key, device), result -> new ClaimResult(null, ClaimResponse.CLAIMED));
|
return Futures.transform(removeClaimingSavedData(cache, claimData, device), result -> new ClaimResult(null, ClaimResponse.CLAIMED));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
log.warn("Failed to find the device's claiming message![{}]", device.getName());
|
log.warn("Failed to find the device's claiming message![{}]", device.getName());
|
||||||
@ -124,6 +152,10 @@ public class ClaimDevicesServiceImpl implements ClaimDevicesService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean secretKeyIsEmptyOrEqual(String secretKeyA, String secretKeyB) {
|
||||||
|
return (StringUtils.isEmpty(secretKeyA) && StringUtils.isEmpty(secretKeyB)) || secretKeyA.equals(secretKeyB);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ListenableFuture<List<Void>> reClaimDevice(TenantId tenantId, Device device) {
|
public ListenableFuture<List<Void>> reClaimDevice(TenantId tenantId, Device device) {
|
||||||
if (!device.getCustomerId().getId().equals(ModelConstants.NULL_UUID)) {
|
if (!device.getCustomerId().getId().equals(ModelConstants.NULL_UUID)) {
|
||||||
@ -159,13 +191,12 @@ public class ClaimDevicesServiceImpl implements ClaimDevicesService {
|
|||||||
return systemDurationMs;
|
return systemDurationMs;
|
||||||
}
|
}
|
||||||
|
|
||||||
private ListenableFuture<List<Void>> removeClaimingSavedData(Cache cache, List<Object> key, Device device) {
|
private ListenableFuture<List<Void>> removeClaimingSavedData(Cache cache, ClaimDataInfo data, Device device) {
|
||||||
cache.evict(key);
|
if (data.isFromCache()) {
|
||||||
if (isAllowedClaimingByDefault) {
|
cache.evict(data.getKey());
|
||||||
return Futures.immediateFuture(null);
|
|
||||||
}
|
}
|
||||||
return attributesService.removeAll(device.getTenantId(),
|
return attributesService.removeAll(device.getTenantId(),
|
||||||
device.getId(), DataConstants.SERVER_SCOPE, Collections.singletonList(CLAIM_ATTRIBUTE_NAME));
|
device.getId(), DataConstants.SERVER_SCOPE, Arrays.asList(CLAIM_ATTRIBUTE_NAME, CLAIM_DATA_ATTRIBUTE_NAME));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void cacheEviction(DeviceId deviceId) {
|
private void cacheEviction(DeviceId deviceId) {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user