Merge pull request #1500 from thingsboard/feature/spring-boot-2

[WIP] Migrate to Spring Boot 2.1.0 and Spring 5.1.2
This commit is contained in:
Igor Kulikov 2019-03-07 13:55:11 +02:00 committed by GitHub
commit e7bb6da9c2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
36 changed files with 385 additions and 124 deletions

View File

@ -118,17 +118,23 @@ class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcessor {
this.rpcSubscriptions = new HashMap<>();
this.toDeviceRpcPendingMap = new HashMap<>();
this.toServerRpcPendingMap = new HashMap<>();
initAttributes();
if (initAttributes()) {
restoreSessions();
}
}
private void initAttributes() {
private boolean initAttributes() {
Device device = systemContext.getDeviceService().findDeviceById(tenantId, deviceId);
if (device != null) {
this.deviceName = device.getName();
this.deviceType = device.getType();
this.defaultMetaData = new TbMsgMetaData();
this.defaultMetaData.putValue("deviceName", deviceName);
this.defaultMetaData.putValue("deviceType", deviceType);
return true;
} else {
return false;
}
}
void processRpcRequest(ActorContext context, ToDeviceRpcRequestActorMsg msg) {

View File

@ -91,6 +91,7 @@ public class RuleChainActorMessageProcessor extends ComponentMsgProcessor<RuleCh
public void start(ActorContext context) {
if (!started) {
RuleChain ruleChain = service.findRuleChainById(tenantId, entityId);
if (ruleChain != null) {
ruleChainName = ruleChain.getName();
List<RuleNode> ruleNodeList = service.getRuleChainNodes(tenantId, entityId);
log.trace("[{}][{}] Starting rule chain with {} nodes", tenantId, entityId, ruleNodeList.size());
@ -102,6 +103,7 @@ public class RuleChainActorMessageProcessor extends ComponentMsgProcessor<RuleCh
}
initRoutes(ruleChain, ruleNodeList);
started = true;
}
} else {
onUpdate(context);
}
@ -110,6 +112,7 @@ public class RuleChainActorMessageProcessor extends ComponentMsgProcessor<RuleCh
@Override
public void onUpdate(ActorContext context) {
RuleChain ruleChain = service.findRuleChainById(tenantId, entityId);
if (ruleChain != null) {
ruleChainName = ruleChain.getName();
List<RuleNode> ruleNodeList = service.getRuleChainNodes(tenantId, entityId);
log.trace("[{}][{}] Updating rule chain with {} nodes", tenantId, entityId, ruleNodeList.size());
@ -136,6 +139,7 @@ public class RuleChainActorMessageProcessor extends ComponentMsgProcessor<RuleCh
initRoutes(ruleChain, ruleNodeList);
}
}
@Override
public void stop(ActorContext context) {

View File

@ -55,8 +55,10 @@ public class RuleNodeActorMessageProcessor extends ComponentMsgProcessor<RuleNod
@Override
public void start(ActorContext context) throws Exception {
tbNode = initComponent(ruleNode);
if (tbNode != null) {
state = ComponentLifecycleState.ACTIVE;
}
}
@Override
public void onUpdate(ActorContext context) throws Exception {
@ -118,9 +120,12 @@ public class RuleNodeActorMessageProcessor extends ComponentMsgProcessor<RuleNod
}
private TbNode initComponent(RuleNode ruleNode) throws Exception {
TbNode tbNode = null;
if (ruleNode != null) {
Class<?> componentClazz = Class.forName(ruleNode.getType());
TbNode tbNode = (TbNode) (componentClazz.newInstance());
tbNode = (TbNode) (componentClazz.newInstance());
tbNode.init(defaultCtx, new TbNodeConfiguration(ruleNode.getConfiguration()));
}
return tbNode;
}

View File

@ -22,7 +22,7 @@ import java.util.HashMap;
import java.util.Map;
@Configuration
@ConfigurationProperties(prefix = "audit_log.logging_level")
@ConfigurationProperties(prefix = "audit-log.logging-level")
public class AuditLogLevelProperties {
private Map<String, String> mask = new HashMap<>();

View File

@ -0,0 +1,46 @@
/**
* 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.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.TaskScheduler;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.SchedulingConfigurer;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
import org.springframework.scheduling.config.ScheduledTaskRegistrar;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
@Configuration
@EnableScheduling
public class SchedulingConfiguration implements SchedulingConfigurer {
@Override
public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
taskRegistrar.setScheduler(taskScheduler());
}
@Bean(destroyMethod="shutdown")
public TaskScheduler taskScheduler() {
ThreadPoolTaskScheduler threadPoolScheduler = new ThreadPoolTaskScheduler();
threadPoolScheduler.setThreadNamePrefix("TB-Scheduling-");
threadPoolScheduler.setPoolSize(Runtime.getRuntime().availableProcessors());
threadPoolScheduler.setRemoveOnCancelPolicy(true);
return threadPoolScheduler;
}
}

View File

@ -15,11 +15,28 @@
*/
package org.thingsboard.server.config;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.ExtendedProperties;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.velocity.app.VelocityEngine;
import org.apache.velocity.exception.ResourceNotFoundException;
import org.apache.velocity.runtime.RuntimeConstants;
import org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader;
import org.springframework.context.MessageSource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.context.support.ResourceBundleMessageSource;
import org.springframework.core.io.DefaultResourceLoader;
import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceLoader;
import org.springframework.util.StringUtils;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.Arrays;
@Configuration
public class ThingsboardMessageConfiguration {
@ -33,4 +50,113 @@ public class ThingsboardMessageConfiguration {
return messageSource;
}
private static final String DEFAULT_RESOURCE_LOADER_PATH = "classpath:/templates/";
private ResourceLoader resourceLoader = new DefaultResourceLoader();
@Bean
public VelocityEngine velocityEngine() {
VelocityEngine velocityEngine = new VelocityEngine();
try {
Resource resource = resourceLoader.getResource(DEFAULT_RESOURCE_LOADER_PATH);
File file = resource.getFile();
velocityEngine.setProperty(RuntimeConstants.RESOURCE_LOADER, "file");
velocityEngine.setProperty(RuntimeConstants.FILE_RESOURCE_LOADER_CACHE, "true");
velocityEngine.setProperty(RuntimeConstants.FILE_RESOURCE_LOADER_PATH, file.getAbsolutePath());
} catch (IOException e) {
initSpringResourceLoader(velocityEngine, DEFAULT_RESOURCE_LOADER_PATH);
}
velocityEngine.init();
return velocityEngine;
}
private void initSpringResourceLoader(VelocityEngine velocityEngine, String resourceLoaderPath) {
velocityEngine.setProperty(
RuntimeConstants.RESOURCE_LOADER, SpringResourceLoader.NAME);
velocityEngine.setProperty(
SpringResourceLoader.SPRING_RESOURCE_LOADER_CLASS, SpringResourceLoader.class.getName());
velocityEngine.setProperty(
SpringResourceLoader.SPRING_RESOURCE_LOADER_CACHE, "true");
velocityEngine.setApplicationAttribute(
SpringResourceLoader.SPRING_RESOURCE_LOADER, resourceLoader);
velocityEngine.setApplicationAttribute(
SpringResourceLoader.SPRING_RESOURCE_LOADER_PATH, resourceLoaderPath);
}
@Slf4j
static class SpringResourceLoader extends org.apache.velocity.runtime.resource.loader.ResourceLoader {
public static final String NAME = "spring";
public static final String SPRING_RESOURCE_LOADER_CLASS = "spring.resource.loader.class";
public static final String SPRING_RESOURCE_LOADER_CACHE = "spring.resource.loader.cache";
public static final String SPRING_RESOURCE_LOADER = "spring.resource.loader";
public static final String SPRING_RESOURCE_LOADER_PATH = "spring.resource.loader.path";
private org.springframework.core.io.ResourceLoader resourceLoader;
private String[] resourceLoaderPaths;
@Override
public void init(ExtendedProperties configuration) {
this.resourceLoader = (org.springframework.core.io.ResourceLoader)
this.rsvc.getApplicationAttribute(SPRING_RESOURCE_LOADER);
String resourceLoaderPath = (String) this.rsvc.getApplicationAttribute(SPRING_RESOURCE_LOADER_PATH);
if (this.resourceLoader == null) {
throw new IllegalArgumentException(
"'resourceLoader' application attribute must be present for SpringResourceLoader");
}
if (resourceLoaderPath == null) {
throw new IllegalArgumentException(
"'resourceLoaderPath' application attribute must be present for SpringResourceLoader");
}
this.resourceLoaderPaths = StringUtils.commaDelimitedListToStringArray(resourceLoaderPath);
for (int i = 0; i < this.resourceLoaderPaths.length; i++) {
String path = this.resourceLoaderPaths[i];
if (!path.endsWith("/")) {
this.resourceLoaderPaths[i] = path + "/";
}
}
if (log.isInfoEnabled()) {
log.info("SpringResourceLoader for Velocity: using resource loader [" + this.resourceLoader +
"] and resource loader paths " + Arrays.asList(this.resourceLoaderPaths));
}
}
@Override
public InputStream getResourceStream(String source) throws ResourceNotFoundException {
if (log.isDebugEnabled()) {
log.debug("Looking for Velocity resource with name [" + source + "]");
}
for (String resourceLoaderPath : this.resourceLoaderPaths) {
org.springframework.core.io.Resource resource =
this.resourceLoader.getResource(resourceLoaderPath + source);
try {
return resource.getInputStream();
}
catch (IOException ex) {
if (log.isDebugEnabled()) {
log.debug("Could not find Velocity resource: " + resource);
}
}
}
throw new ResourceNotFoundException(
"Could not find resource [" + source + "] in Spring resource loader path");
}
@Override
public boolean isSourceModified(org.apache.velocity.runtime.resource.Resource resource) {
return false;
}
@Override
public long getLastModified(org.apache.velocity.runtime.resource.Resource resource) {
return 0;
}
}
}

View File

@ -57,7 +57,7 @@ import java.util.List;
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled=true)
@Order(SecurityProperties.ACCESS_OVERRIDE_ORDER)
@Order(SecurityProperties.BASIC_AUTH_ORDER)
public class ThingsboardSecurityConfiguration extends WebSecurityConfigurerAdapter {
public static final String JWT_TOKEN_HEADER_PARAM = "X-Authorization";

View File

@ -17,6 +17,7 @@ package org.thingsboard.server.service.install;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.thingsboard.server.dao.cassandra.CassandraInstallCluster;
import org.thingsboard.server.service.install.cql.CQLStatementsParser;
@ -30,6 +31,7 @@ public abstract class CassandraAbstractDatabaseSchemaService implements Database
private static final String CASSANDRA_DIR = "cassandra";
@Autowired
@Qualifier("CassandraInstallCluster")
private CassandraInstallCluster cluster;
@Autowired

View File

@ -18,6 +18,7 @@ package org.thingsboard.server.service.install;
import com.datastax.driver.core.KeyspaceMetadata;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Profile;
import org.springframework.stereotype.Service;
import org.thingsboard.server.dao.cassandra.CassandraCluster;
@ -65,6 +66,7 @@ public class CassandraDatabaseUpgradeService implements DatabaseUpgradeService {
private CassandraCluster cluster;
@Autowired
@Qualifier("CassandraInstallCluster")
private CassandraInstallCluster installCluster;
@Autowired

View File

@ -18,7 +18,9 @@ package org.thingsboard.server.service.mail;
import com.fasterxml.jackson.databind.JsonNode;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.velocity.VelocityContext;
import org.apache.velocity.app.VelocityEngine;
import org.apache.velocity.exception.VelocityException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.MessageSource;
@ -26,7 +28,6 @@ import org.springframework.core.NestedRuntimeException;
import org.springframework.mail.javamail.JavaMailSenderImpl;
import org.springframework.mail.javamail.MimeMessageHelper;
import org.springframework.stereotype.Service;
import org.springframework.ui.velocity.VelocityEngineUtils;
import org.thingsboard.rule.engine.api.MailService;
import org.thingsboard.server.common.data.AdminSettings;
import org.thingsboard.server.common.data.exception.ThingsboardErrorCode;
@ -39,6 +40,8 @@ import org.thingsboard.server.dao.settings.AdminSettingsService;
import javax.annotation.PostConstruct;
import javax.mail.MessagingException;
import javax.mail.internet.MimeMessage;
import java.io.StringWriter;
import java.io.Writer;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
@ -126,7 +129,7 @@ public class DefaultMailService implements MailService {
Map<String, Object> model = new HashMap<String, Object>();
model.put(TARGET_EMAIL, email);
String message = VelocityEngineUtils.mergeTemplateIntoString(this.engine,
String message = mergeTemplateIntoString(this.engine,
"test.vm", UTF_8, model);
sendMail(testMailSender, mailFrom, email, subject, message);
@ -141,7 +144,7 @@ public class DefaultMailService implements MailService {
model.put("activationLink", activationLink);
model.put(TARGET_EMAIL, email);
String message = VelocityEngineUtils.mergeTemplateIntoString(this.engine,
String message = mergeTemplateIntoString(this.engine,
"activation.vm", UTF_8, model);
sendMail(mailSender, mailFrom, email, subject, message);
@ -156,7 +159,7 @@ public class DefaultMailService implements MailService {
model.put("loginLink", loginLink);
model.put(TARGET_EMAIL, email);
String message = VelocityEngineUtils.mergeTemplateIntoString(this.engine,
String message = mergeTemplateIntoString(this.engine,
"account.activated.vm", UTF_8, model);
sendMail(mailSender, mailFrom, email, subject, message);
@ -171,7 +174,7 @@ public class DefaultMailService implements MailService {
model.put("passwordResetLink", passwordResetLink);
model.put(TARGET_EMAIL, email);
String message = VelocityEngineUtils.mergeTemplateIntoString(this.engine,
String message = mergeTemplateIntoString(this.engine,
"reset.password.vm", UTF_8, model);
sendMail(mailSender, mailFrom, email, subject, message);
@ -186,7 +189,7 @@ public class DefaultMailService implements MailService {
model.put("loginLink", loginLink);
model.put(TARGET_EMAIL, email);
String message = VelocityEngineUtils.mergeTemplateIntoString(this.engine,
String message = mergeTemplateIntoString(this.engine,
"password.was.reset.vm", UTF_8, model);
sendMail(mailSender, mailFrom, email, subject, message);
@ -225,6 +228,22 @@ public class DefaultMailService implements MailService {
}
}
private static String mergeTemplateIntoString(VelocityEngine velocityEngine, String templateLocation,
String encoding, Map<String, Object> model) throws VelocityException {
StringWriter result = new StringWriter();
mergeTemplate(velocityEngine, templateLocation, encoding, model, result);
return result.toString();
}
private static void mergeTemplate(
VelocityEngine velocityEngine, String templateLocation, String encoding,
Map<String, Object> model, Writer writer) throws VelocityException {
VelocityContext velocityContext = new VelocityContext(model);
velocityEngine.mergeTemplate(templateLocation, encoding, velocityContext, writer);
}
protected ThingsboardException handleException(Exception exception) {
String message;
if (exception instanceof NestedRuntimeException) {

View File

@ -27,7 +27,6 @@ import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import org.springframework.web.socket.CloseStatus;
import org.springframework.web.socket.WebSocketSession;
import org.thingsboard.server.common.data.DataConstants;
import org.thingsboard.server.common.data.id.CustomerId;
import org.thingsboard.server.common.data.id.EntityId;

View File

@ -293,11 +293,13 @@ spring.mvc.cors:
# spring serve gzip compressed static resources
spring.resources.chain:
gzipped: "true"
compressed: "true"
strategy:
content:
enabled: "true"
spring.jpa.properties.hibernate.jdbc.lob.non_contextual_creation: "true"
# HSQLDB DAO Configuration
spring:
data:
@ -331,7 +333,7 @@ spring:
# password: "${SPRING_DATASOURCE_PASSWORD:postgres}"
# Audit log parameters
audit_log:
audit-log:
# Enable/disable audit log functionality.
enabled: "${AUDIT_LOG_ENABLED:true}"
# Specify partitioning size for audit log by tenant id storage. Example MINUTES, HOURS, DAYS, MONTHS
@ -340,7 +342,7 @@ audit_log:
default_query_period: "${AUDIT_LOG_DEFAULT_QUERY_PERIOD:30}"
# Logging levels per each entity type.
# Allowed values: OFF (disable), W (log write operations), RW (log read and write operations)
logging_level:
logging-level:
mask:
"device": "${AUDIT_LOG_MASK_DEVICE:W}"
"asset": "${AUDIT_LOG_MASK_ASSET:W}"

View File

@ -128,7 +128,7 @@ public abstract class AbstractMqttServerSideRpcIntegrationTest extends AbstractC
String accessToken = deviceCredentials.getCredentialsId();
assertNotNull(accessToken);
String setGpioRequest = "{\"method\":\"setGpio\",\"params\":{\"pin\": \"23\",\"value\": 1}}";
String setGpioRequest = "{\"method\":\"setGpio\",\"params\":{\"pin\": \"23\",\"value\": 1},\"timeout\": 6000}";
String deviceId = savedDevice.getId().getId().toString();
doPostAsync("/api/plugins/rpc/oneway/" + deviceId, setGpioRequest, String.class, status().isRequestTimeout(),
@ -183,7 +183,7 @@ public abstract class AbstractMqttServerSideRpcIntegrationTest extends AbstractC
String accessToken = deviceCredentials.getCredentialsId();
assertNotNull(accessToken);
String setGpioRequest = "{\"method\":\"setGpio\",\"params\":{\"pin\": \"23\",\"value\": 1}}";
String setGpioRequest = "{\"method\":\"setGpio\",\"params\":{\"pin\": \"23\",\"value\": 1},\"timeout\": 6000}";
String deviceId = savedDevice.getId().getId().toString();
doPostAsync("/api/plugins/rpc/twoway/" + deviceId, setGpioRequest, String.class, status().isRequestTimeout(),

View File

@ -111,7 +111,7 @@ public abstract class AbstractMqttTelemetryIntegrationTest extends AbstractContr
client.subscribe("v1/devices/me/attributes", MqttQoS.AT_MOST_ONCE.value());
String payload = "{\"key\":\"value\"}";
String result = doPostAsync("/api/plugins/telemetry/" + savedDevice.getId() + "/SHARED_SCOPE", payload, String.class, status().isOk());
latch.await(3, TimeUnit.SECONDS);
latch.await(10, TimeUnit.SECONDS);
assertEquals(payload, callback.getPayload());
assertEquals(MqttQoS.AT_MOST_ONCE.value(), callback.getQoS());
}

View File

@ -18,11 +18,7 @@ package org.thingsboard.server.dao;
import org.thingsboard.server.common.data.id.UUIDBased;
import org.thingsboard.server.dao.model.ToData;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.UUID;
import java.util.*;
public abstract class DaoUtil {
@ -50,6 +46,14 @@ public abstract class DaoUtil {
return object;
}
public static <T> T getData(Optional<? extends ToData<T>> data) {
T object = null;
if (data.isPresent()) {
object = data.get().toData();
}
return object;
}
public static UUID getId(UUIDBased idBased) {
UUID id = null;
if (idBased != null) {

View File

@ -60,7 +60,7 @@ import static org.thingsboard.server.dao.service.Validator.validateId;
@Slf4j
@Service
@ConditionalOnProperty(prefix = "audit_log", value = "enabled", havingValue = "true")
@ConditionalOnProperty(prefix = "audit-log", value = "enabled", havingValue = "true")
public class AuditLogServiceImpl implements AuditLogService {
private static final ObjectMapper objectMapper = new ObjectMapper();

View File

@ -88,11 +88,11 @@ public class CassandraAuditLogDao extends CassandraAbstractSearchTimeDao<AuditLo
protected ExecutorService readResultsProcessingExecutor;
@Value("${audit_log.by_tenant_partitioning}")
@Value("${audit-log.by_tenant_partitioning}")
private String partitioning;
private TsPartitionDate tsFormat;
@Value("${audit_log.default_query_period}")
@Value("${audit-log.default_query_period}")
private Integer defaultQueryPeriodInDays;
private PreparedStatement partitionInsertStmt;

View File

@ -33,7 +33,7 @@ import org.thingsboard.server.common.data.page.TimePageLink;
import java.util.List;
@Service
@ConditionalOnProperty(prefix = "audit_log", value = "enabled", havingValue = "false")
@ConditionalOnProperty(prefix = "audit-log", value = "enabled", havingValue = "false")
public class DummyAuditLogServiceImpl implements AuditLogService {
@Override

View File

@ -20,7 +20,7 @@ import org.springframework.stereotype.Component;
import org.thingsboard.server.common.data.audit.AuditLog;
@Component
@ConditionalOnProperty(prefix = "audit_log.sink", value = "type", havingValue = "none")
@ConditionalOnProperty(prefix = "audit-log.sink", value = "type", havingValue = "none")
public class DummyAuditLogSink implements AuditLogSink {
@Override

View File

@ -44,7 +44,7 @@ import java.time.format.DateTimeFormatter;
import java.util.Collections;
@Component
@ConditionalOnProperty(prefix = "audit_log.sink", value = "type", havingValue = "elasticsearch")
@ConditionalOnProperty(prefix = "audit-log.sink", value = "type", havingValue = "elasticsearch")
@Slf4j
public class ElasticsearchAuditLogSink implements AuditLogSink {
@ -54,19 +54,19 @@ public class ElasticsearchAuditLogSink implements AuditLogSink {
private final ObjectMapper mapper = new ObjectMapper();
@Value("${audit_log.sink.index_pattern}")
@Value("${audit-log.sink.index_pattern}")
private String indexPattern;
@Value("${audit_log.sink.scheme_name}")
@Value("${audit-log.sink.scheme_name}")
private String schemeName;
@Value("${audit_log.sink.host}")
@Value("${audit-log.sink.host}")
private String host;
@Value("${audit_log.sink.port}")
@Value("${audit-log.sink.port}")
private int port;
@Value("${audit_log.sink.user_name}")
@Value("${audit-log.sink.user_name}")
private String userName;
@Value("${audit_log.sink.password}")
@Value("${audit-log.sink.password}")
private String password;
@Value("${audit_log.sink.date_format}")
@Value("${audit-log.sink.date_format}")
private String dateFormat;
private RestClient restClient;

View File

@ -19,14 +19,37 @@ import lombok.Data;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.cache.CacheManager;
import org.springframework.cache.interceptor.SimpleKey;
import org.springframework.core.convert.ConversionService;
import org.springframework.core.convert.TypeDescriptor;
import org.springframework.core.convert.converter.ConditionalGenericConverter;
import org.springframework.core.convert.converter.Converter;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.cache.interceptor.KeyGenerator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.convert.converter.ConverterRegistry;
import org.springframework.data.convert.ReadingConverter;
import org.springframework.data.convert.WritingConverter;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.convert.RedisCustomConversions;
import org.springframework.format.support.DefaultFormattingConversionService;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.common.data.id.EntityIdFactory;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.Collections;
import java.util.Set;
import java.util.UUID;
@Configuration
@ConditionalOnProperty(prefix = "cache", value = "type", havingValue = "redis", matchIfMissing = false)
@ -57,15 +80,12 @@ public class TBRedisCacheConfiguration {
}
@Bean
public RedisTemplate<String, String> redisTemplate(RedisConnectionFactory cf) {
RedisTemplate<String, String> redisTemplate = new RedisTemplate<>();
redisTemplate.setConnectionFactory(cf);
return redisTemplate;
}
@Bean
public CacheManager cacheManager(RedisTemplate redisTemplate) {
return new RedisCacheManager(redisTemplate);
public CacheManager cacheManager(RedisConnectionFactory cf) {
DefaultFormattingConversionService redisConversionService = new DefaultFormattingConversionService();
RedisCacheConfiguration.registerDefaultConverters(redisConversionService);
registerDefaultConverters(redisConversionService);
RedisCacheConfiguration configuration = RedisCacheConfiguration.defaultCacheConfig().withConversionService(redisConversionService);
return RedisCacheManager.builder(cf).cacheDefaults(configuration).build();
}
@Bean
@ -73,5 +93,8 @@ public class TBRedisCacheConfiguration {
return new PreviousDeviceCredentialsIdKeyGenerator();
}
private static void registerDefaultConverters(ConverterRegistry registry) {
Assert.notNull(registry, "ConverterRegistry must not be null!");
registry.addConverter(EntityId.class, String.class, EntityId::toString);
}
}

View File

@ -21,7 +21,7 @@ import org.thingsboard.server.dao.util.NoSqlAnyDao;
import javax.annotation.PostConstruct;
@Component
@Component("CassandraCluster")
@NoSqlAnyDao
public class CassandraCluster extends AbstractCassandraCluster {

View File

@ -21,7 +21,7 @@ import org.thingsboard.server.dao.util.NoSqlAnyDao;
import javax.annotation.PostConstruct;
@Component
@Component("CassandraInstallCluster")
@NoSqlAnyDao
@Profile("install")
public class CassandraInstallCluster extends AbstractCassandraCluster {

View File

@ -27,6 +27,7 @@ import com.datastax.driver.core.TypeCodec;
import com.datastax.driver.core.exceptions.CodecNotFoundException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.dao.cassandra.CassandraCluster;
import org.thingsboard.server.dao.model.type.AuthorityCodec;
@ -44,6 +45,7 @@ import java.util.concurrent.ConcurrentMap;
public abstract class CassandraAbstractDao {
@Autowired
@Qualifier("CassandraCluster")
protected CassandraCluster cluster;
private ConcurrentMap<String, PreparedStatement> preparedStatementMap = new ConcurrentHashMap<>();

View File

@ -27,6 +27,7 @@ import org.thingsboard.server.dao.DaoUtil;
import org.thingsboard.server.dao.model.BaseEntity;
import java.util.List;
import java.util.Optional;
import java.util.UUID;
import static org.thingsboard.server.common.data.UUIDConverter.fromTimeUUID;
@ -67,23 +68,23 @@ public abstract class JpaAbstractDao<E extends BaseEntity<D>, D>
@Override
public D findById(TenantId tenantId, UUID key) {
log.debug("Get entity by key {}", key);
E entity = getCrudRepository().findOne(fromTimeUUID(key));
Optional<E> entity = getCrudRepository().findById(fromTimeUUID(key));
return DaoUtil.getData(entity);
}
@Override
public ListenableFuture<D> findByIdAsync(TenantId tenantId, UUID key) {
log.debug("Get entity by key async {}", key);
return service.submit(() -> DaoUtil.getData(getCrudRepository().findOne(fromTimeUUID(key))));
return service.submit(() -> DaoUtil.getData(getCrudRepository().findById(fromTimeUUID(key))));
}
@Override
@Transactional
public boolean removeById(TenantId tenantId, UUID id) {
String key = fromTimeUUID(id);
getCrudRepository().delete(key);
getCrudRepository().deleteById(key);
log.debug("Remove request: {}", key);
return getCrudRepository().findOne(key) == null;
return !getCrudRepository().existsById(key);
}
@Override

View File

@ -52,7 +52,7 @@ public class JpaAttributeDao extends JpaAbstractDaoListeningExecutorService impl
AttributeKvCompositeKey compositeKey =
getAttributeKvCompositeKey(entityId, attributeType, attributeKey);
return Futures.immediateFuture(
Optional.ofNullable(DaoUtil.getData(attributeKvRepository.findOne(compositeKey))));
Optional.ofNullable(DaoUtil.getData(attributeKvRepository.findById(compositeKey))));
}
@Override
@ -64,7 +64,7 @@ public class JpaAttributeDao extends JpaAbstractDaoListeningExecutorService impl
getAttributeKvCompositeKey(entityId, attributeType, attributeKey))
.collect(Collectors.toList());
return Futures.immediateFuture(
DaoUtil.convertDataList(Lists.newArrayList(attributeKvRepository.findAll(compositeKeys))));
DaoUtil.convertDataList(Lists.newArrayList(attributeKvRepository.findAllById(compositeKeys))));
}
@Override
@ -103,7 +103,7 @@ public class JpaAttributeDao extends JpaAbstractDaoListeningExecutorService impl
}).collect(Collectors.toList());
return service.submit(() -> {
attributeKvRepository.delete(entitiesToDelete);
attributeKvRepository.deleteAll(entitiesToDelete);
return null;
});
}

View File

@ -66,7 +66,7 @@ public class JpaBaseComponentDescriptorDao extends JpaAbstractSearchTextDao<Comp
if (component.getId() == null) {
component.setId(new ComponentDescriptorId(UUIDs.timeBased()));
}
if (componentDescriptorRepository.findOne(UUIDConverter.fromTimeUUID(component.getId().getId())) == null) {
if (!componentDescriptorRepository.existsById(UUIDConverter.fromTimeUUID(component.getId().getId()))) {
return Optional.of(save(tenantId, component));
}
return Optional.empty();

View File

@ -97,13 +97,13 @@ public class JpaRelationDao extends JpaAbstractDaoListeningExecutorService imple
@Override
public ListenableFuture<Boolean> checkRelation(TenantId tenantId, EntityId from, EntityId to, String relationType, RelationTypeGroup typeGroup) {
RelationCompositeKey key = getRelationCompositeKey(from, to, relationType, typeGroup);
return service.submit(() -> relationRepository.findOne(key) != null);
return service.submit(() -> relationRepository.existsById(key));
}
@Override
public ListenableFuture<EntityRelation> getRelation(TenantId tenantId, EntityId from, EntityId to, String relationType, RelationTypeGroup typeGroup) {
RelationCompositeKey key = getRelationCompositeKey(from, to, relationType, typeGroup);
return service.submit(() -> DaoUtil.getData(relationRepository.findOne(key)));
return service.submit(() -> DaoUtil.getData(relationRepository.findById(key)));
}
private RelationCompositeKey getRelationCompositeKey(EntityId from, EntityId to, String relationType, RelationTypeGroup typeGroup) {
@ -152,9 +152,9 @@ public class JpaRelationDao extends JpaAbstractDaoListeningExecutorService imple
}
private boolean deleteRelationIfExists(RelationCompositeKey key) {
boolean relationExistsBeforeDelete = relationRepository.exists(key);
boolean relationExistsBeforeDelete = relationRepository.existsById(key);
if (relationExistsBeforeDelete) {
relationRepository.delete(key);
relationRepository.deleteById(key);
}
return relationExistsBeforeDelete;
}

View File

@ -53,7 +53,7 @@ public interface RelationRepository
RelationEntity save(RelationEntity entity);
@Transactional
void delete(RelationCompositeKey id);
void deleteById(RelationCompositeKey id);
@Transactional
void deleteByFromIdAndFromType(String fromId, String fromType);

View File

@ -284,10 +284,10 @@ public class JpaTimeseriesDao extends JpaAbstractDaoListeningExecutorService imp
entityId.getEntityType(),
fromTimeUUID(entityId.getId()),
key);
TsKvLatestEntity entry = tsKvLatestRepository.findOne(compositeKey);
Optional<TsKvLatestEntity> entry = tsKvLatestRepository.findById(compositeKey);
TsKvEntry result;
if (entry != null) {
result = DaoUtil.getData(entry);
if (entry.isPresent()) {
result = DaoUtil.getData(entry.get());
} else {
result = new BasicTsKvEntry(System.currentTimeMillis(), new StringDataEntry(key, null));
}

View File

@ -82,6 +82,7 @@ public class CustomCassandraCQLUnit extends BaseCassandraUnit {
session = null;
cluster = null;
}
System.setSecurityManager(null);
}
// Getters for those who do not like to directly access fields

View File

@ -4,10 +4,10 @@ zk.zk_dir=/thingsboard
updates.enabled=false
audit_log.enabled=true
audit_log.by_tenant_partitioning=MONTHS
audit_log.default_query_period=30
audit_log.sink.type=none
audit-log.enabled=true
audit-log.by_tenant_partitioning=MONTHS
audit-log.default_query_period=30
audit-log.sink.type=none
cache.type=caffeine
#cache.type=redis

View File

@ -4,6 +4,7 @@ database.entities.type=sql
sql.ts_inserts_executor_type=fixed
sql.ts_inserts_fixed_thread_pool_size=10
spring.jpa.properties.hibernate.jdbc.lob.non_contextual_creation=true
spring.jpa.show-sql=false
spring.jpa.hibernate.ddl-auto=validate
spring.jpa.database-platform=org.hibernate.dialect.HSQLDialect

38
pom.xml
View File

@ -29,10 +29,10 @@
<properties>
<main.dir>${basedir}</main.dir>
<spring-boot.version>1.4.3.RELEASE</spring-boot.version>
<spring.version>4.3.4.RELEASE</spring.version>
<spring-security.version>4.2.0.RELEASE</spring-security.version>
<spring-data-redis.version>1.8.10.RELEASE</spring-data-redis.version>
<spring-boot.version>2.1.3.RELEASE</spring-boot.version>
<spring.version>5.1.5.RELEASE</spring.version>
<spring-security.version>5.1.4.RELEASE</spring-security.version>
<spring-data-redis.version>2.1.5.RELEASE</spring-data-redis.version>
<jedis.version>2.9.0</jedis.version>
<jjwt.version>0.7.0</jjwt.version>
<json-path.version>2.2.0</json-path.version>
@ -41,8 +41,8 @@
<logback.version>1.2.3</logback.version>
<mockito.version>1.9.5</mockito.version>
<rat.version>0.10</rat.version>
<cassandra.version>3.5.0</cassandra.version>
<cassandra-unit.version>3.3.0.2</cassandra-unit.version>
<cassandra.version>3.6.0</cassandra.version>
<cassandra-unit.version>3.5.0.1</cassandra-unit.version>
<takari-cpsuite.version>1.2.7</takari-cpsuite.version>
<guava.version>21.0</guava.version>
<caffeine.version>2.6.1</caffeine.version>
@ -50,7 +50,7 @@
<commons-validator.version>1.5.0</commons-validator.version>
<commons-io.version>2.5</commons-io.version>
<commons-csv.version>1.4</commons-csv.version>
<jackson.version>2.8.11.1</jackson.version>
<jackson.version>2.9.7</jackson.version>
<json-schema-validator.version>2.2.6</json-schema-validator.version>
<scala.version>2.11</scala.version>
<akka.version>2.4.2</akka.version>
@ -60,11 +60,11 @@
<velocity-tools.version>2.0</velocity-tools.version>
<mail.version>1.4.3</mail.version>
<curator.version>4.0.1</curator.version>
<protobuf.version>3.0.2</protobuf.version>
<grpc.version>1.12.0</grpc.version>
<protobuf.version>3.6.1</protobuf.version>
<grpc.version>1.16.1</grpc.version>
<lombok.version>1.16.18</lombok.version>
<paho.client.version>1.1.0</paho.client.version>
<netty.version>4.1.22.Final</netty.version>
<netty.version>4.1.30.Final</netty.version>
<os-maven-plugin.version>1.5.0</os-maven-plugin.version>
<rabbitmq.version>4.8.0</rabbitmq.version>
<surfire.version>2.19.1</surfire.version>
@ -85,6 +85,8 @@
<kafka.version>2.0.0</kafka.version>
<bucket4j.version>4.1.1</bucket4j.version>
<fst.version>2.57</fst.version>
<antlr.version>2.7.7</antlr.version>
<snakeyaml.version>1.23</snakeyaml.version>
</properties>
<modules>
@ -512,6 +514,16 @@
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.yaml</groupId>
<artifactId>snakeyaml</artifactId>
<version>${snakeyaml.version}</version>
</dependency>
<dependency>
<groupId>antlr</groupId>
<artifactId>antlr</artifactId>
<version>${antlr.version}</version>
</dependency>
<dependency>
<groupId>com.rabbitmq</groupId>
<artifactId>amqp-client</artifactId>
@ -794,6 +806,12 @@
<groupId>de.ruedigermoeller</groupId>
<artifactId>fst</artifactId>
<version>${fst.version}</version>
<exclusions>
<exclusion>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>io.springfox.ui</groupId>