thingsboard-developers
Changes
dao/src/main/java/org/thingsboard/server/dao/sql/JpaAbstractDaoListeningExecutorService.java 1(+1 -0)
transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/session/GatewayDeviceSessionCtx.java 44(+25 -19)
transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/session/GatewaySessionCtx.java 22(+14 -8)
ui/src/app/home/home-links.controller.js 39(+37 -2)
ui/src/app/home/home-links.tpl.html 16(+8 -8)
Details
diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/JpaAbstractDaoListeningExecutorService.java b/dao/src/main/java/org/thingsboard/server/dao/sql/JpaAbstractDaoListeningExecutorService.java
index 7c34aa1..7828267 100644
--- a/dao/src/main/java/org/thingsboard/server/dao/sql/JpaAbstractDaoListeningExecutorService.java
+++ b/dao/src/main/java/org/thingsboard/server/dao/sql/JpaAbstractDaoListeningExecutorService.java
@@ -22,6 +22,7 @@ import javax.annotation.PreDestroy;
import java.util.concurrent.Executors;
public abstract class JpaAbstractDaoListeningExecutorService {
+
protected ListeningExecutorService service = MoreExecutors.listeningDecorator(Executors.newFixedThreadPool(10));
@PreDestroy
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 7fddfae..170f9a6 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
@@ -17,9 +17,7 @@ package org.thingsboard.server.dao.sql.timeseries;
import com.google.common.base.Function;
import com.google.common.collect.Lists;
-import com.google.common.util.concurrent.Futures;
-import com.google.common.util.concurrent.ListenableFuture;
-import com.google.common.util.concurrent.SettableFuture;
+import com.google.common.util.concurrent.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.PageRequest;
@@ -36,10 +34,12 @@ import org.thingsboard.server.dao.timeseries.TimeseriesDao;
import org.thingsboard.server.dao.util.SqlDao;
import javax.annotation.Nullable;
+import javax.annotation.PreDestroy;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.Executors;
import java.util.stream.Collectors;
import static org.thingsboard.server.common.data.UUIDConverter.fromTimeUUID;
@@ -50,6 +50,8 @@ import static org.thingsboard.server.common.data.UUIDConverter.fromTimeUUID;
@SqlDao
public class JpaTimeseriesDao extends JpaAbstractDaoListeningExecutorService implements TimeseriesDao {
+ private ListeningExecutorService insertService = MoreExecutors.listeningDecorator(Executors.newSingleThreadExecutor());
+
@Autowired
private TsKvRepository tsKvRepository;
@@ -232,7 +234,8 @@ public class JpaTimeseriesDao extends JpaAbstractDaoListeningExecutorService imp
entity.setDoubleValue(tsKvEntry.getDoubleValue().orElse(null));
entity.setLongValue(tsKvEntry.getLongValue().orElse(null));
entity.setBooleanValue(tsKvEntry.getBooleanValue().orElse(null));
- return service.submit(() -> {
+ log.trace("Saving entity: " + entity);
+ return insertService.submit(() -> {
tsKvRepository.save(entity);
return null;
});
@@ -240,7 +243,7 @@ public class JpaTimeseriesDao extends JpaAbstractDaoListeningExecutorService imp
@Override
public ListenableFuture<Void> savePartition(EntityId entityId, long tsKvEntryTs, String key, long ttl) {
- return service.submit(() -> null);
+ return insertService.submit(() -> null);
}
@Override
@@ -254,10 +257,15 @@ public class JpaTimeseriesDao extends JpaAbstractDaoListeningExecutorService imp
latestEntity.setDoubleValue(tsKvEntry.getDoubleValue().orElse(null));
latestEntity.setLongValue(tsKvEntry.getLongValue().orElse(null));
latestEntity.setBooleanValue(tsKvEntry.getBooleanValue().orElse(null));
- return service.submit(() -> {
+ return insertService.submit(() -> {
tsKvLatestRepository.save(latestEntity);
return null;
});
}
+ @PreDestroy
+ void onDestroy() {
+ insertService.shutdown();
+ }
+
}
diff --git a/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/session/GatewayDeviceSessionCtx.java b/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/session/GatewayDeviceSessionCtx.java
index 7b527df..7bed03a 100644
--- a/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/session/GatewayDeviceSessionCtx.java
+++ b/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/session/GatewayDeviceSessionCtx.java
@@ -16,6 +16,7 @@
package org.thingsboard.server.transport.mqtt.session;
import com.google.gson.Gson;
+import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import io.netty.buffer.ByteBuf;
@@ -24,6 +25,7 @@ import io.netty.buffer.UnpooledByteBufAllocator;
import io.netty.handler.codec.mqtt.*;
import org.thingsboard.server.common.data.Device;
import org.thingsboard.server.common.data.id.SessionId;
+import org.thingsboard.server.common.data.kv.AttributeKvEntry;
import org.thingsboard.server.common.data.kv.KvEntry;
import org.thingsboard.server.common.msg.core.*;
import org.thingsboard.server.common.msg.kv.AttributesKVMsg;
@@ -35,6 +37,7 @@ import org.thingsboard.server.transport.mqtt.MqttTopics;
import org.thingsboard.server.transport.mqtt.MqttTransportHandler;
import java.nio.charset.Charset;
+import java.util.List;
import java.util.Optional;
import java.util.concurrent.atomic.AtomicInteger;
@@ -83,7 +86,7 @@ public class GatewayDeviceSessionCtx extends DeviceAwareSessionContext {
if (responseMsg.isSuccess()) {
MsgType requestMsgType = responseMsg.getRequestMsgType();
Integer requestId = responseMsg.getRequestId();
- if (requestMsgType == MsgType.POST_ATTRIBUTES_REQUEST || requestMsgType == MsgType.POST_TELEMETRY_REQUEST) {
+ if (requestId >= 0 && requestMsgType == MsgType.POST_ATTRIBUTES_REQUEST || requestMsgType == MsgType.POST_TELEMETRY_REQUEST) {
return Optional.of(MqttTransportHandler.createMqttPubAckMsg(requestId));
}
}
@@ -135,40 +138,43 @@ public class GatewayDeviceSessionCtx extends DeviceAwareSessionContext {
if (responseData.isPresent()) {
AttributesKVMsg msg = responseData.get();
if (msg.getClientAttributes() != null) {
- msg.getClientAttributes().forEach(v -> addValueToJson(result, "value", v));
+ addValues(result, msg.getClientAttributes());
}
if (msg.getSharedAttributes() != null) {
- msg.getSharedAttributes().forEach(v -> addValueToJson(result, "value", v));
+ addValues(result, msg.getSharedAttributes());
}
}
return createMqttPublishMsg(topic, result);
}
+ private void addValues(JsonObject result, List<AttributeKvEntry> kvList) {
+ if (kvList.size() == 1) {
+ addValueToJson(result, "value", kvList.get(0));
+ } else {
+ JsonObject values;
+ if (result.has("values")) {
+ values = result.get("values").getAsJsonObject();
+ } else {
+ values = new JsonObject();
+ result.add("values", values);
+ }
+ kvList.forEach(value -> addValueToJson(values, value.getKey(), value));
+ }
+ }
+
private void addValueToJson(JsonObject json, String name, KvEntry entry) {
switch (entry.getDataType()) {
case BOOLEAN:
- Optional<Boolean> booleanValue = entry.getBooleanValue();
- if (booleanValue.isPresent()) {
- json.addProperty(name, booleanValue.get());
- }
+ entry.getBooleanValue().ifPresent(aBoolean -> json.addProperty(name, aBoolean));
break;
case STRING:
- Optional<String> stringValue = entry.getStrValue();
- if (stringValue.isPresent()) {
- json.addProperty(name, stringValue.get());
- }
+ entry.getStrValue().ifPresent(aString -> json.addProperty(name, aString));
break;
case DOUBLE:
- Optional<Double> doubleValue = entry.getDoubleValue();
- if (doubleValue.isPresent()) {
- json.addProperty(name, doubleValue.get());
- }
+ entry.getDoubleValue().ifPresent(aDouble -> json.addProperty(name, aDouble));
break;
case LONG:
- Optional<Long> longValue = entry.getLongValue();
- if (longValue.isPresent()) {
- json.addProperty(name, longValue.get());
- }
+ entry.getLongValue().ifPresent(aLong -> json.addProperty(name, aLong));
break;
}
}
diff --git a/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/session/GatewaySessionCtx.java b/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/session/GatewaySessionCtx.java
index 00d1f0c..5bccf49 100644
--- a/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/session/GatewaySessionCtx.java
+++ b/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/session/GatewaySessionCtx.java
@@ -41,10 +41,7 @@ import org.thingsboard.server.dao.relation.RelationService;
import org.thingsboard.server.transport.mqtt.MqttTransportHandler;
import org.thingsboard.server.transport.mqtt.adaptors.JsonMqttAdaptor;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Optional;
+import java.util.*;
import java.util.stream.Collectors;
import static org.thingsboard.server.transport.mqtt.adaptors.JsonMqttAdaptor.validateJsonPayload;
@@ -193,13 +190,22 @@ public class GatewaySessionCtx {
int requestId = jsonObj.get("id").getAsInt();
String deviceName = jsonObj.get(DEVICE_PROPERTY).getAsString();
boolean clientScope = jsonObj.get("client").getAsBoolean();
- String key = jsonObj.get("key").getAsString();
+ Set<String> keys;
+ if (jsonObj.has("key")) {
+ keys = Collections.singleton(jsonObj.get("key").getAsString());
+ } else {
+ JsonArray keysArray = jsonObj.get("keys").getAsJsonArray();
+ keys = new HashSet<>();
+ for (JsonElement keyObj : keysArray) {
+ keys.add(keyObj.getAsString());
+ }
+ }
BasicGetAttributesRequest request;
if (clientScope) {
- request = new BasicGetAttributesRequest(requestId, Collections.singleton(key), null);
+ request = new BasicGetAttributesRequest(requestId, keys, null);
} else {
- request = new BasicGetAttributesRequest(requestId, null, Collections.singleton(key));
+ request = new BasicGetAttributesRequest(requestId, null, keys);
}
GatewayDeviceSessionCtx deviceSessionCtx = devices.get(deviceName);
processor.process(new BasicToDeviceActorSessionMsg(deviceSessionCtx.getDevice(),
@@ -251,7 +257,7 @@ public class GatewaySessionCtx {
}
private void ack(MqttPublishMessage msg) {
- if(msg.variableHeader().messageId() > 0) {
+ if (msg.variableHeader().messageId() > 0) {
writeAndFlush(MqttTransportHandler.createMqttPubAckMsg(msg.variableHeader().messageId()));
}
}
ui/src/app/home/home-links.controller.js 39(+37 -2)
diff --git a/ui/src/app/home/home-links.controller.js b/ui/src/app/home/home-links.controller.js
index 799a0bc..32ae091 100644
--- a/ui/src/app/home/home-links.controller.js
+++ b/ui/src/app/home/home-links.controller.js
@@ -17,7 +17,42 @@
import './home-links.scss';
/*@ngInject*/
-export default function HomeLinksController($scope, menu) {
+export default function HomeLinksController($scope, $mdMedia, menu) {
+
var vm = this;
- vm.model = menu.getHomeSections();
+
+ vm.sectionColspan = sectionColspan;
+
+ $scope.$watch(function() { return $mdMedia('lg'); }, function() {
+ updateColumnCount();
+ });
+
+ $scope.$watch(function() { return $mdMedia('gt-lg'); }, function() {
+ updateColumnCount();
+ });
+
+ updateColumnCount();
+
+ menu.getHomeSections().then((homeSections) => {
+ vm.model = homeSections;
+ });
+
+ function updateColumnCount() {
+ vm.cols = 2;
+ if ($mdMedia('lg')) {
+ vm.cols = 3;
+ }
+ if ($mdMedia('gt-lg')) {
+ vm.cols = 4;
+ }
+ }
+
+ function sectionColspan(section) {
+ var colspan = vm.cols;
+ if (section && section.places && section.places.length <= colspan) {
+ colspan = section.places.length;
+ }
+ return colspan;
+ }
+
}
ui/src/app/home/home-links.tpl.html 16(+8 -8)
diff --git a/ui/src/app/home/home-links.tpl.html b/ui/src/app/home/home-links.tpl.html
index e27f20a..f0e5582 100644
--- a/ui/src/app/home/home-links.tpl.html
+++ b/ui/src/app/home/home-links.tpl.html
@@ -15,8 +15,8 @@
limitations under the License.
-->
-<md-grid-list class="tb-home-links" md-cols="2" md-cols-lg="3" md-cols-gt-lg="4" md-row-height="280px">
- <md-grid-tile md-colspan="2" md-colspan-gt-sm="{{section.places.length}}" ng-repeat="section in vm.model">
+<md-grid-list class="tb-home-links" md-cols="{{vm.cols}}" md-row-height="280px">
+ <md-grid-tile md-colspan="2" md-colspan-gt-sm="{{vm.sectionColspan(section)}}" ng-repeat="section in vm.model">
<md-card style='width: 100%;'>
<md-card-title>
<md-card-title-text>
@@ -25,12 +25,12 @@
</md-card-title>
<md-card-content>
<md-grid-list md-row-height="170px" md-cols="{{section.places.length}}" md-cols-gt-md="{{section.places.length}}">
- <md-grid-tile class="card-tile" ng-repeat="place in section.places">
- <md-button class="tb-card-button md-raised md-primary" layout="column" ui-sref="{{place.state}}">
- <md-icon class="material-icons tb-md-96" aria-label="{{place.icon}}">{{place.icon}}</md-icon>
- <span translate>{{place.name}}</span>
- </md-button>
- </md-grid-tile>
+ <md-grid-tile class="card-tile" ng-repeat="place in section.places">
+ <md-button class="tb-card-button md-raised md-primary" layout="column" ui-sref="{{place.state}}">
+ <md-icon class="material-icons tb-md-96" aria-label="{{place.icon}}">{{place.icon}}</md-icon>
+ <span translate>{{place.name}}</span>
+ </md-button>
+ </md-grid-tile>
</md-grid-list>
</md-card-content>
</md-card>