diff --git a/application/pom.xml b/application/pom.xml
index d99f60773e..238c5f47f9 100644
--- a/application/pom.xml
+++ b/application/pom.xml
@@ -122,7 +122,7 @@
org.springframework.boot
- spring-boot-starter-websocket
+ spring-boot-starter-webflux
io.jsonwebtoken
diff --git a/application/src/main/java/org/thingsboard/server/config/AuditLogLevelProperties.java b/application/src/main/java/org/thingsboard/server/config/AuditLogLevelProperties.java
index 4c36a15758..d05f8326b1 100644
--- a/application/src/main/java/org/thingsboard/server/config/AuditLogLevelProperties.java
+++ b/application/src/main/java/org/thingsboard/server/config/AuditLogLevelProperties.java
@@ -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 mask = new HashMap<>();
diff --git a/application/src/main/java/org/thingsboard/server/config/SchedulingConfiguration.java b/application/src/main/java/org/thingsboard/server/config/SchedulingConfiguration.java
new file mode 100644
index 0000000000..aebd63698a
--- /dev/null
+++ b/application/src/main/java/org/thingsboard/server/config/SchedulingConfiguration.java
@@ -0,0 +1,47 @@
+/**
+ * Copyright © 2016-2018 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;
+ }
+}
diff --git a/application/src/main/java/org/thingsboard/server/config/ThingsboardMessageConfiguration.java b/application/src/main/java/org/thingsboard/server/config/ThingsboardMessageConfiguration.java
index 038f8bc6ae..a44d9fedcb 100644
--- a/application/src/main/java/org/thingsboard/server/config/ThingsboardMessageConfiguration.java
+++ b/application/src/main/java/org/thingsboard/server/config/ThingsboardMessageConfiguration.java
@@ -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 {
@@ -32,5 +49,114 @@ public class ThingsboardMessageConfiguration {
messageSource.setDefaultEncoding("UTF-8");
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;
+ }
+
+ }
}
diff --git a/application/src/main/java/org/thingsboard/server/config/ThingsboardSecurityConfiguration.java b/application/src/main/java/org/thingsboard/server/config/ThingsboardSecurityConfiguration.java
index 1901e49c3d..13f7c569c4 100644
--- a/application/src/main/java/org/thingsboard/server/config/ThingsboardSecurityConfiguration.java
+++ b/application/src/main/java/org/thingsboard/server/config/ThingsboardSecurityConfiguration.java
@@ -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";
diff --git a/application/src/main/java/org/thingsboard/server/config/ThingsboardWebFluxSecurityConfig.java b/application/src/main/java/org/thingsboard/server/config/ThingsboardWebFluxSecurityConfig.java
new file mode 100644
index 0000000000..bdb168f714
--- /dev/null
+++ b/application/src/main/java/org/thingsboard/server/config/ThingsboardWebFluxSecurityConfig.java
@@ -0,0 +1,61 @@
+/**
+ * Copyright © 2016-2018 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.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Bean;
+import org.springframework.security.authentication.AuthenticationManager;
+import org.springframework.security.authentication.ReactiveAuthenticationManager;
+import org.springframework.security.config.annotation.method.configuration.EnableReactiveMethodSecurity;
+import org.springframework.security.config.annotation.web.reactive.EnableWebFluxSecurity;
+import org.springframework.security.config.web.server.SecurityWebFiltersOrder;
+import org.springframework.security.config.web.server.ServerHttpSecurity;
+import org.springframework.security.web.server.SecurityWebFilterChain;
+import org.springframework.security.web.server.context.ServerSecurityContextRepository;
+
+//@EnableWebFluxSecurity
+//@EnableReactiveMethodSecurity
+public class ThingsboardWebFluxSecurityConfig {
+
+ private static final String WS_TOKEN_BASED_AUTH_ENTRY_POINT = "/api/ws/**";
+
+ @Autowired
+ private ReactiveAuthenticationManager webfluxAuthenticationManager;
+
+ @Autowired
+ private ServerSecurityContextRepository jwtTokenSecurityContextRepository;
+
+ @Bean
+ public SecurityWebFilterChain securityWebFilterChain(ServerHttpSecurity http) {
+ return http
+ .cors()
+ .and()
+ .csrf().disable()
+ .formLogin().disable()
+ .httpBasic().disable()
+ .exceptionHandling()
+ .and()
+ .authenticationManager(webfluxAuthenticationManager)
+ .securityContextRepository(jwtTokenSecurityContextRepository)
+ .authorizeExchange()
+ .pathMatchers(WS_TOKEN_BASED_AUTH_ENTRY_POINT)
+ .authenticated()
+ .and()
+ .build();
+ }
+
+}
diff --git a/application/src/main/java/org/thingsboard/server/config/WebSocketConfiguration.java b/application/src/main/java/org/thingsboard/server/config/WebSocketConfiguration.java
index 59b7da2e76..4472db305e 100644
--- a/application/src/main/java/org/thingsboard/server/config/WebSocketConfiguration.java
+++ b/application/src/main/java/org/thingsboard/server/config/WebSocketConfiguration.java
@@ -21,38 +21,57 @@ import org.springframework.http.HttpStatus;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.security.core.Authentication;
+import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;
-import org.springframework.web.socket.WebSocketHandler;
-import org.springframework.web.socket.config.annotation.EnableWebSocket;
-import org.springframework.web.socket.config.annotation.WebSocketConfigurer;
-import org.springframework.web.socket.config.annotation.WebSocketHandlerRegistry;
-import org.springframework.web.socket.server.HandshakeInterceptor;
-import org.springframework.web.socket.server.standard.ServletServerContainerFactoryBean;
-import org.springframework.web.socket.server.support.HttpSessionHandshakeInterceptor;
+import org.springframework.security.web.server.context.WebSessionServerSecurityContextRepository;
+import org.springframework.web.reactive.HandlerMapping;
+import org.springframework.web.reactive.HandlerResult;
+import org.springframework.web.reactive.handler.SimpleUrlHandlerMapping;
+import org.springframework.web.reactive.socket.WebSocketHandler;
+import org.springframework.web.reactive.socket.server.support.HandshakeWebSocketService;
+import org.springframework.web.reactive.socket.server.support.WebSocketHandlerAdapter;
+import org.springframework.web.server.ServerWebExchange;
import org.thingsboard.server.common.data.exception.ThingsboardErrorCode;
import org.thingsboard.server.common.data.exception.ThingsboardException;
import org.thingsboard.server.controller.plugin.TbWebSocketHandler;
import org.thingsboard.server.service.security.model.SecurityUser;
+import reactor.core.publisher.Mono;
+import java.util.HashMap;
import java.util.Map;
@Configuration
-@EnableWebSocket
-public class WebSocketConfiguration implements WebSocketConfigurer {
+public class WebSocketConfiguration {
public static final String WS_PLUGIN_PREFIX = "/api/ws/plugins/";
public static final String WS_SECURITY_USER_ATTRIBUTE = "SECURITY_USER";
private static final String WS_PLUGIN_MAPPING = WS_PLUGIN_PREFIX + "**";
- @Bean
+/* @Bean
public ServletServerContainerFactoryBean createWebSocketContainer() {
ServletServerContainerFactoryBean container = new ServletServerContainerFactoryBean();
container.setMaxTextMessageBufferSize(32768);
container.setMaxBinaryMessageBufferSize(32768);
return container;
+ }*/
+
+ @Bean
+ public HandlerMapping handlerMapping() {
+ Map map = new HashMap<>();
+ map.put(WS_PLUGIN_MAPPING, wsHandler());
+
+ SimpleUrlHandlerMapping mapping = new SimpleUrlHandlerMapping();
+ mapping.setUrlMap(map);
+ mapping.setOrder(-1); // before annotated controllers
+ return mapping;
}
- @Override
+ @Bean
+ public WebSocketHandlerAdapter handlerAdapter() {
+ return new WebSocketHandlerAdapter();
+ }
+
+/* @Override
public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
registry.addHandler(wsHandler(), WS_PLUGIN_MAPPING).setAllowedOrigins("*")
.addInterceptors(new HttpSessionHandshakeInterceptor(), new HandshakeInterceptor() {
@@ -79,19 +98,19 @@ public class WebSocketConfiguration implements WebSocketConfigurer {
//Do nothing
}
});
- }
+ }*/
@Bean
public WebSocketHandler wsHandler() {
return new TbWebSocketHandler();
}
- protected SecurityUser getCurrentUser() throws ThingsboardException {
+/* protected SecurityUser getCurrentUser() throws ThingsboardException {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
if (authentication != null && authentication.getPrincipal() instanceof SecurityUser) {
return (SecurityUser) authentication.getPrincipal();
} else {
throw new ThingsboardException("You aren't authorized to perform this operation!", ThingsboardErrorCode.AUTHENTICATION);
}
- }
+ }*/
}
diff --git a/application/src/main/java/org/thingsboard/server/controller/plugin/TbWebSocketHandler.java b/application/src/main/java/org/thingsboard/server/controller/plugin/TbWebSocketHandler.java
index f579db8588..d01fc07e71 100644
--- a/application/src/main/java/org/thingsboard/server/controller/plugin/TbWebSocketHandler.java
+++ b/application/src/main/java/org/thingsboard/server/controller/plugin/TbWebSocketHandler.java
@@ -21,10 +21,9 @@ import org.springframework.beans.factory.annotation.Autowired;
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.TextMessage;
-import org.springframework.web.socket.WebSocketSession;
-import org.springframework.web.socket.handler.TextWebSocketHandler;
+import org.springframework.web.reactive.socket.CloseStatus;
+import org.springframework.web.reactive.socket.WebSocketHandler;
+import org.springframework.web.reactive.socket.WebSocketSession;
import org.thingsboard.server.common.data.exception.ThingsboardErrorCode;
import org.thingsboard.server.common.data.id.CustomerId;
import org.thingsboard.server.common.data.id.TenantId;
@@ -37,10 +36,13 @@ import org.thingsboard.server.service.telemetry.SessionEvent;
import org.thingsboard.server.service.telemetry.TelemetryWebSocketMsgEndpoint;
import org.thingsboard.server.service.telemetry.TelemetryWebSocketService;
import org.thingsboard.server.service.telemetry.TelemetryWebSocketSessionRef;
+import reactor.core.publisher.Flux;
+import reactor.core.publisher.Mono;
import java.io.IOException;
import java.net.URI;
import java.security.InvalidParameterException;
+import java.security.Principal;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
@@ -48,12 +50,12 @@ import java.util.concurrent.ConcurrentMap;
@Service
@Slf4j
-public class TbWebSocketHandler extends TextWebSocketHandler implements TelemetryWebSocketMsgEndpoint {
+public class TbWebSocketHandler implements WebSocketHandler, TelemetryWebSocketMsgEndpoint {
- private static final ConcurrentMap internalSessionMap = new ConcurrentHashMap<>();
- private static final ConcurrentMap externalSessionMap = new ConcurrentHashMap<>();
+ //private static final ConcurrentMap internalSessionMap = new ConcurrentHashMap<>();
+ // private static final ConcurrentMap externalSessionMap = new ConcurrentHashMap<>();
- @Autowired
+ /* @Autowired
private TelemetryWebSocketService webSocketService;
@Value("${server.ws.limits.max_sessions_per_tenant:0}")
@@ -90,8 +92,26 @@ public class TbWebSocketHandler extends TextWebSocketHandler implements Telemetr
} catch (IOException e) {
log.warn("IO error", e);
}
+ }*/
+
+ @Override
+ public Mono handle(WebSocketSession session) {
+ return session.receive()
+ .doOnNext(message -> {
+ Principal principal = session.getHandshakeInfo().getPrincipal().block();
+ if (principal instanceof SecurityUser) {
+ SecurityUser currentUser = (SecurityUser) principal;
+ log.info("[{}][{}] Processing {}", currentUser.getTenantId(), session.getId(), message.getPayloadAsText());
+ } else {
+ log.info("[{}] Principal {}", session.getId(), principal);
+ log.info("[{}] Processing {}", session.getId(), message.getPayloadAsText());
+ }
+ })
+ .then();
}
+
+/*
@Override
public void afterConnectionEstablished(WebSocketSession session) throws Exception {
super.afterConnectionEstablished(session);
@@ -173,11 +193,11 @@ public class TbWebSocketHandler extends TextWebSocketHandler implements Telemetr
this.session = session;
this.sessionRef = sessionRef;
}
- }
+ }*/
@Override
public void send(TelemetryWebSocketSessionRef sessionRef, int subscriptionId, String msg) throws IOException {
- String externalId = sessionRef.getSessionId();
+ /* String externalId = sessionRef.getSessionId();
log.debug("[{}] Processing {}", externalId, msg);
String internalId = externalSessionMap.get(externalId);
if (internalId != null) {
@@ -212,12 +232,12 @@ public class TbWebSocketHandler extends TextWebSocketHandler implements Telemetr
}
} else {
log.warn("[{}] Failed to find session by external id", externalId);
- }
+ }*/
}
@Override
public void close(TelemetryWebSocketSessionRef sessionRef, CloseStatus reason) throws IOException {
- String externalId = sessionRef.getSessionId();
+ /* String externalId = sessionRef.getSessionId();
log.debug("[{}] Processing close request", externalId);
String internalId = externalSessionMap.get(externalId);
if (internalId != null) {
@@ -229,10 +249,10 @@ public class TbWebSocketHandler extends TextWebSocketHandler implements Telemetr
}
} else {
log.warn("[{}] Failed to find session by external id", externalId);
- }
+ }*/
}
- private boolean checkLimits(WebSocketSession session, TelemetryWebSocketSessionRef sessionRef) throws Exception {
+ /*private boolean checkLimits(WebSocketSession session, TelemetryWebSocketSessionRef sessionRef) throws Exception {
String sessionId = session.getId();
if (maxSessionsPerTenant > 0) {
Set tenantSessions = tenantSessionsMap.computeIfAbsent(sessionRef.getSecurityCtx().getTenantId(), id -> ConcurrentHashMap.newKeySet());
@@ -322,6 +342,6 @@ public class TbWebSocketHandler extends TextWebSocketHandler implements Telemetr
}
}
}
- }
+ }*/
}
diff --git a/application/src/main/java/org/thingsboard/server/service/install/CassandraAbstractDatabaseSchemaService.java b/application/src/main/java/org/thingsboard/server/service/install/CassandraAbstractDatabaseSchemaService.java
index 10559ba2d2..f800ced5ae 100644
--- a/application/src/main/java/org/thingsboard/server/service/install/CassandraAbstractDatabaseSchemaService.java
+++ b/application/src/main/java/org/thingsboard/server/service/install/CassandraAbstractDatabaseSchemaService.java
@@ -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
diff --git a/application/src/main/java/org/thingsboard/server/service/install/CassandraDatabaseUpgradeService.java b/application/src/main/java/org/thingsboard/server/service/install/CassandraDatabaseUpgradeService.java
index a2aeefaecf..58021a6d67 100644
--- a/application/src/main/java/org/thingsboard/server/service/install/CassandraDatabaseUpgradeService.java
+++ b/application/src/main/java/org/thingsboard/server/service/install/CassandraDatabaseUpgradeService.java
@@ -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
diff --git a/application/src/main/java/org/thingsboard/server/service/mail/DefaultMailService.java b/application/src/main/java/org/thingsboard/server/service/mail/DefaultMailService.java
index 6c48ee144f..479c628d7e 100644
--- a/application/src/main/java/org/thingsboard/server/service/mail/DefaultMailService.java
+++ b/application/src/main/java/org/thingsboard/server/service/mail/DefaultMailService.java
@@ -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,7 @@ 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.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 +41,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 +130,7 @@ public class DefaultMailService implements MailService {
Map model = new HashMap();
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 +145,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 +160,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 +175,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 +190,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 +229,22 @@ public class DefaultMailService implements MailService {
}
}
+ private static String mergeTemplateIntoString(VelocityEngine velocityEngine, String templateLocation,
+ String encoding, Map 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 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) {
diff --git a/application/src/main/java/org/thingsboard/server/service/security/auth/webflux/WebfluxAuthenticationManager.java b/application/src/main/java/org/thingsboard/server/service/security/auth/webflux/WebfluxAuthenticationManager.java
new file mode 100644
index 0000000000..b2aeb0ded8
--- /dev/null
+++ b/application/src/main/java/org/thingsboard/server/service/security/auth/webflux/WebfluxAuthenticationManager.java
@@ -0,0 +1,48 @@
+/**
+ * Copyright © 2016-2018 The Thingsboard Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.thingsboard.server.service.security.auth.webflux;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.authentication.ReactiveAuthenticationManager;
+import org.springframework.security.core.Authentication;
+import org.springframework.stereotype.Component;
+import org.thingsboard.server.service.security.auth.JwtAuthenticationToken;
+import org.thingsboard.server.service.security.model.SecurityUser;
+import org.thingsboard.server.service.security.model.token.JwtTokenFactory;
+import org.thingsboard.server.service.security.model.token.RawAccessJwtToken;
+import reactor.core.publisher.Mono;
+
+@Component
+public class WebfluxAuthenticationManager implements ReactiveAuthenticationManager {
+
+ @Autowired
+ private JwtTokenFactory tokenFactory;
+
+ @Override
+ public Mono authenticate(Authentication authentication) {
+ try {
+ if (authentication.getCredentials() != null && authentication.getCredentials() instanceof RawAccessJwtToken) {
+ RawAccessJwtToken rawAccessToken = (RawAccessJwtToken) authentication.getCredentials();
+ SecurityUser securityUser = tokenFactory.parseAccessJwtToken(rawAccessToken);
+ JwtAuthenticationToken auth = new JwtAuthenticationToken(securityUser);
+ return Mono.just(auth);
+ }
+ return Mono.empty();
+ } catch (Exception e) {
+ return Mono.error(e);
+ }
+ }
+}
diff --git a/application/src/main/java/org/thingsboard/server/service/security/auth/webflux/jwt/JwtTokenSecurityContextRepository.java b/application/src/main/java/org/thingsboard/server/service/security/auth/webflux/jwt/JwtTokenSecurityContextRepository.java
new file mode 100644
index 0000000000..482830086e
--- /dev/null
+++ b/application/src/main/java/org/thingsboard/server/service/security/auth/webflux/jwt/JwtTokenSecurityContextRepository.java
@@ -0,0 +1,86 @@
+/**
+ * Copyright © 2016-2018 The Thingsboard Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.thingsboard.server.service.security.auth.webflux.jwt;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Qualifier;
+import org.springframework.http.server.reactive.ServerHttpRequest;
+import org.springframework.security.authentication.AuthenticationManager;
+import org.springframework.security.authentication.ReactiveAuthenticationManager;
+import org.springframework.security.core.Authentication;
+import org.springframework.security.core.context.SecurityContext;
+import org.springframework.security.core.context.SecurityContextImpl;
+import org.springframework.security.web.server.context.ServerSecurityContextRepository;
+import org.springframework.security.web.server.context.WebSessionServerSecurityContextRepository;
+import org.springframework.stereotype.Component;
+import org.springframework.util.StringUtils;
+import org.springframework.web.server.ServerWebExchange;
+import org.thingsboard.server.config.ThingsboardSecurityConfiguration;
+import org.thingsboard.server.service.security.auth.JwtAuthenticationToken;
+import org.thingsboard.server.service.security.auth.jwt.extractor.TokenExtractor;
+import org.thingsboard.server.service.security.model.token.RawAccessJwtToken;
+import reactor.core.publisher.Mono;
+
+import java.util.List;
+
+@Component
+public class JwtTokenSecurityContextRepository implements ServerSecurityContextRepository {
+
+ public static final String DEFAULT_SPRING_SECURITY_CONTEXT_ATTR_NAME = "SPRING_SECURITY_CONTEXT";
+
+ @Autowired
+ private ReactiveAuthenticationManager webfluxAuthenticationManager;
+
+ @Override
+ public Mono save(ServerWebExchange exchange, SecurityContext context) {
+ return exchange.getSession()
+ .doOnNext(session -> {
+ if (context == null) {
+ session.getAttributes().remove(WebSessionServerSecurityContextRepository.DEFAULT_SPRING_SECURITY_CONTEXT_ATTR_NAME);
+ } else {
+ session.getAttributes().put(WebSessionServerSecurityContextRepository.DEFAULT_SPRING_SECURITY_CONTEXT_ATTR_NAME, context);
+ }
+ })
+ .flatMap(session -> session.changeSessionId());
+ }
+
+ @Override
+ public Mono load(ServerWebExchange exchange) {
+ ServerHttpRequest request = exchange.getRequest();
+ String token = extractTokenFromQuery(request);
+ if (!StringUtils.isEmpty(token)) {
+ RawAccessJwtToken rawToken = new RawAccessJwtToken(token);
+ Authentication auth = new JwtAuthenticationToken(rawToken);
+ return this.webfluxAuthenticationManager.authenticate(auth).map((authentication) -> {
+ return new SecurityContextImpl(authentication);
+ });
+ } else {
+ return Mono.empty();
+ }
+ }
+
+ private String extractTokenFromQuery(ServerHttpRequest request) {
+ String token = null;
+ if (request.getQueryParams() != null) {
+ List tokenParamValue = request.getQueryParams().get(ThingsboardSecurityConfiguration.JWT_TOKEN_QUERY_PARAM);
+ if (tokenParamValue != null && !tokenParamValue.isEmpty()) {
+ token = tokenParamValue.get(0);
+ }
+ }
+ return token;
+ }
+
+}
diff --git a/application/src/main/java/org/thingsboard/server/service/telemetry/DefaultTelemetryWebSocketService.java b/application/src/main/java/org/thingsboard/server/service/telemetry/DefaultTelemetryWebSocketService.java
index 6b87e033fc..883eba8bc7 100644
--- a/application/src/main/java/org/thingsboard/server/service/telemetry/DefaultTelemetryWebSocketService.java
+++ b/application/src/main/java/org/thingsboard/server/service/telemetry/DefaultTelemetryWebSocketService.java
@@ -26,8 +26,7 @@ import org.springframework.beans.factory.annotation.Autowired;
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.springframework.web.reactive.socket.CloseStatus;
import org.thingsboard.server.common.data.DataConstants;
import org.thingsboard.server.common.data.id.CustomerId;
import org.thingsboard.server.common.data.id.EntityId;
diff --git a/application/src/main/java/org/thingsboard/server/service/telemetry/TelemetryWebSocketMsgEndpoint.java b/application/src/main/java/org/thingsboard/server/service/telemetry/TelemetryWebSocketMsgEndpoint.java
index b73aadff1b..0b097167ad 100644
--- a/application/src/main/java/org/thingsboard/server/service/telemetry/TelemetryWebSocketMsgEndpoint.java
+++ b/application/src/main/java/org/thingsboard/server/service/telemetry/TelemetryWebSocketMsgEndpoint.java
@@ -15,7 +15,7 @@
*/
package org.thingsboard.server.service.telemetry;
-import org.springframework.web.socket.CloseStatus;
+import org.springframework.web.reactive.socket.CloseStatus;
import java.io.IOException;
diff --git a/application/src/main/resources/thingsboard.yml b/application/src/main/resources/thingsboard.yml
index 9f60fb6a90..1512961c8c 100644
--- a/application/src/main/resources/thingsboard.yml
+++ b/application/src/main/resources/thingsboard.yml
@@ -282,11 +282,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:
@@ -320,7 +322,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
@@ -329,7 +331,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}"
diff --git a/application/src/test/java/org/thingsboard/server/mqtt/rpc/AbstractMqttServerSideRpcIntegrationTest.java b/application/src/test/java/org/thingsboard/server/mqtt/rpc/AbstractMqttServerSideRpcIntegrationTest.java
index 7453682644..9e3463672d 100644
--- a/application/src/test/java/org/thingsboard/server/mqtt/rpc/AbstractMqttServerSideRpcIntegrationTest.java
+++ b/application/src/test/java/org/thingsboard/server/mqtt/rpc/AbstractMqttServerSideRpcIntegrationTest.java
@@ -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(),
diff --git a/dao/src/main/java/org/thingsboard/server/dao/DaoUtil.java b/dao/src/main/java/org/thingsboard/server/dao/DaoUtil.java
index c7bcfbcd33..1031215204 100644
--- a/dao/src/main/java/org/thingsboard/server/dao/DaoUtil.java
+++ b/dao/src/main/java/org/thingsboard/server/dao/DaoUtil.java
@@ -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 getData(Optional extends ToData> 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) {
diff --git a/dao/src/main/java/org/thingsboard/server/dao/audit/AuditLogServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/audit/AuditLogServiceImpl.java
index 24c6a274f1..34ae9d306a 100644
--- a/dao/src/main/java/org/thingsboard/server/dao/audit/AuditLogServiceImpl.java
+++ b/dao/src/main/java/org/thingsboard/server/dao/audit/AuditLogServiceImpl.java
@@ -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();
diff --git a/dao/src/main/java/org/thingsboard/server/dao/audit/CassandraAuditLogDao.java b/dao/src/main/java/org/thingsboard/server/dao/audit/CassandraAuditLogDao.java
index f2b2973996..ccc1880a12 100644
--- a/dao/src/main/java/org/thingsboard/server/dao/audit/CassandraAuditLogDao.java
+++ b/dao/src/main/java/org/thingsboard/server/dao/audit/CassandraAuditLogDao.java
@@ -88,11 +88,11 @@ public class CassandraAuditLogDao extends CassandraAbstractSearchTimeDao redisTemplate(RedisConnectionFactory cf) {
- RedisTemplate 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);
+ }
}
diff --git a/dao/src/main/java/org/thingsboard/server/dao/cassandra/CassandraCluster.java b/dao/src/main/java/org/thingsboard/server/dao/cassandra/CassandraCluster.java
index 19409ad146..c0c4853387 100644
--- a/dao/src/main/java/org/thingsboard/server/dao/cassandra/CassandraCluster.java
+++ b/dao/src/main/java/org/thingsboard/server/dao/cassandra/CassandraCluster.java
@@ -21,7 +21,7 @@ import org.thingsboard.server.dao.util.NoSqlAnyDao;
import javax.annotation.PostConstruct;
-@Component
+@Component("CassandraCluster")
@NoSqlAnyDao
public class CassandraCluster extends AbstractCassandraCluster {
diff --git a/dao/src/main/java/org/thingsboard/server/dao/cassandra/CassandraInstallCluster.java b/dao/src/main/java/org/thingsboard/server/dao/cassandra/CassandraInstallCluster.java
index 247a204ee5..718a4fa299 100644
--- a/dao/src/main/java/org/thingsboard/server/dao/cassandra/CassandraInstallCluster.java
+++ b/dao/src/main/java/org/thingsboard/server/dao/cassandra/CassandraInstallCluster.java
@@ -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 {
diff --git a/dao/src/main/java/org/thingsboard/server/dao/nosql/CassandraAbstractDao.java b/dao/src/main/java/org/thingsboard/server/dao/nosql/CassandraAbstractDao.java
index 1a419df9a1..ebcc4f61dd 100644
--- a/dao/src/main/java/org/thingsboard/server/dao/nosql/CassandraAbstractDao.java
+++ b/dao/src/main/java/org/thingsboard/server/dao/nosql/CassandraAbstractDao.java
@@ -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 preparedStatementMap = new ConcurrentHashMap<>();
diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/JpaAbstractDao.java b/dao/src/main/java/org/thingsboard/server/dao/sql/JpaAbstractDao.java
index 987eabe738..4c8eb372e5 100644
--- a/dao/src/main/java/org/thingsboard/server/dao/sql/JpaAbstractDao.java
+++ b/dao/src/main/java/org/thingsboard/server/dao/sql/JpaAbstractDao.java
@@ -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, D>
@Override
public D findById(TenantId tenantId, UUID key) {
log.debug("Get entity by key {}", key);
- E entity = getCrudRepository().findOne(fromTimeUUID(key));
+ Optional entity = getCrudRepository().findById(fromTimeUUID(key));
return DaoUtil.getData(entity);
}
@Override
public ListenableFuture 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
diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/attributes/JpaAttributeDao.java b/dao/src/main/java/org/thingsboard/server/dao/sql/attributes/JpaAttributeDao.java
index 2193646ec9..84ef8b88a8 100644
--- a/dao/src/main/java/org/thingsboard/server/dao/sql/attributes/JpaAttributeDao.java
+++ b/dao/src/main/java/org/thingsboard/server/dao/sql/attributes/JpaAttributeDao.java
@@ -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;
});
}
diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/component/JpaBaseComponentDescriptorDao.java b/dao/src/main/java/org/thingsboard/server/dao/sql/component/JpaBaseComponentDescriptorDao.java
index 47b006e3b1..56b0ec7e7f 100644
--- a/dao/src/main/java/org/thingsboard/server/dao/sql/component/JpaBaseComponentDescriptorDao.java
+++ b/dao/src/main/java/org/thingsboard/server/dao/sql/component/JpaBaseComponentDescriptorDao.java
@@ -66,7 +66,7 @@ public class JpaBaseComponentDescriptorDao extends JpaAbstractSearchTextDao 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 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;
}
diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/relation/RelationRepository.java b/dao/src/main/java/org/thingsboard/server/dao/sql/relation/RelationRepository.java
index 60c6a0e9d7..cf1e2b22b0 100644
--- a/dao/src/main/java/org/thingsboard/server/dao/sql/relation/RelationRepository.java
+++ b/dao/src/main/java/org/thingsboard/server/dao/sql/relation/RelationRepository.java
@@ -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);
diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/timeseries/JpaTimeseriesDao.java b/dao/src/main/java/org/thingsboard/server/dao/sql/timeseries/JpaTimeseriesDao.java
index 312014861f..7fc28b0ec3 100644
--- a/dao/src/main/java/org/thingsboard/server/dao/sql/timeseries/JpaTimeseriesDao.java
+++ b/dao/src/main/java/org/thingsboard/server/dao/sql/timeseries/JpaTimeseriesDao.java
@@ -258,10 +258,10 @@ public class JpaTimeseriesDao extends JpaAbstractDaoListeningExecutorService imp
entityId.getEntityType(),
fromTimeUUID(entityId.getId()),
key);
- TsKvLatestEntity entry = tsKvLatestRepository.findOne(compositeKey);
+ Optional 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));
}
diff --git a/dao/src/test/resources/application-test.properties b/dao/src/test/resources/application-test.properties
index a285676f08..c873c908db 100644
--- a/dao/src/test/resources/application-test.properties
+++ b/dao/src/test/resources/application-test.properties
@@ -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
diff --git a/dao/src/test/resources/sql-test.properties b/dao/src/test/resources/sql-test.properties
index 3357425fce..745aa9e1e0 100644
--- a/dao/src/test/resources/sql-test.properties
+++ b/dao/src/test/resources/sql-test.properties
@@ -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
diff --git a/docker/docker-compose.yml b/docker/docker-compose.yml
index 944ed66880..b89a214b39 100644
--- a/docker/docker-compose.yml
+++ b/docker/docker-compose.yml
@@ -23,6 +23,9 @@ services:
image: "zookeeper:3.5"
ports:
- "2181"
+ environment:
+ ZOO_MY_ID: 1
+ ZOO_SERVERS: server.1=zookeeper:2888:3888;zookeeper:2181
kafka:
restart: always
image: "wurstmeister/kafka"
diff --git a/pom.xml b/pom.xml
index 00c9c28567..27cb40121b 100755
--- a/pom.xml
+++ b/pom.xml
@@ -29,10 +29,10 @@
${basedir}
- 1.4.3.RELEASE
- 4.3.4.RELEASE
- 4.2.0.RELEASE
- 1.8.10.RELEASE
+ 2.1.0.RELEASE
+ 5.1.2.RELEASE
+ 5.1.1.RELEASE
+ 2.1.2.RELEASE
2.9.0
0.7.0
2.2.0
@@ -41,8 +41,8 @@
1.2.3
1.9.5
0.10
- 3.5.0
- 3.3.0.2
+ 3.6.0
+ 3.5.0.1
1.2.7
21.0
2.6.1
@@ -50,7 +50,7 @@
1.5.0
2.5
1.4
- 2.8.11.1
+ 2.9.7
2.2.6
2.11
2.4.2
@@ -58,13 +58,15 @@
2.6.2
1.7
2.0
+ 2.7.7
+ 1.23
1.4.3
4.0.1
- 3.0.2
- 1.12.0
+ 3.6.1
+ 1.16.1
1.16.18
1.1.0
- 4.1.22.Final
+ 4.1.30.Final
1.5.0
4.8.0
2.19.1
@@ -410,7 +412,7 @@
org.springframework.boot
- spring-boot-starter-websocket
+ spring-boot-starter-webflux
${spring-boot.version}
@@ -485,20 +487,16 @@
org.apache.velocity
velocity-tools
${velocity-tools.version}
-
-
- javax.servlet
- servlet-api
-
-
- dom4j
- dom4j
-
-
- antlr
- antlr
-
-
+
+
+ antlr
+ antlr
+ ${antlr.version}
+
+
+ org.yaml
+ snakeyaml
+ ${snakeyaml.version}
com.rabbitmq