Caching of main requests related to relations and GWs API (#567)
* added enable/disable condition for transport protocols * fix coap tests * configured relations cache * minor fix * Improvements * delete devices caching
This commit is contained in:
parent
f6da85e9ae
commit
d727a8a3b4
@ -77,6 +77,8 @@ http:
|
|||||||
|
|
||||||
# MQTT server parameters
|
# MQTT server parameters
|
||||||
mqtt:
|
mqtt:
|
||||||
|
# Enable/disable mqtt transport protocol.
|
||||||
|
enabled: "${MQTT_ENABLED:true}"
|
||||||
bind_address: "${MQTT_BIND_ADDRESS:0.0.0.0}"
|
bind_address: "${MQTT_BIND_ADDRESS:0.0.0.0}"
|
||||||
bind_port: "${MQTT_BIND_PORT:1883}"
|
bind_port: "${MQTT_BIND_PORT:1883}"
|
||||||
adaptor: "${MQTT_ADAPTOR_NAME:JsonMqttAdaptor}"
|
adaptor: "${MQTT_ADAPTOR_NAME:JsonMqttAdaptor}"
|
||||||
@ -102,6 +104,8 @@ mqtt:
|
|||||||
|
|
||||||
# CoAP server parameters
|
# CoAP server parameters
|
||||||
coap:
|
coap:
|
||||||
|
# Enable/disable coap transport protocol.
|
||||||
|
enabled: "${COAP_ENABLED:true}"
|
||||||
bind_address: "${COAP_BIND_ADDRESS:0.0.0.0}"
|
bind_address: "${COAP_BIND_ADDRESS:0.0.0.0}"
|
||||||
bind_port: "${COAP_BIND_PORT:5683}"
|
bind_port: "${COAP_BIND_PORT:5683}"
|
||||||
adaptor: "${COAP_ADAPTOR_NAME:JsonCoapAdaptor}"
|
adaptor: "${COAP_ADAPTOR_NAME:JsonCoapAdaptor}"
|
||||||
@ -208,6 +212,18 @@ cache:
|
|||||||
policy: "${CACHE_DEVICE_CREDENTIAL_MAX_SIZE_POLICY:PER_NODE}"
|
policy: "${CACHE_DEVICE_CREDENTIAL_MAX_SIZE_POLICY:PER_NODE}"
|
||||||
size: "${CACHE_DEVICE_CREDENTIAL_MAX_SIZE_SIZE:1000000}"
|
size: "${CACHE_DEVICE_CREDENTIAL_MAX_SIZE_SIZE:1000000}"
|
||||||
|
|
||||||
|
caching:
|
||||||
|
specs:
|
||||||
|
relations:
|
||||||
|
timeToLiveInMinutes: 1440
|
||||||
|
maxSize: 100000
|
||||||
|
deviceCredentials:
|
||||||
|
timeToLiveInMinutes: 1440
|
||||||
|
maxSize: 100000
|
||||||
|
devices:
|
||||||
|
timeToLiveInMinutes: 1440
|
||||||
|
maxSize: 100000
|
||||||
|
|
||||||
# Check new version updates parameters
|
# Check new version updates parameters
|
||||||
updates:
|
updates:
|
||||||
# Enable/disable updates checking.
|
# Enable/disable updates checking.
|
||||||
|
|||||||
@ -17,4 +17,6 @@ package org.thingsboard.server.common.data;
|
|||||||
|
|
||||||
public class CacheConstants {
|
public class CacheConstants {
|
||||||
public static final String DEVICE_CREDENTIALS_CACHE = "deviceCredentials";
|
public static final String DEVICE_CREDENTIALS_CACHE = "deviceCredentials";
|
||||||
|
public static final String RELATIONS_CACHE = "relations";
|
||||||
|
public static final String DEVICE_CACHE = "devices";
|
||||||
}
|
}
|
||||||
|
|||||||
@ -148,6 +148,10 @@
|
|||||||
<groupId>com.hazelcast</groupId>
|
<groupId>com.hazelcast</groupId>
|
||||||
<artifactId>hazelcast</artifactId>
|
<artifactId>hazelcast</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.github.ben-manes.caffeine</groupId>
|
||||||
|
<artifactId>caffeine</artifactId>
|
||||||
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.hazelcast</groupId>
|
<groupId>com.hazelcast</groupId>
|
||||||
<artifactId>hazelcast-spring</artifactId>
|
<artifactId>hazelcast-spring</artifactId>
|
||||||
@ -174,6 +178,10 @@
|
|||||||
<artifactId>hsqldb</artifactId>
|
<artifactId>hsqldb</artifactId>
|
||||||
<scope>test</scope>
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework</groupId>
|
||||||
|
<artifactId>spring-context-support</artifactId>
|
||||||
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
<build>
|
<build>
|
||||||
<plugins>
|
<plugins>
|
||||||
|
|||||||
24
dao/src/main/java/org/thingsboard/server/dao/cache/CacheSpecs.java
vendored
Normal file
24
dao/src/main/java/org/thingsboard/server/dao/cache/CacheSpecs.java
vendored
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
/**
|
||||||
|
* Copyright © 2016-2017 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.cache;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public class CacheSpecs {
|
||||||
|
private Integer timeToLiveInMinutes;
|
||||||
|
private Integer maxSize;
|
||||||
|
}
|
||||||
@ -23,6 +23,8 @@ import java.lang.reflect.Method;
|
|||||||
|
|
||||||
public class PreviousDeviceCredentialsIdKeyGenerator implements KeyGenerator {
|
public class PreviousDeviceCredentialsIdKeyGenerator implements KeyGenerator {
|
||||||
|
|
||||||
|
private static final String NOT_VALID_DEVICE = "notValidDeviceCredentialsId";
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object generate(Object o, Method method, Object... objects) {
|
public Object generate(Object o, Method method, Object... objects) {
|
||||||
DeviceCredentialsService deviceCredentialsService = (DeviceCredentialsService) o;
|
DeviceCredentialsService deviceCredentialsService = (DeviceCredentialsService) o;
|
||||||
@ -33,6 +35,6 @@ public class PreviousDeviceCredentialsIdKeyGenerator implements KeyGenerator {
|
|||||||
return oldDeviceCredentials.getCredentialsId();
|
return oldDeviceCredentials.getCredentialsId();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return null;
|
return NOT_VALID_DEVICE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -15,76 +15,57 @@
|
|||||||
*/
|
*/
|
||||||
package org.thingsboard.server.dao.cache;
|
package org.thingsboard.server.dao.cache;
|
||||||
|
|
||||||
import com.hazelcast.config.*;
|
import com.github.benmanes.caffeine.cache.Caffeine;
|
||||||
import com.hazelcast.core.Hazelcast;
|
import com.github.benmanes.caffeine.cache.Ticker;
|
||||||
import com.hazelcast.core.HazelcastInstance;
|
import lombok.Data;
|
||||||
import com.hazelcast.instance.GroupProperty;
|
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||||
import com.hazelcast.spring.cache.HazelcastCacheManager;
|
|
||||||
import com.hazelcast.zookeeper.ZookeeperDiscoveryProperties;
|
|
||||||
import com.hazelcast.zookeeper.ZookeeperDiscoveryStrategyFactory;
|
|
||||||
import org.springframework.beans.factory.annotation.Value;
|
|
||||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
|
||||||
import org.springframework.cache.CacheManager;
|
import org.springframework.cache.CacheManager;
|
||||||
import org.springframework.cache.annotation.EnableCaching;
|
import org.springframework.cache.annotation.EnableCaching;
|
||||||
|
import org.springframework.cache.caffeine.CaffeineCache;
|
||||||
import org.springframework.cache.interceptor.KeyGenerator;
|
import org.springframework.cache.interceptor.KeyGenerator;
|
||||||
|
import org.springframework.cache.support.SimpleCacheManager;
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
import org.thingsboard.server.common.data.CacheConstants;
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
@Configuration
|
@Configuration
|
||||||
|
@ConfigurationProperties(prefix = "caching")
|
||||||
@EnableCaching
|
@EnableCaching
|
||||||
@ConditionalOnProperty(prefix = "cache", value = "enabled", havingValue = "true")
|
@Data
|
||||||
public class ServiceCacheConfiguration {
|
public class ServiceCacheConfiguration {
|
||||||
|
|
||||||
private static final String HAZELCAST_CLUSTER_NAME = "hazelcast";
|
private Map<String, CacheSpecs> specs;
|
||||||
|
|
||||||
@Value("${cache.device_credentials.max_size.size}")
|
|
||||||
private Integer cacheDeviceCredentialsMaxSizeSize;
|
|
||||||
@Value("${cache.device_credentials.max_size.policy}")
|
|
||||||
private String cacheDeviceCredentialsMaxSizePolicy;
|
|
||||||
@Value("${cache.device_credentials.time_to_live}")
|
|
||||||
private Integer cacheDeviceCredentialsTTL;
|
|
||||||
|
|
||||||
@Value("${zk.enabled}")
|
|
||||||
private boolean zkEnabled;
|
|
||||||
@Value("${zk.url}")
|
|
||||||
private String zkUrl;
|
|
||||||
@Value("${zk.zk_dir}")
|
|
||||||
private String zkDir;
|
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
public HazelcastInstance hazelcastInstance() {
|
public CacheManager cacheManager() {
|
||||||
Config config = new Config();
|
SimpleCacheManager manager = new SimpleCacheManager();
|
||||||
|
if (specs != null) {
|
||||||
if (zkEnabled) {
|
List<CaffeineCache> caches =
|
||||||
addZkConfig(config);
|
specs.entrySet().stream()
|
||||||
|
.map(entry -> buildCache(entry.getKey(),
|
||||||
|
entry.getValue()))
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
manager.setCaches(caches);
|
||||||
|
}
|
||||||
|
return manager;
|
||||||
}
|
}
|
||||||
|
|
||||||
config.addMapConfig(createDeviceCredentialsCacheConfig());
|
private CaffeineCache buildCache(String name, CacheSpecs cacheSpec) {
|
||||||
|
final Caffeine<Object, Object> caffeineBuilder
|
||||||
return Hazelcast.newHazelcastInstance(config);
|
= Caffeine.newBuilder()
|
||||||
|
.expireAfterWrite(cacheSpec.getTimeToLiveInMinutes(), TimeUnit.MINUTES)
|
||||||
|
.maximumSize(cacheSpec.getMaxSize())
|
||||||
|
.ticker(ticker());
|
||||||
|
return new CaffeineCache(name, caffeineBuilder.build());
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addZkConfig(Config config) {
|
@Bean
|
||||||
config.getNetworkConfig().getJoin().getMulticastConfig().setEnabled(false);
|
public Ticker ticker() {
|
||||||
config.setProperty(GroupProperty.DISCOVERY_SPI_ENABLED.getName(), Boolean.TRUE.toString());
|
return Ticker.systemTicker();
|
||||||
DiscoveryStrategyConfig discoveryStrategyConfig = new DiscoveryStrategyConfig(new ZookeeperDiscoveryStrategyFactory());
|
|
||||||
discoveryStrategyConfig.addProperty(ZookeeperDiscoveryProperties.ZOOKEEPER_URL.key(), zkUrl);
|
|
||||||
discoveryStrategyConfig.addProperty(ZookeeperDiscoveryProperties.ZOOKEEPER_PATH.key(), zkDir);
|
|
||||||
discoveryStrategyConfig.addProperty(ZookeeperDiscoveryProperties.GROUP.key(), HAZELCAST_CLUSTER_NAME);
|
|
||||||
config.getNetworkConfig().getJoin().getDiscoveryConfig().addDiscoveryStrategyConfig(discoveryStrategyConfig);
|
|
||||||
}
|
|
||||||
|
|
||||||
private MapConfig createDeviceCredentialsCacheConfig() {
|
|
||||||
MapConfig deviceCredentialsCacheConfig = new MapConfig(CacheConstants.DEVICE_CREDENTIALS_CACHE);
|
|
||||||
deviceCredentialsCacheConfig.setTimeToLiveSeconds(cacheDeviceCredentialsTTL);
|
|
||||||
deviceCredentialsCacheConfig.setEvictionPolicy(EvictionPolicy.LRU);
|
|
||||||
deviceCredentialsCacheConfig.setMaxSizeConfig(
|
|
||||||
new MaxSizeConfig(
|
|
||||||
cacheDeviceCredentialsMaxSizeSize,
|
|
||||||
MaxSizeConfig.MaxSizePolicy.valueOf(cacheDeviceCredentialsMaxSizePolicy))
|
|
||||||
);
|
|
||||||
return deviceCredentialsCacheConfig;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
@ -92,8 +73,4 @@ public class ServiceCacheConfiguration {
|
|||||||
return new PreviousDeviceCredentialsIdKeyGenerator();
|
return new PreviousDeviceCredentialsIdKeyGenerator();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Bean
|
|
||||||
public CacheManager cacheManager() {
|
|
||||||
return new HazelcastCacheManager(hazelcastInstance());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -34,7 +34,7 @@ public interface DeviceService {
|
|||||||
|
|
||||||
ListenableFuture<Device> findDeviceByIdAsync(DeviceId deviceId);
|
ListenableFuture<Device> findDeviceByIdAsync(DeviceId deviceId);
|
||||||
|
|
||||||
Optional<Device> findDeviceByTenantIdAndName(TenantId tenantId, String name);
|
Device findDeviceByTenantIdAndName(TenantId tenantId, String name);
|
||||||
|
|
||||||
Device saveDevice(Device device);
|
Device saveDevice(Device device);
|
||||||
|
|
||||||
|
|||||||
@ -22,6 +22,10 @@ import com.google.common.util.concurrent.ListenableFuture;
|
|||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.apache.commons.lang3.RandomStringUtils;
|
import org.apache.commons.lang3.RandomStringUtils;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.cache.Cache;
|
||||||
|
import org.springframework.cache.CacheManager;
|
||||||
|
import org.springframework.cache.annotation.CacheEvict;
|
||||||
|
import org.springframework.cache.annotation.Cacheable;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import org.springframework.util.StringUtils;
|
import org.springframework.util.StringUtils;
|
||||||
import org.thingsboard.server.common.data.*;
|
import org.thingsboard.server.common.data.*;
|
||||||
@ -33,12 +37,12 @@ import org.thingsboard.server.common.data.id.TenantId;
|
|||||||
import org.thingsboard.server.common.data.page.TextPageData;
|
import org.thingsboard.server.common.data.page.TextPageData;
|
||||||
import org.thingsboard.server.common.data.page.TextPageLink;
|
import org.thingsboard.server.common.data.page.TextPageLink;
|
||||||
import org.thingsboard.server.common.data.relation.EntityRelation;
|
import org.thingsboard.server.common.data.relation.EntityRelation;
|
||||||
|
import org.thingsboard.server.common.data.relation.EntitySearchDirection;
|
||||||
import org.thingsboard.server.common.data.security.DeviceCredentials;
|
import org.thingsboard.server.common.data.security.DeviceCredentials;
|
||||||
import org.thingsboard.server.common.data.security.DeviceCredentialsType;
|
import org.thingsboard.server.common.data.security.DeviceCredentialsType;
|
||||||
import org.thingsboard.server.dao.customer.CustomerDao;
|
import org.thingsboard.server.dao.customer.CustomerDao;
|
||||||
import org.thingsboard.server.dao.entity.AbstractEntityService;
|
import org.thingsboard.server.dao.entity.AbstractEntityService;
|
||||||
import org.thingsboard.server.dao.exception.DataValidationException;
|
import org.thingsboard.server.dao.exception.DataValidationException;
|
||||||
import org.thingsboard.server.common.data.relation.EntitySearchDirection;
|
|
||||||
import org.thingsboard.server.dao.service.DataValidator;
|
import org.thingsboard.server.dao.service.DataValidator;
|
||||||
import org.thingsboard.server.dao.service.PaginatedRemover;
|
import org.thingsboard.server.dao.service.PaginatedRemover;
|
||||||
import org.thingsboard.server.dao.tenant.TenantDao;
|
import org.thingsboard.server.dao.tenant.TenantDao;
|
||||||
@ -47,6 +51,7 @@ import javax.annotation.Nullable;
|
|||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
import static org.thingsboard.server.common.data.CacheConstants.DEVICE_CACHE;
|
||||||
import static org.thingsboard.server.dao.DaoUtil.toUUIDs;
|
import static org.thingsboard.server.dao.DaoUtil.toUUIDs;
|
||||||
import static org.thingsboard.server.dao.model.ModelConstants.NULL_UUID;
|
import static org.thingsboard.server.dao.model.ModelConstants.NULL_UUID;
|
||||||
import static org.thingsboard.server.dao.service.Validator.*;
|
import static org.thingsboard.server.dao.service.Validator.*;
|
||||||
@ -71,6 +76,9 @@ public class DeviceServiceImpl extends AbstractEntityService implements DeviceSe
|
|||||||
@Autowired
|
@Autowired
|
||||||
private DeviceCredentialsService deviceCredentialsService;
|
private DeviceCredentialsService deviceCredentialsService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private CacheManager cacheManager;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Device findDeviceById(DeviceId deviceId) {
|
public Device findDeviceById(DeviceId deviceId) {
|
||||||
log.trace("Executing findDeviceById [{}]", deviceId);
|
log.trace("Executing findDeviceById [{}]", deviceId);
|
||||||
@ -85,18 +93,16 @@ public class DeviceServiceImpl extends AbstractEntityService implements DeviceSe
|
|||||||
return deviceDao.findByIdAsync(deviceId.getId());
|
return deviceDao.findByIdAsync(deviceId.getId());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Cacheable(cacheNames = DEVICE_CACHE, key = "{#tenantId, #name}")
|
||||||
@Override
|
@Override
|
||||||
public Optional<Device> findDeviceByTenantIdAndName(TenantId tenantId, String name) {
|
public Device findDeviceByTenantIdAndName(TenantId tenantId, String name) {
|
||||||
log.trace("Executing findDeviceByTenantIdAndName [{}][{}]", tenantId, name);
|
log.trace("Executing findDeviceByTenantIdAndName [{}][{}]", tenantId, name);
|
||||||
validateId(tenantId, INCORRECT_TENANT_ID + tenantId);
|
validateId(tenantId, INCORRECT_TENANT_ID + tenantId);
|
||||||
Optional<Device> deviceOpt = deviceDao.findDeviceByTenantIdAndName(tenantId.getId(), name);
|
Optional<Device> deviceOpt = deviceDao.findDeviceByTenantIdAndName(tenantId.getId(), name);
|
||||||
if (deviceOpt.isPresent()) {
|
return deviceOpt.orElse(null);
|
||||||
return Optional.of(deviceOpt.get());
|
|
||||||
} else {
|
|
||||||
return Optional.empty();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@CacheEvict(cacheNames = DEVICE_CACHE, key = "{#device.tenantId, #device.name}")
|
||||||
@Override
|
@Override
|
||||||
public Device saveDevice(Device device) {
|
public Device saveDevice(Device device) {
|
||||||
log.trace("Executing saveDevice [{}]", device);
|
log.trace("Executing saveDevice [{}]", device);
|
||||||
@ -129,12 +135,18 @@ public class DeviceServiceImpl extends AbstractEntityService implements DeviceSe
|
|||||||
@Override
|
@Override
|
||||||
public void deleteDevice(DeviceId deviceId) {
|
public void deleteDevice(DeviceId deviceId) {
|
||||||
log.trace("Executing deleteDevice [{}]", deviceId);
|
log.trace("Executing deleteDevice [{}]", deviceId);
|
||||||
|
Cache cache = cacheManager.getCache(DEVICE_CACHE);
|
||||||
validateId(deviceId, INCORRECT_DEVICE_ID + deviceId);
|
validateId(deviceId, INCORRECT_DEVICE_ID + deviceId);
|
||||||
DeviceCredentials deviceCredentials = deviceCredentialsService.findDeviceCredentialsByDeviceId(deviceId);
|
DeviceCredentials deviceCredentials = deviceCredentialsService.findDeviceCredentialsByDeviceId(deviceId);
|
||||||
if (deviceCredentials != null) {
|
if (deviceCredentials != null) {
|
||||||
deviceCredentialsService.deleteDeviceCredentials(deviceCredentials);
|
deviceCredentialsService.deleteDeviceCredentials(deviceCredentials);
|
||||||
}
|
}
|
||||||
deleteEntityRelations(deviceId);
|
deleteEntityRelations(deviceId);
|
||||||
|
Device device = deviceDao.findById(deviceId.getId());
|
||||||
|
List<Object> list = new ArrayList<>();
|
||||||
|
list.add(device.getTenantId());
|
||||||
|
list.add(device.getName());
|
||||||
|
cache.evict(list);
|
||||||
deviceDao.removeById(deviceId.getId());
|
deviceDao.removeById(deviceId.getId());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -21,6 +21,11 @@ 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;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.cache.Cache;
|
||||||
|
import org.springframework.cache.CacheManager;
|
||||||
|
import org.springframework.cache.annotation.CacheEvict;
|
||||||
|
import org.springframework.cache.annotation.Cacheable;
|
||||||
|
import org.springframework.cache.annotation.Caching;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import org.springframework.util.StringUtils;
|
import org.springframework.util.StringUtils;
|
||||||
import org.thingsboard.server.common.data.id.EntityId;
|
import org.thingsboard.server.common.data.id.EntityId;
|
||||||
@ -34,6 +39,8 @@ import java.util.concurrent.ConcurrentHashMap;
|
|||||||
import java.util.concurrent.ExecutionException;
|
import java.util.concurrent.ExecutionException;
|
||||||
import java.util.function.BiConsumer;
|
import java.util.function.BiConsumer;
|
||||||
|
|
||||||
|
import static org.thingsboard.server.common.data.CacheConstants.RELATIONS_CACHE;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Created by ashvayka on 28.04.17.
|
* Created by ashvayka on 28.04.17.
|
||||||
*/
|
*/
|
||||||
@ -47,6 +54,9 @@ public class BaseRelationService implements RelationService {
|
|||||||
@Autowired
|
@Autowired
|
||||||
private EntityService entityService;
|
private EntityService entityService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private CacheManager cacheManager;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ListenableFuture<Boolean> checkRelation(EntityId from, EntityId to, String relationType, RelationTypeGroup typeGroup) {
|
public ListenableFuture<Boolean> checkRelation(EntityId from, EntityId to, String relationType, RelationTypeGroup typeGroup) {
|
||||||
log.trace("Executing checkRelation [{}][{}][{}][{}]", from, to, relationType, typeGroup);
|
log.trace("Executing checkRelation [{}][{}][{}][{}]", from, to, relationType, typeGroup);
|
||||||
@ -54,6 +64,7 @@ public class BaseRelationService implements RelationService {
|
|||||||
return relationDao.checkRelation(from, to, relationType, typeGroup);
|
return relationDao.checkRelation(from, to, relationType, typeGroup);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Cacheable(cacheNames = RELATIONS_CACHE, key = "{#from, #to, #relationType}")
|
||||||
@Override
|
@Override
|
||||||
public ListenableFuture<EntityRelation> getRelation(EntityId from, EntityId to, String relationType, RelationTypeGroup typeGroup) {
|
public ListenableFuture<EntityRelation> getRelation(EntityId from, EntityId to, String relationType, RelationTypeGroup typeGroup) {
|
||||||
log.trace("Executing EntityRelation [{}][{}][{}][{}]", from, to, relationType, typeGroup);
|
log.trace("Executing EntityRelation [{}][{}][{}][{}]", from, to, relationType, typeGroup);
|
||||||
@ -61,6 +72,12 @@ public class BaseRelationService implements RelationService {
|
|||||||
return relationDao.getRelation(from, to, relationType, typeGroup);
|
return relationDao.getRelation(from, to, relationType, typeGroup);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Caching(evict = {
|
||||||
|
@CacheEvict(cacheNames = RELATIONS_CACHE, key = "#relation.from"),
|
||||||
|
@CacheEvict(cacheNames = RELATIONS_CACHE, key = "{#relation.from, #relation.type}"),
|
||||||
|
@CacheEvict(cacheNames = RELATIONS_CACHE, key = "#relation.to"),
|
||||||
|
@CacheEvict(cacheNames = RELATIONS_CACHE, key = "{#relation.to, #relation.type}")
|
||||||
|
})
|
||||||
@Override
|
@Override
|
||||||
public boolean saveRelation(EntityRelation relation) {
|
public boolean saveRelation(EntityRelation relation) {
|
||||||
log.trace("Executing saveRelation [{}]", relation);
|
log.trace("Executing saveRelation [{}]", relation);
|
||||||
@ -68,6 +85,12 @@ public class BaseRelationService implements RelationService {
|
|||||||
return relationDao.saveRelation(relation);
|
return relationDao.saveRelation(relation);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Caching(evict = {
|
||||||
|
@CacheEvict(cacheNames = RELATIONS_CACHE, key = "#relation.from"),
|
||||||
|
@CacheEvict(cacheNames = RELATIONS_CACHE, key = "{#relation.from, #relation.type}"),
|
||||||
|
@CacheEvict(cacheNames = RELATIONS_CACHE, key = "#relation.to"),
|
||||||
|
@CacheEvict(cacheNames = RELATIONS_CACHE, key = "{#relation.to, #relation.type}")
|
||||||
|
})
|
||||||
@Override
|
@Override
|
||||||
public ListenableFuture<Boolean> saveRelationAsync(EntityRelation relation) {
|
public ListenableFuture<Boolean> saveRelationAsync(EntityRelation relation) {
|
||||||
log.trace("Executing saveRelationAsync [{}]", relation);
|
log.trace("Executing saveRelationAsync [{}]", relation);
|
||||||
@ -75,6 +98,13 @@ public class BaseRelationService implements RelationService {
|
|||||||
return relationDao.saveRelationAsync(relation);
|
return relationDao.saveRelationAsync(relation);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Caching(evict = {
|
||||||
|
@CacheEvict(cacheNames = RELATIONS_CACHE, key = "#relation.from"),
|
||||||
|
@CacheEvict(cacheNames = RELATIONS_CACHE, key = "{#relation.from, #relation.type}"),
|
||||||
|
@CacheEvict(cacheNames = RELATIONS_CACHE, key = "#relation.to"),
|
||||||
|
@CacheEvict(cacheNames = RELATIONS_CACHE, key = "{#relation.to, #relation.type}"),
|
||||||
|
@CacheEvict(cacheNames = RELATIONS_CACHE, key = "{#relation.from, #relation.to, #relation.type}")
|
||||||
|
})
|
||||||
@Override
|
@Override
|
||||||
public boolean deleteRelation(EntityRelation relation) {
|
public boolean deleteRelation(EntityRelation relation) {
|
||||||
log.trace("Executing deleteRelation [{}]", relation);
|
log.trace("Executing deleteRelation [{}]", relation);
|
||||||
@ -82,6 +112,13 @@ public class BaseRelationService implements RelationService {
|
|||||||
return relationDao.deleteRelation(relation);
|
return relationDao.deleteRelation(relation);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Caching(evict = {
|
||||||
|
@CacheEvict(cacheNames = RELATIONS_CACHE, key = "#relation.from"),
|
||||||
|
@CacheEvict(cacheNames = RELATIONS_CACHE, key = "{#relation.from, #relation.type}"),
|
||||||
|
@CacheEvict(cacheNames = RELATIONS_CACHE, key = "#relation.to"),
|
||||||
|
@CacheEvict(cacheNames = RELATIONS_CACHE, key = "{#relation.to, #relation.type}"),
|
||||||
|
@CacheEvict(cacheNames = RELATIONS_CACHE, key = "{#relation.from, #relation.to, #relation.type}")
|
||||||
|
})
|
||||||
@Override
|
@Override
|
||||||
public ListenableFuture<Boolean> deleteRelationAsync(EntityRelation relation) {
|
public ListenableFuture<Boolean> deleteRelationAsync(EntityRelation relation) {
|
||||||
log.trace("Executing deleteRelationAsync [{}]", relation);
|
log.trace("Executing deleteRelationAsync [{}]", relation);
|
||||||
@ -89,6 +126,13 @@ public class BaseRelationService implements RelationService {
|
|||||||
return relationDao.deleteRelationAsync(relation);
|
return relationDao.deleteRelationAsync(relation);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Caching(evict = {
|
||||||
|
@CacheEvict(cacheNames = RELATIONS_CACHE, key = "#from"),
|
||||||
|
@CacheEvict(cacheNames = RELATIONS_CACHE, key = "{#from, #relationType}"),
|
||||||
|
@CacheEvict(cacheNames = RELATIONS_CACHE, key = "#to"),
|
||||||
|
@CacheEvict(cacheNames = RELATIONS_CACHE, key = "{#to, #relationType}"),
|
||||||
|
@CacheEvict(cacheNames = RELATIONS_CACHE, key = "{#from, #to, #relationType}")
|
||||||
|
})
|
||||||
@Override
|
@Override
|
||||||
public boolean deleteRelation(EntityId from, EntityId to, String relationType, RelationTypeGroup typeGroup) {
|
public boolean deleteRelation(EntityId from, EntityId to, String relationType, RelationTypeGroup typeGroup) {
|
||||||
log.trace("Executing deleteRelation [{}][{}][{}][{}]", from, to, relationType, typeGroup);
|
log.trace("Executing deleteRelation [{}][{}][{}][{}]", from, to, relationType, typeGroup);
|
||||||
@ -96,6 +140,13 @@ public class BaseRelationService implements RelationService {
|
|||||||
return relationDao.deleteRelation(from, to, relationType, typeGroup);
|
return relationDao.deleteRelation(from, to, relationType, typeGroup);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Caching(evict = {
|
||||||
|
@CacheEvict(cacheNames = RELATIONS_CACHE, key = "#from"),
|
||||||
|
@CacheEvict(cacheNames = RELATIONS_CACHE, key = "{#from, #relationType}"),
|
||||||
|
@CacheEvict(cacheNames = RELATIONS_CACHE, key = "#to"),
|
||||||
|
@CacheEvict(cacheNames = RELATIONS_CACHE, key = "{#to, #relationType}"),
|
||||||
|
@CacheEvict(cacheNames = RELATIONS_CACHE, key = "{#from, #to, #relationType}")
|
||||||
|
})
|
||||||
@Override
|
@Override
|
||||||
public ListenableFuture<Boolean> deleteRelationAsync(EntityId from, EntityId to, String relationType, RelationTypeGroup typeGroup) {
|
public ListenableFuture<Boolean> deleteRelationAsync(EntityId from, EntityId to, String relationType, RelationTypeGroup typeGroup) {
|
||||||
log.trace("Executing deleteRelationAsync [{}][{}][{}][{}]", from, to, relationType, typeGroup);
|
log.trace("Executing deleteRelationAsync [{}][{}][{}][{}]", from, to, relationType, typeGroup);
|
||||||
@ -105,23 +156,17 @@ public class BaseRelationService implements RelationService {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean deleteEntityRelations(EntityId entity) {
|
public boolean deleteEntityRelations(EntityId entity) {
|
||||||
|
Cache cache = cacheManager.getCache(RELATIONS_CACHE);
|
||||||
log.trace("Executing deleteEntityRelations [{}]", entity);
|
log.trace("Executing deleteEntityRelations [{}]", entity);
|
||||||
validate(entity);
|
validate(entity);
|
||||||
List<ListenableFuture<List<EntityRelation>>> inboundRelationsList = new ArrayList<>();
|
List<ListenableFuture<List<EntityRelation>>> inboundRelationsListTo = new ArrayList<>();
|
||||||
for (RelationTypeGroup typeGroup : RelationTypeGroup.values()) {
|
for (RelationTypeGroup typeGroup : RelationTypeGroup.values()) {
|
||||||
inboundRelationsList.add(relationDao.findAllByTo(entity, typeGroup));
|
inboundRelationsListTo.add(relationDao.findAllByTo(entity, typeGroup));
|
||||||
}
|
}
|
||||||
ListenableFuture<List<List<EntityRelation>>> inboundRelations = Futures.allAsList(inboundRelationsList);
|
ListenableFuture<List<List<EntityRelation>>> inboundRelationsTo = Futures.allAsList(inboundRelationsListTo);
|
||||||
ListenableFuture<List<Boolean>> inboundDeletions = Futures.transform(inboundRelations, new Function<List<List<EntityRelation>>, List<Boolean>>() {
|
ListenableFuture<List<Boolean>> inboundDeletions = Futures.transform(inboundRelationsTo, (List<List<EntityRelation>> relations) ->
|
||||||
@Override
|
getBooleans(relations, cache, true));
|
||||||
public List<Boolean> apply(List<List<EntityRelation>> relations) {
|
|
||||||
List<Boolean> results = new ArrayList<>();
|
|
||||||
for (List<EntityRelation> relationList : relations) {
|
|
||||||
relationList.stream().forEach(relation -> results.add(relationDao.deleteRelation(relation)));
|
|
||||||
}
|
|
||||||
return results;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
ListenableFuture<Boolean> inboundFuture = Futures.transform(inboundDeletions, getListToBooleanFunction());
|
ListenableFuture<Boolean> inboundFuture = Futures.transform(inboundDeletions, getListToBooleanFunction());
|
||||||
boolean inboundDeleteResult = false;
|
boolean inboundDeleteResult = false;
|
||||||
try {
|
try {
|
||||||
@ -129,12 +174,39 @@ public class BaseRelationService implements RelationService {
|
|||||||
} catch (InterruptedException | ExecutionException e) {
|
} catch (InterruptedException | ExecutionException e) {
|
||||||
log.error("Error deleting entity inbound relations", e);
|
log.error("Error deleting entity inbound relations", e);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
List<ListenableFuture<List<EntityRelation>>> inboundRelationsListFrom = new ArrayList<>();
|
||||||
|
for (RelationTypeGroup typeGroup : RelationTypeGroup.values()) {
|
||||||
|
inboundRelationsListFrom.add(relationDao.findAllByFrom(entity, typeGroup));
|
||||||
|
}
|
||||||
|
ListenableFuture<List<List<EntityRelation>>> inboundRelationsFrom = Futures.allAsList(inboundRelationsListFrom);
|
||||||
|
Futures.transform(inboundRelationsFrom, (Function<List<List<EntityRelation>>, List<Boolean>>) relations ->
|
||||||
|
getBooleans(relations, cache, false));
|
||||||
|
|
||||||
boolean outboundDeleteResult = relationDao.deleteOutboundRelations(entity);
|
boolean outboundDeleteResult = relationDao.deleteOutboundRelations(entity);
|
||||||
return inboundDeleteResult && outboundDeleteResult;
|
return inboundDeleteResult && outboundDeleteResult;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private List<Boolean> getBooleans(List<List<EntityRelation>> relations, Cache cache, boolean isRemove) {
|
||||||
|
List<Boolean> results = new ArrayList<>();
|
||||||
|
for (List<EntityRelation> relationList : relations) {
|
||||||
|
relationList.stream().forEach(relation -> {
|
||||||
|
checkFromDeleteSync(cache, results, relation, isRemove);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void checkFromDeleteSync(Cache cache, List<Boolean> results, EntityRelation relation, boolean isRemove) {
|
||||||
|
if (isRemove) {
|
||||||
|
results.add(relationDao.deleteRelation(relation));
|
||||||
|
}
|
||||||
|
cacheEviction(relation, relation.getTo(), cache);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ListenableFuture<Boolean> deleteEntityRelationsAsync(EntityId entity) {
|
public ListenableFuture<Boolean> deleteEntityRelationsAsync(EntityId entity) {
|
||||||
|
Cache cache = cacheManager.getCache(RELATIONS_CACHE);
|
||||||
log.trace("Executing deleteEntityRelationsAsync [{}]", entity);
|
log.trace("Executing deleteEntityRelationsAsync [{}]", entity);
|
||||||
validate(entity);
|
validate(entity);
|
||||||
List<ListenableFuture<List<EntityRelation>>> inboundRelationsList = new ArrayList<>();
|
List<ListenableFuture<List<EntityRelation>>> inboundRelationsList = new ArrayList<>();
|
||||||
@ -142,24 +214,61 @@ public class BaseRelationService implements RelationService {
|
|||||||
inboundRelationsList.add(relationDao.findAllByTo(entity, typeGroup));
|
inboundRelationsList.add(relationDao.findAllByTo(entity, typeGroup));
|
||||||
}
|
}
|
||||||
ListenableFuture<List<List<EntityRelation>>> inboundRelations = Futures.allAsList(inboundRelationsList);
|
ListenableFuture<List<List<EntityRelation>>> inboundRelations = Futures.allAsList(inboundRelationsList);
|
||||||
ListenableFuture<List<Boolean>> inboundDeletions = Futures.transform(inboundRelations, new AsyncFunction<List<List<EntityRelation>>, List<Boolean>>() {
|
ListenableFuture<List<Boolean>> inboundDeletions = Futures.transform(inboundRelations,
|
||||||
@Override
|
(AsyncFunction<List<List<EntityRelation>>, List<Boolean>>) relations -> {
|
||||||
public ListenableFuture<List<Boolean>> apply(List<List<EntityRelation>> relations) throws Exception {
|
List<ListenableFuture<Boolean>> results = getListenableFutures(relations, cache, true);
|
||||||
List<ListenableFuture<Boolean>> results = new ArrayList<>();
|
|
||||||
for (List<EntityRelation> relationList : relations) {
|
|
||||||
relationList.stream().forEach(relation -> results.add(relationDao.deleteRelationAsync(relation)));
|
|
||||||
}
|
|
||||||
return Futures.allAsList(results);
|
return Futures.allAsList(results);
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
ListenableFuture<Boolean> inboundFuture = Futures.transform(inboundDeletions, getListToBooleanFunction());
|
ListenableFuture<Boolean> inboundFuture = Futures.transform(inboundDeletions, getListToBooleanFunction());
|
||||||
|
|
||||||
ListenableFuture<Boolean> outboundFuture = relationDao.deleteOutboundRelationsAsync(entity);
|
List<ListenableFuture<List<EntityRelation>>> inboundRelationsList1 = new ArrayList<>();
|
||||||
|
for (RelationTypeGroup typeGroup : RelationTypeGroup.values()) {
|
||||||
|
inboundRelationsList1.add(relationDao.findAllByTo(entity, typeGroup));
|
||||||
|
}
|
||||||
|
ListenableFuture<List<List<EntityRelation>>> inboundRelations1 = Futures.allAsList(inboundRelationsList1);
|
||||||
|
Futures.transform(inboundRelations1, (AsyncFunction<List<List<EntityRelation>>, List<Boolean>>) relations -> {
|
||||||
|
List<ListenableFuture<Boolean>> results = getListenableFutures(relations, cache, false);
|
||||||
|
return Futures.allAsList(results);
|
||||||
|
});
|
||||||
|
|
||||||
|
ListenableFuture<Boolean> outboundFuture = relationDao.deleteOutboundRelationsAsync(entity);
|
||||||
return Futures.transform(Futures.allAsList(Arrays.asList(inboundFuture, outboundFuture)), getListToBooleanFunction());
|
return Futures.transform(Futures.allAsList(Arrays.asList(inboundFuture, outboundFuture)), getListToBooleanFunction());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private List<ListenableFuture<Boolean>> getListenableFutures(List<List<EntityRelation>> relations, Cache cache, boolean isRemove) {
|
||||||
|
List<ListenableFuture<Boolean>> results = new ArrayList<>();
|
||||||
|
for (List<EntityRelation> relationList : relations) {
|
||||||
|
relationList.stream().forEach(relation -> {
|
||||||
|
checkFromDeleteAsync(cache, results, relation, isRemove);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void checkFromDeleteAsync(Cache cache, List<ListenableFuture<Boolean>> results, EntityRelation relation, boolean isRemove) {
|
||||||
|
if (isRemove) {
|
||||||
|
results.add(relationDao.deleteRelationAsync(relation));
|
||||||
|
}
|
||||||
|
cacheEviction(relation, relation.getTo(), cache);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void cacheEviction(EntityRelation relation, EntityId entityId, Cache cache) {
|
||||||
|
cache.evict(entityId);
|
||||||
|
|
||||||
|
List<Object> toAndType = new ArrayList<>();
|
||||||
|
toAndType.add(entityId);
|
||||||
|
toAndType.add(relation.getType());
|
||||||
|
cache.evict(toAndType);
|
||||||
|
|
||||||
|
List<Object> fromToAndType = new ArrayList<>();
|
||||||
|
fromToAndType.add(relation.getFrom());
|
||||||
|
fromToAndType.add(relation.getTo());
|
||||||
|
fromToAndType.add(relation.getType());
|
||||||
|
cache.evict(fromToAndType);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Cacheable(cacheNames = RELATIONS_CACHE, key = "#from")
|
||||||
@Override
|
@Override
|
||||||
public ListenableFuture<List<EntityRelation>> findByFrom(EntityId from, RelationTypeGroup typeGroup) {
|
public ListenableFuture<List<EntityRelation>> findByFrom(EntityId from, RelationTypeGroup typeGroup) {
|
||||||
log.trace("Executing findByFrom [{}][{}]", from, typeGroup);
|
log.trace("Executing findByFrom [{}][{}]", from, typeGroup);
|
||||||
@ -187,6 +296,7 @@ public class BaseRelationService implements RelationService {
|
|||||||
return relationsInfo;
|
return relationsInfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Cacheable(cacheNames = RELATIONS_CACHE, key = "{#from, #relationType}")
|
||||||
@Override
|
@Override
|
||||||
public ListenableFuture<List<EntityRelation>> findByFromAndType(EntityId from, String relationType, RelationTypeGroup typeGroup) {
|
public ListenableFuture<List<EntityRelation>> findByFromAndType(EntityId from, String relationType, RelationTypeGroup typeGroup) {
|
||||||
log.trace("Executing findByFromAndType [{}][{}][{}]", from, relationType, typeGroup);
|
log.trace("Executing findByFromAndType [{}][{}][{}]", from, relationType, typeGroup);
|
||||||
@ -196,6 +306,7 @@ public class BaseRelationService implements RelationService {
|
|||||||
return relationDao.findAllByFromAndType(from, relationType, typeGroup);
|
return relationDao.findAllByFromAndType(from, relationType, typeGroup);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Cacheable(cacheNames = RELATIONS_CACHE, key = "#to")
|
||||||
@Override
|
@Override
|
||||||
public ListenableFuture<List<EntityRelation>> findByTo(EntityId to, RelationTypeGroup typeGroup) {
|
public ListenableFuture<List<EntityRelation>> findByTo(EntityId to, RelationTypeGroup typeGroup) {
|
||||||
log.trace("Executing findByTo [{}][{}]", to, typeGroup);
|
log.trace("Executing findByTo [{}][{}]", to, typeGroup);
|
||||||
@ -236,6 +347,7 @@ public class BaseRelationService implements RelationService {
|
|||||||
return entityRelationInfo;
|
return entityRelationInfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Cacheable(cacheNames = RELATIONS_CACHE, key = "{#to, #relationType}")
|
||||||
@Override
|
@Override
|
||||||
public ListenableFuture<List<EntityRelation>> findByToAndType(EntityId to, String relationType, RelationTypeGroup typeGroup) {
|
public ListenableFuture<List<EntityRelation>> findByToAndType(EntityId to, String relationType, RelationTypeGroup typeGroup) {
|
||||||
log.trace("Executing findByToAndType [{}][{}][{}]", to, relationType, typeGroup);
|
log.trace("Executing findByToAndType [{}][{}][{}]", to, relationType, typeGroup);
|
||||||
@ -417,5 +529,4 @@ public class BaseRelationService implements RelationService {
|
|||||||
}
|
}
|
||||||
return relations;
|
return relations;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -15,16 +15,14 @@
|
|||||||
*/
|
*/
|
||||||
package org.thingsboard.server.dao.service;
|
package org.thingsboard.server.dao.service;
|
||||||
|
|
||||||
import com.hazelcast.core.HazelcastInstance;
|
|
||||||
import org.apache.commons.lang3.RandomStringUtils;
|
import org.apache.commons.lang3.RandomStringUtils;
|
||||||
import org.junit.After;
|
import org.junit.After;
|
||||||
import org.junit.Assert;
|
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.springframework.aop.framework.Advised;
|
import org.springframework.aop.framework.Advised;
|
||||||
import org.springframework.aop.support.AopUtils;
|
import org.springframework.aop.support.AopUtils;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.test.context.TestPropertySource;
|
import org.springframework.cache.CacheManager;
|
||||||
import org.springframework.test.util.ReflectionTestUtils;
|
import org.springframework.test.util.ReflectionTestUtils;
|
||||||
import org.thingsboard.server.common.data.CacheConstants;
|
import org.thingsboard.server.common.data.CacheConstants;
|
||||||
import org.thingsboard.server.common.data.Device;
|
import org.thingsboard.server.common.data.Device;
|
||||||
@ -40,7 +38,6 @@ import java.util.UUID;
|
|||||||
|
|
||||||
import static org.mockito.Mockito.*;
|
import static org.mockito.Mockito.*;
|
||||||
|
|
||||||
@TestPropertySource(properties = {"cache.enabled = true"})
|
|
||||||
public abstract class BaseDeviceCredentialsCacheTest extends AbstractServiceTest {
|
public abstract class BaseDeviceCredentialsCacheTest extends AbstractServiceTest {
|
||||||
|
|
||||||
private static final String CREDENTIALS_ID_1 = RandomStringUtils.randomAlphanumeric(20);
|
private static final String CREDENTIALS_ID_1 = RandomStringUtils.randomAlphanumeric(20);
|
||||||
@ -53,7 +50,7 @@ public abstract class BaseDeviceCredentialsCacheTest extends AbstractServiceTest
|
|||||||
private DeviceService deviceService;
|
private DeviceService deviceService;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private HazelcastInstance hazelcastInstance;
|
private CacheManager cacheManager;
|
||||||
|
|
||||||
private UUID deviceId = UUID.randomUUID();
|
private UUID deviceId = UUID.randomUUID();
|
||||||
|
|
||||||
@ -67,7 +64,7 @@ public abstract class BaseDeviceCredentialsCacheTest extends AbstractServiceTest
|
|||||||
|
|
||||||
@After
|
@After
|
||||||
public void cleanup() {
|
public void cleanup() {
|
||||||
hazelcastInstance.getMap(CacheConstants.DEVICE_CREDENTIALS_CACHE).evictAll();
|
cacheManager.getCache(CacheConstants.DEVICE_CREDENTIALS_CACHE).clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -77,7 +74,6 @@ public abstract class BaseDeviceCredentialsCacheTest extends AbstractServiceTest
|
|||||||
deviceCredentialsService.findDeviceCredentialsByCredentialsId(CREDENTIALS_ID_1);
|
deviceCredentialsService.findDeviceCredentialsByCredentialsId(CREDENTIALS_ID_1);
|
||||||
deviceCredentialsService.findDeviceCredentialsByCredentialsId(CREDENTIALS_ID_1);
|
deviceCredentialsService.findDeviceCredentialsByCredentialsId(CREDENTIALS_ID_1);
|
||||||
|
|
||||||
Assert.assertEquals(1, hazelcastInstance.getMap(CacheConstants.DEVICE_CREDENTIALS_CACHE).size());
|
|
||||||
verify(deviceCredentialsDao, times(1)).findByCredentialsId(CREDENTIALS_ID_1);
|
verify(deviceCredentialsDao, times(1)).findByCredentialsId(CREDENTIALS_ID_1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -88,17 +84,13 @@ public abstract class BaseDeviceCredentialsCacheTest extends AbstractServiceTest
|
|||||||
deviceCredentialsService.findDeviceCredentialsByCredentialsId(CREDENTIALS_ID_1);
|
deviceCredentialsService.findDeviceCredentialsByCredentialsId(CREDENTIALS_ID_1);
|
||||||
deviceCredentialsService.findDeviceCredentialsByCredentialsId(CREDENTIALS_ID_1);
|
deviceCredentialsService.findDeviceCredentialsByCredentialsId(CREDENTIALS_ID_1);
|
||||||
|
|
||||||
Assert.assertEquals(1, hazelcastInstance.getMap(CacheConstants.DEVICE_CREDENTIALS_CACHE).size());
|
|
||||||
verify(deviceCredentialsDao, times(1)).findByCredentialsId(CREDENTIALS_ID_1);
|
verify(deviceCredentialsDao, times(1)).findByCredentialsId(CREDENTIALS_ID_1);
|
||||||
|
|
||||||
deviceCredentialsService.deleteDeviceCredentials(createDummyDeviceCredentials(CREDENTIALS_ID_1, deviceId));
|
deviceCredentialsService.deleteDeviceCredentials(createDummyDeviceCredentials(CREDENTIALS_ID_1, deviceId));
|
||||||
|
|
||||||
Assert.assertEquals(0, hazelcastInstance.getMap(CacheConstants.DEVICE_CREDENTIALS_CACHE).size());
|
|
||||||
|
|
||||||
deviceCredentialsService.findDeviceCredentialsByCredentialsId(CREDENTIALS_ID_1);
|
deviceCredentialsService.findDeviceCredentialsByCredentialsId(CREDENTIALS_ID_1);
|
||||||
deviceCredentialsService.findDeviceCredentialsByCredentialsId(CREDENTIALS_ID_1);
|
deviceCredentialsService.findDeviceCredentialsByCredentialsId(CREDENTIALS_ID_1);
|
||||||
|
|
||||||
Assert.assertEquals(1, hazelcastInstance.getMap(CacheConstants.DEVICE_CREDENTIALS_CACHE).size());
|
|
||||||
verify(deviceCredentialsDao, times(2)).findByCredentialsId(CREDENTIALS_ID_1);
|
verify(deviceCredentialsDao, times(2)).findByCredentialsId(CREDENTIALS_ID_1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -109,7 +101,6 @@ public abstract class BaseDeviceCredentialsCacheTest extends AbstractServiceTest
|
|||||||
deviceCredentialsService.findDeviceCredentialsByCredentialsId(CREDENTIALS_ID_1);
|
deviceCredentialsService.findDeviceCredentialsByCredentialsId(CREDENTIALS_ID_1);
|
||||||
deviceCredentialsService.findDeviceCredentialsByCredentialsId(CREDENTIALS_ID_1);
|
deviceCredentialsService.findDeviceCredentialsByCredentialsId(CREDENTIALS_ID_1);
|
||||||
|
|
||||||
Assert.assertEquals(1, hazelcastInstance.getMap(CacheConstants.DEVICE_CREDENTIALS_CACHE).size());
|
|
||||||
verify(deviceCredentialsDao, times(1)).findByCredentialsId(CREDENTIALS_ID_1);
|
verify(deviceCredentialsDao, times(1)).findByCredentialsId(CREDENTIALS_ID_1);
|
||||||
|
|
||||||
when(deviceCredentialsDao.findByDeviceId(deviceId)).thenReturn(createDummyDeviceCredentialsEntity(CREDENTIALS_ID_1));
|
when(deviceCredentialsDao.findByDeviceId(deviceId)).thenReturn(createDummyDeviceCredentialsEntity(CREDENTIALS_ID_1));
|
||||||
@ -119,13 +110,11 @@ public abstract class BaseDeviceCredentialsCacheTest extends AbstractServiceTest
|
|||||||
when(deviceService.findDeviceById(new DeviceId(deviceId))).thenReturn(new Device());
|
when(deviceService.findDeviceById(new DeviceId(deviceId))).thenReturn(new Device());
|
||||||
|
|
||||||
deviceCredentialsService.updateDeviceCredentials(createDummyDeviceCredentials(deviceCredentialsId, CREDENTIALS_ID_2, deviceId));
|
deviceCredentialsService.updateDeviceCredentials(createDummyDeviceCredentials(deviceCredentialsId, CREDENTIALS_ID_2, deviceId));
|
||||||
Assert.assertEquals(0, hazelcastInstance.getMap(CacheConstants.DEVICE_CREDENTIALS_CACHE).size());
|
|
||||||
|
|
||||||
when(deviceCredentialsDao.findByCredentialsId(CREDENTIALS_ID_1)).thenReturn(null);
|
when(deviceCredentialsDao.findByCredentialsId(CREDENTIALS_ID_1)).thenReturn(null);
|
||||||
|
|
||||||
deviceCredentialsService.findDeviceCredentialsByCredentialsId(CREDENTIALS_ID_1);
|
deviceCredentialsService.findDeviceCredentialsByCredentialsId(CREDENTIALS_ID_1);
|
||||||
deviceCredentialsService.findDeviceCredentialsByCredentialsId(CREDENTIALS_ID_1);
|
deviceCredentialsService.findDeviceCredentialsByCredentialsId(CREDENTIALS_ID_1);
|
||||||
Assert.assertEquals(0, hazelcastInstance.getMap(CacheConstants.DEVICE_CREDENTIALS_CACHE).size());
|
|
||||||
|
|
||||||
verify(deviceCredentialsDao, times(3)).findByCredentialsId(CREDENTIALS_ID_1);
|
verify(deviceCredentialsDao, times(3)).findByCredentialsId(CREDENTIALS_ID_1);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,101 @@
|
|||||||
|
/**
|
||||||
|
* Copyright © 2016-2017 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.service;
|
||||||
|
|
||||||
|
import com.google.common.util.concurrent.Futures;
|
||||||
|
import org.junit.After;
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.springframework.aop.framework.Advised;
|
||||||
|
import org.springframework.aop.support.AopUtils;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.cache.CacheManager;
|
||||||
|
import org.springframework.test.util.ReflectionTestUtils;
|
||||||
|
import org.thingsboard.server.common.data.id.DeviceId;
|
||||||
|
import org.thingsboard.server.common.data.id.EntityId;
|
||||||
|
import org.thingsboard.server.common.data.relation.EntityRelation;
|
||||||
|
import org.thingsboard.server.common.data.relation.RelationTypeGroup;
|
||||||
|
import org.thingsboard.server.dao.relation.RelationDao;
|
||||||
|
import org.thingsboard.server.dao.relation.RelationService;
|
||||||
|
|
||||||
|
import java.util.UUID;
|
||||||
|
import java.util.concurrent.ExecutionException;
|
||||||
|
|
||||||
|
import static org.mockito.Mockito.*;
|
||||||
|
import static org.thingsboard.server.common.data.CacheConstants.RELATIONS_CACHE;
|
||||||
|
|
||||||
|
public abstract class BaseRelationCacheTest extends AbstractServiceTest {
|
||||||
|
|
||||||
|
private static final EntityId ENTITY_ID_FROM = new DeviceId(UUID.randomUUID());
|
||||||
|
private static final EntityId ENTITY_ID_TO = new DeviceId(UUID.randomUUID());
|
||||||
|
private static final String RELATION_TYPE = "Contains";
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private RelationService relationService;
|
||||||
|
@Autowired
|
||||||
|
private CacheManager cacheManager;
|
||||||
|
|
||||||
|
private RelationDao relationDao;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setup() throws Exception {
|
||||||
|
relationDao = mock(RelationDao.class);
|
||||||
|
ReflectionTestUtils.setField(unwrapRelationService(), "relationDao", relationDao);
|
||||||
|
}
|
||||||
|
|
||||||
|
@After
|
||||||
|
public void cleanup() {
|
||||||
|
cacheManager.getCache(RELATIONS_CACHE).clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
private RelationService unwrapRelationService() throws Exception {
|
||||||
|
if (AopUtils.isAopProxy(relationService) && relationService instanceof Advised) {
|
||||||
|
Object target = ((Advised) relationService).getTargetSource().getTarget();
|
||||||
|
return (RelationService) target;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testFindRelationByFrom_Cached() throws ExecutionException, InterruptedException {
|
||||||
|
when(relationDao.getRelation(ENTITY_ID_FROM, ENTITY_ID_TO, RELATION_TYPE, RelationTypeGroup.COMMON))
|
||||||
|
.thenReturn(Futures.immediateFuture(new EntityRelation(ENTITY_ID_FROM, ENTITY_ID_TO, RELATION_TYPE)));
|
||||||
|
|
||||||
|
relationService.getRelation(ENTITY_ID_FROM, ENTITY_ID_TO, RELATION_TYPE, RelationTypeGroup.COMMON);
|
||||||
|
relationService.getRelation(ENTITY_ID_FROM, ENTITY_ID_TO, RELATION_TYPE, RelationTypeGroup.COMMON);
|
||||||
|
|
||||||
|
verify(relationDao, times(1)).getRelation(ENTITY_ID_FROM, ENTITY_ID_TO, RELATION_TYPE, RelationTypeGroup.COMMON);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testDeleteRelations_EvictsCache() {
|
||||||
|
when(relationDao.getRelation(ENTITY_ID_FROM, ENTITY_ID_TO, RELATION_TYPE, RelationTypeGroup.COMMON))
|
||||||
|
.thenReturn(Futures.immediateFuture(new EntityRelation(ENTITY_ID_FROM, ENTITY_ID_TO, RELATION_TYPE)));
|
||||||
|
|
||||||
|
relationService.getRelation(ENTITY_ID_FROM, ENTITY_ID_TO, RELATION_TYPE, RelationTypeGroup.COMMON);
|
||||||
|
relationService.getRelation(ENTITY_ID_FROM, ENTITY_ID_TO, RELATION_TYPE, RelationTypeGroup.COMMON);
|
||||||
|
|
||||||
|
verify(relationDao, times(1)).getRelation(ENTITY_ID_FROM, ENTITY_ID_TO, RELATION_TYPE, RelationTypeGroup.COMMON);
|
||||||
|
|
||||||
|
relationService.deleteRelation(ENTITY_ID_FROM, ENTITY_ID_TO, RELATION_TYPE, RelationTypeGroup.COMMON);
|
||||||
|
|
||||||
|
relationService.getRelation(ENTITY_ID_FROM, ENTITY_ID_TO, RELATION_TYPE, RelationTypeGroup.COMMON);
|
||||||
|
relationService.getRelation(ENTITY_ID_FROM, ENTITY_ID_TO, RELATION_TYPE, RelationTypeGroup.COMMON);
|
||||||
|
|
||||||
|
verify(relationDao, times(2)).getRelation(ENTITY_ID_FROM, ENTITY_ID_TO, RELATION_TYPE, RelationTypeGroup.COMMON);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,23 @@
|
|||||||
|
/**
|
||||||
|
* Copyright © 2016-2017 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.service.nosql;
|
||||||
|
|
||||||
|
import org.thingsboard.server.dao.service.BaseRelationCacheTest;
|
||||||
|
import org.thingsboard.server.dao.service.DaoNoSqlTest;
|
||||||
|
|
||||||
|
@DaoNoSqlTest
|
||||||
|
public class RelationCacheNoSqlTest extends BaseRelationCacheTest {
|
||||||
|
}
|
||||||
@ -0,0 +1,23 @@
|
|||||||
|
/**
|
||||||
|
* Copyright © 2016-2017 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.service.sql;
|
||||||
|
|
||||||
|
import org.thingsboard.server.dao.service.BaseRelationCacheTest;
|
||||||
|
import org.thingsboard.server.dao.service.DaoSqlTest;
|
||||||
|
|
||||||
|
@DaoSqlTest
|
||||||
|
public class RelationCacheSqlTest extends BaseRelationCacheTest {
|
||||||
|
}
|
||||||
@ -8,3 +8,12 @@ zk.url=localhost:2181
|
|||||||
zk.zk_dir=/thingsboard
|
zk.zk_dir=/thingsboard
|
||||||
|
|
||||||
updates.enabled=false
|
updates.enabled=false
|
||||||
|
|
||||||
|
caching.specs.relations.timeToLiveInMinutes=1440
|
||||||
|
caching.specs.relations.maxSize=100000
|
||||||
|
|
||||||
|
caching.specs.deviceCredentials.timeToLiveInMinutes=1440
|
||||||
|
caching.specs.deviceCredentials.maxSize=100000
|
||||||
|
|
||||||
|
caching.specs.devices.timeToLiveInMinutes=1440
|
||||||
|
caching.specs.devices.maxSize=100000
|
||||||
6
pom.xml
6
pom.xml
@ -43,6 +43,7 @@
|
|||||||
<cassandra-unit.version>3.0.0.1</cassandra-unit.version>
|
<cassandra-unit.version>3.0.0.1</cassandra-unit.version>
|
||||||
<takari-cpsuite.version>1.2.7</takari-cpsuite.version>
|
<takari-cpsuite.version>1.2.7</takari-cpsuite.version>
|
||||||
<guava.version>18.0</guava.version>
|
<guava.version>18.0</guava.version>
|
||||||
|
<caffeine.version>2.6.1</caffeine.version>
|
||||||
<commons-lang3.version>3.4</commons-lang3.version>
|
<commons-lang3.version>3.4</commons-lang3.version>
|
||||||
<commons-validator.version>1.5.0</commons-validator.version>
|
<commons-validator.version>1.5.0</commons-validator.version>
|
||||||
<commons-io.version>2.5</commons-io.version>
|
<commons-io.version>2.5</commons-io.version>
|
||||||
@ -644,6 +645,11 @@
|
|||||||
<artifactId>guava</artifactId>
|
<artifactId>guava</artifactId>
|
||||||
<version>${guava.version}</version>
|
<version>${guava.version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.github.ben-manes.caffeine</groupId>
|
||||||
|
<artifactId>caffeine</artifactId>
|
||||||
|
<version>${caffeine.version}</version>
|
||||||
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.google.protobuf</groupId>
|
<groupId>com.google.protobuf</groupId>
|
||||||
<artifactId>protobuf-java</artifactId>
|
<artifactId>protobuf-java</artifactId>
|
||||||
|
|||||||
@ -26,17 +26,17 @@ import lombok.extern.slf4j.Slf4j;
|
|||||||
import org.eclipse.californium.core.CoapResource;
|
import org.eclipse.californium.core.CoapResource;
|
||||||
import org.eclipse.californium.core.CoapServer;
|
import org.eclipse.californium.core.CoapServer;
|
||||||
import org.eclipse.californium.core.network.CoapEndpoint;
|
import org.eclipse.californium.core.network.CoapEndpoint;
|
||||||
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||||
import org.thingsboard.server.common.transport.SessionMsgProcessor;
|
import org.thingsboard.server.common.transport.SessionMsgProcessor;
|
||||||
import org.thingsboard.server.common.transport.auth.DeviceAuthService;
|
import org.thingsboard.server.common.transport.auth.DeviceAuthService;
|
||||||
import org.thingsboard.server.transport.coap.adaptors.CoapTransportAdaptor;
|
import org.thingsboard.server.transport.coap.adaptors.CoapTransportAdaptor;
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.beans.factory.annotation.Value;
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
import org.springframework.context.ApplicationContext;
|
import org.springframework.context.ApplicationContext;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
@Service("CoapTransportService")
|
@Service("CoapTransportService")
|
||||||
|
@ConditionalOnProperty(prefix = "coap", value = "enabled", havingValue = "true", matchIfMissing = true)
|
||||||
@Slf4j
|
@Slf4j
|
||||||
public class CoapTransportService {
|
public class CoapTransportService {
|
||||||
|
|
||||||
|
|||||||
@ -24,6 +24,7 @@ import io.netty.util.ResourceLeakDetector;
|
|||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.beans.factory.annotation.Value;
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||||
import org.springframework.context.ApplicationContext;
|
import org.springframework.context.ApplicationContext;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import org.thingsboard.server.common.transport.SessionMsgProcessor;
|
import org.thingsboard.server.common.transport.SessionMsgProcessor;
|
||||||
@ -39,6 +40,7 @@ import javax.annotation.PreDestroy;
|
|||||||
* @author Andrew Shvayka
|
* @author Andrew Shvayka
|
||||||
*/
|
*/
|
||||||
@Service("MqttTransportService")
|
@Service("MqttTransportService")
|
||||||
|
@ConditionalOnProperty(prefix = "mqtt", value = "enabled", havingValue = "true", matchIfMissing = false)
|
||||||
@Slf4j
|
@Slf4j
|
||||||
public class MqttTransportService {
|
public class MqttTransportService {
|
||||||
|
|
||||||
|
|||||||
@ -84,16 +84,15 @@ public class GatewaySessionCtx {
|
|||||||
|
|
||||||
private void onDeviceConnect(String deviceName, String deviceType) {
|
private void onDeviceConnect(String deviceName, String deviceType) {
|
||||||
if (!devices.containsKey(deviceName)) {
|
if (!devices.containsKey(deviceName)) {
|
||||||
Optional<Device> deviceOpt = deviceService.findDeviceByTenantIdAndName(gateway.getTenantId(), deviceName);
|
Device device = deviceService.findDeviceByTenantIdAndName(gateway.getTenantId(), deviceName);
|
||||||
Device device = deviceOpt.orElseGet(() -> {
|
if (device == null) {
|
||||||
Device newDevice = new Device();
|
device = new Device();
|
||||||
newDevice.setTenantId(gateway.getTenantId());
|
device.setTenantId(gateway.getTenantId());
|
||||||
newDevice.setName(deviceName);
|
device.setName(deviceName);
|
||||||
newDevice.setType(deviceType);
|
device.setType(deviceType);
|
||||||
newDevice = deviceService.saveDevice(newDevice);
|
device = deviceService.saveDevice(device);
|
||||||
relationService.saveRelationAsync(new EntityRelation(gateway.getId(), newDevice.getId(), "Created"));
|
relationService.saveRelationAsync(new EntityRelation(gateway.getId(), device.getId(), "Created"));
|
||||||
return newDevice;
|
}
|
||||||
});
|
|
||||||
GatewayDeviceSessionCtx ctx = new GatewayDeviceSessionCtx(this, device);
|
GatewayDeviceSessionCtx ctx = new GatewayDeviceSessionCtx(this, device);
|
||||||
devices.put(deviceName, ctx);
|
devices.put(deviceName, ctx);
|
||||||
log.debug("[{}] Added device [{}] to the gateway session", gatewaySessionId, deviceName);
|
log.debug("[{}] Added device [{}] to the gateway session", gatewaySessionId, deviceName);
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user