Commit a075d9591dda83281934b13e83c3169445093e38

Authored by Andrew Shvayka
2 parents ae85dd66 fbc83a72

Merge branch 'master' into feature/TB-74

... ... @@ -22,6 +22,7 @@ import javax.annotation.PreDestroy;
22 22 import java.util.concurrent.Executors;
23 23
24 24 public abstract class JpaAbstractDaoListeningExecutorService {
  25 +
25 26 protected ListeningExecutorService service = MoreExecutors.listeningDecorator(Executors.newFixedThreadPool(10));
26 27
27 28 @PreDestroy
... ...
... ... @@ -17,9 +17,7 @@ package org.thingsboard.server.dao.sql.timeseries;
17 17
18 18 import com.google.common.base.Function;
19 19 import com.google.common.collect.Lists;
20   -import com.google.common.util.concurrent.Futures;
21   -import com.google.common.util.concurrent.ListenableFuture;
22   -import com.google.common.util.concurrent.SettableFuture;
  20 +import com.google.common.util.concurrent.*;
23 21 import lombok.extern.slf4j.Slf4j;
24 22 import org.springframework.beans.factory.annotation.Autowired;
25 23 import org.springframework.data.domain.PageRequest;
... ... @@ -36,10 +34,12 @@ import org.thingsboard.server.dao.timeseries.TimeseriesDao;
36 34 import org.thingsboard.server.dao.util.SqlDao;
37 35
38 36 import javax.annotation.Nullable;
  37 +import javax.annotation.PreDestroy;
39 38 import java.util.ArrayList;
40 39 import java.util.List;
41 40 import java.util.Optional;
42 41 import java.util.concurrent.CompletableFuture;
  42 +import java.util.concurrent.Executors;
43 43 import java.util.stream.Collectors;
44 44
45 45 import static org.thingsboard.server.common.data.UUIDConverter.fromTimeUUID;
... ... @@ -50,6 +50,8 @@ import static org.thingsboard.server.common.data.UUIDConverter.fromTimeUUID;
50 50 @SqlDao
51 51 public class JpaTimeseriesDao extends JpaAbstractDaoListeningExecutorService implements TimeseriesDao {
52 52
  53 + private ListeningExecutorService insertService = MoreExecutors.listeningDecorator(Executors.newSingleThreadExecutor());
  54 +
53 55 @Autowired
54 56 private TsKvRepository tsKvRepository;
55 57
... ... @@ -232,7 +234,8 @@ public class JpaTimeseriesDao extends JpaAbstractDaoListeningExecutorService imp
232 234 entity.setDoubleValue(tsKvEntry.getDoubleValue().orElse(null));
233 235 entity.setLongValue(tsKvEntry.getLongValue().orElse(null));
234 236 entity.setBooleanValue(tsKvEntry.getBooleanValue().orElse(null));
235   - return service.submit(() -> {
  237 + log.trace("Saving entity: " + entity);
  238 + return insertService.submit(() -> {
236 239 tsKvRepository.save(entity);
237 240 return null;
238 241 });
... ... @@ -240,7 +243,7 @@ public class JpaTimeseriesDao extends JpaAbstractDaoListeningExecutorService imp
240 243
241 244 @Override
242 245 public ListenableFuture<Void> savePartition(EntityId entityId, long tsKvEntryTs, String key, long ttl) {
243   - return service.submit(() -> null);
  246 + return insertService.submit(() -> null);
244 247 }
245 248
246 249 @Override
... ... @@ -254,10 +257,15 @@ public class JpaTimeseriesDao extends JpaAbstractDaoListeningExecutorService imp
254 257 latestEntity.setDoubleValue(tsKvEntry.getDoubleValue().orElse(null));
255 258 latestEntity.setLongValue(tsKvEntry.getLongValue().orElse(null));
256 259 latestEntity.setBooleanValue(tsKvEntry.getBooleanValue().orElse(null));
257   - return service.submit(() -> {
  260 + return insertService.submit(() -> {
258 261 tsKvLatestRepository.save(latestEntity);
259 262 return null;
260 263 });
261 264 }
262 265
  266 + @PreDestroy
  267 + void onDestroy() {
  268 + insertService.shutdown();
  269 + }
  270 +
263 271 }
... ...
... ... @@ -16,6 +16,7 @@
16 16 package org.thingsboard.server.transport.mqtt.session;
17 17
18 18 import com.google.gson.Gson;
  19 +import com.google.gson.JsonArray;
19 20 import com.google.gson.JsonElement;
20 21 import com.google.gson.JsonObject;
21 22 import io.netty.buffer.ByteBuf;
... ... @@ -24,6 +25,7 @@ import io.netty.buffer.UnpooledByteBufAllocator;
24 25 import io.netty.handler.codec.mqtt.*;
25 26 import org.thingsboard.server.common.data.Device;
26 27 import org.thingsboard.server.common.data.id.SessionId;
  28 +import org.thingsboard.server.common.data.kv.AttributeKvEntry;
27 29 import org.thingsboard.server.common.data.kv.KvEntry;
28 30 import org.thingsboard.server.common.msg.core.*;
29 31 import org.thingsboard.server.common.msg.kv.AttributesKVMsg;
... ... @@ -35,6 +37,7 @@ import org.thingsboard.server.transport.mqtt.MqttTopics;
35 37 import org.thingsboard.server.transport.mqtt.MqttTransportHandler;
36 38
37 39 import java.nio.charset.Charset;
  40 +import java.util.List;
38 41 import java.util.Optional;
39 42 import java.util.concurrent.atomic.AtomicInteger;
40 43
... ... @@ -83,7 +86,7 @@ public class GatewayDeviceSessionCtx extends DeviceAwareSessionContext {
83 86 if (responseMsg.isSuccess()) {
84 87 MsgType requestMsgType = responseMsg.getRequestMsgType();
85 88 Integer requestId = responseMsg.getRequestId();
86   - if (requestMsgType == MsgType.POST_ATTRIBUTES_REQUEST || requestMsgType == MsgType.POST_TELEMETRY_REQUEST) {
  89 + if (requestId >= 0 && requestMsgType == MsgType.POST_ATTRIBUTES_REQUEST || requestMsgType == MsgType.POST_TELEMETRY_REQUEST) {
87 90 return Optional.of(MqttTransportHandler.createMqttPubAckMsg(requestId));
88 91 }
89 92 }
... ... @@ -135,40 +138,43 @@ public class GatewayDeviceSessionCtx extends DeviceAwareSessionContext {
135 138 if (responseData.isPresent()) {
136 139 AttributesKVMsg msg = responseData.get();
137 140 if (msg.getClientAttributes() != null) {
138   - msg.getClientAttributes().forEach(v -> addValueToJson(result, "value", v));
  141 + addValues(result, msg.getClientAttributes());
139 142 }
140 143 if (msg.getSharedAttributes() != null) {
141   - msg.getSharedAttributes().forEach(v -> addValueToJson(result, "value", v));
  144 + addValues(result, msg.getSharedAttributes());
142 145 }
143 146 }
144 147 return createMqttPublishMsg(topic, result);
145 148 }
146 149
  150 + private void addValues(JsonObject result, List<AttributeKvEntry> kvList) {
  151 + if (kvList.size() == 1) {
  152 + addValueToJson(result, "value", kvList.get(0));
  153 + } else {
  154 + JsonObject values;
  155 + if (result.has("values")) {
  156 + values = result.get("values").getAsJsonObject();
  157 + } else {
  158 + values = new JsonObject();
  159 + result.add("values", values);
  160 + }
  161 + kvList.forEach(value -> addValueToJson(values, value.getKey(), value));
  162 + }
  163 + }
  164 +
147 165 private void addValueToJson(JsonObject json, String name, KvEntry entry) {
148 166 switch (entry.getDataType()) {
149 167 case BOOLEAN:
150   - Optional<Boolean> booleanValue = entry.getBooleanValue();
151   - if (booleanValue.isPresent()) {
152   - json.addProperty(name, booleanValue.get());
153   - }
  168 + entry.getBooleanValue().ifPresent(aBoolean -> json.addProperty(name, aBoolean));
154 169 break;
155 170 case STRING:
156   - Optional<String> stringValue = entry.getStrValue();
157   - if (stringValue.isPresent()) {
158   - json.addProperty(name, stringValue.get());
159   - }
  171 + entry.getStrValue().ifPresent(aString -> json.addProperty(name, aString));
160 172 break;
161 173 case DOUBLE:
162   - Optional<Double> doubleValue = entry.getDoubleValue();
163   - if (doubleValue.isPresent()) {
164   - json.addProperty(name, doubleValue.get());
165   - }
  174 + entry.getDoubleValue().ifPresent(aDouble -> json.addProperty(name, aDouble));
166 175 break;
167 176 case LONG:
168   - Optional<Long> longValue = entry.getLongValue();
169   - if (longValue.isPresent()) {
170   - json.addProperty(name, longValue.get());
171   - }
  177 + entry.getLongValue().ifPresent(aLong -> json.addProperty(name, aLong));
172 178 break;
173 179 }
174 180 }
... ...
... ... @@ -41,10 +41,7 @@ import org.thingsboard.server.dao.relation.RelationService;
41 41 import org.thingsboard.server.transport.mqtt.MqttTransportHandler;
42 42 import org.thingsboard.server.transport.mqtt.adaptors.JsonMqttAdaptor;
43 43
44   -import java.util.Collections;
45   -import java.util.HashMap;
46   -import java.util.Map;
47   -import java.util.Optional;
  44 +import java.util.*;
48 45 import java.util.stream.Collectors;
49 46
50 47 import static org.thingsboard.server.transport.mqtt.adaptors.JsonMqttAdaptor.validateJsonPayload;
... ... @@ -193,13 +190,22 @@ public class GatewaySessionCtx {
193 190 int requestId = jsonObj.get("id").getAsInt();
194 191 String deviceName = jsonObj.get(DEVICE_PROPERTY).getAsString();
195 192 boolean clientScope = jsonObj.get("client").getAsBoolean();
196   - String key = jsonObj.get("key").getAsString();
  193 + Set<String> keys;
  194 + if (jsonObj.has("key")) {
  195 + keys = Collections.singleton(jsonObj.get("key").getAsString());
  196 + } else {
  197 + JsonArray keysArray = jsonObj.get("keys").getAsJsonArray();
  198 + keys = new HashSet<>();
  199 + for (JsonElement keyObj : keysArray) {
  200 + keys.add(keyObj.getAsString());
  201 + }
  202 + }
197 203
198 204 BasicGetAttributesRequest request;
199 205 if (clientScope) {
200   - request = new BasicGetAttributesRequest(requestId, Collections.singleton(key), null);
  206 + request = new BasicGetAttributesRequest(requestId, keys, null);
201 207 } else {
202   - request = new BasicGetAttributesRequest(requestId, null, Collections.singleton(key));
  208 + request = new BasicGetAttributesRequest(requestId, null, keys);
203 209 }
204 210 GatewayDeviceSessionCtx deviceSessionCtx = devices.get(deviceName);
205 211 processor.process(new BasicToDeviceActorSessionMsg(deviceSessionCtx.getDevice(),
... ... @@ -251,7 +257,7 @@ public class GatewaySessionCtx {
251 257 }
252 258
253 259 private void ack(MqttPublishMessage msg) {
254   - if(msg.variableHeader().messageId() > 0) {
  260 + if (msg.variableHeader().messageId() > 0) {
255 261 writeAndFlush(MqttTransportHandler.createMqttPubAckMsg(msg.variableHeader().messageId()));
256 262 }
257 263 }
... ...
... ... @@ -17,7 +17,42 @@
17 17 import './home-links.scss';
18 18
19 19 /*@ngInject*/
20   -export default function HomeLinksController($scope, menu) {
  20 +export default function HomeLinksController($scope, $mdMedia, menu) {
  21 +
21 22 var vm = this;
22   - vm.model = menu.getHomeSections();
  23 +
  24 + vm.sectionColspan = sectionColspan;
  25 +
  26 + $scope.$watch(function() { return $mdMedia('lg'); }, function() {
  27 + updateColumnCount();
  28 + });
  29 +
  30 + $scope.$watch(function() { return $mdMedia('gt-lg'); }, function() {
  31 + updateColumnCount();
  32 + });
  33 +
  34 + updateColumnCount();
  35 +
  36 + menu.getHomeSections().then((homeSections) => {
  37 + vm.model = homeSections;
  38 + });
  39 +
  40 + function updateColumnCount() {
  41 + vm.cols = 2;
  42 + if ($mdMedia('lg')) {
  43 + vm.cols = 3;
  44 + }
  45 + if ($mdMedia('gt-lg')) {
  46 + vm.cols = 4;
  47 + }
  48 + }
  49 +
  50 + function sectionColspan(section) {
  51 + var colspan = vm.cols;
  52 + if (section && section.places && section.places.length <= colspan) {
  53 + colspan = section.places.length;
  54 + }
  55 + return colspan;
  56 + }
  57 +
23 58 }
... ...
... ... @@ -15,8 +15,8 @@
15 15 limitations under the License.
16 16
17 17 -->
18   -<md-grid-list class="tb-home-links" md-cols="2" md-cols-lg="3" md-cols-gt-lg="4" md-row-height="280px">
19   - <md-grid-tile md-colspan="2" md-colspan-gt-sm="{{section.places.length}}" ng-repeat="section in vm.model">
  18 +<md-grid-list class="tb-home-links" md-cols="{{vm.cols}}" md-row-height="280px">
  19 + <md-grid-tile md-colspan="2" md-colspan-gt-sm="{{vm.sectionColspan(section)}}" ng-repeat="section in vm.model">
20 20 <md-card style='width: 100%;'>
21 21 <md-card-title>
22 22 <md-card-title-text>
... ... @@ -25,12 +25,12 @@
25 25 </md-card-title>
26 26 <md-card-content>
27 27 <md-grid-list md-row-height="170px" md-cols="{{section.places.length}}" md-cols-gt-md="{{section.places.length}}">
28   - <md-grid-tile class="card-tile" ng-repeat="place in section.places">
29   - <md-button class="tb-card-button md-raised md-primary" layout="column" ui-sref="{{place.state}}">
30   - <md-icon class="material-icons tb-md-96" aria-label="{{place.icon}}">{{place.icon}}</md-icon>
31   - <span translate>{{place.name}}</span>
32   - </md-button>
33   - </md-grid-tile>
  28 + <md-grid-tile class="card-tile" ng-repeat="place in section.places">
  29 + <md-button class="tb-card-button md-raised md-primary" layout="column" ui-sref="{{place.state}}">
  30 + <md-icon class="material-icons tb-md-96" aria-label="{{place.icon}}">{{place.icon}}</md-icon>
  31 + <span translate>{{place.name}}</span>
  32 + </md-button>
  33 + </md-grid-tile>
34 34 </md-grid-list>
35 35 </md-card-content>
36 36 </md-card>
... ...