Commit 0045f00613ac04e27f25ee7c986c7c9b9b17a921

Authored by Andrew Shvayka
Committed by GitHub
2 parents b1712430 3c1682f5

Merge pull request #4451 from ViacheslavKlimov/master-to-snmp

Merge 'master' into 'develop/snmp'
Showing 82 changed files with 1583 additions and 658 deletions

Too many changes to show.

To preserve performance only 82 of 217 files are displayed.

... ... @@ -455,6 +455,24 @@
455 455 "dataKeySettingsSchema": "{}\n",
456 456 "defaultConfig": "{\"datasources\":[{\"type\":\"function\",\"name\":\"function\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Random\",\"color\":\"#2196f3\",\"settings\":{},\"_hash\":0.15479322438769105,\"funcBody\":\"var value = prevValue + Math.random() * 100 - 50;\\nvar multiplier = Math.pow(10, 2 || 0);\\nvar value = Math.round(value * multiplier) / multiplier;\\nif (value < -1000) {\\n\\tvalue = -1000;\\n} else if (value > 1000) {\\n\\tvalue = 1000;\\n}\\nreturn value;\"}]}],\"timewindow\":{\"realtime\":{\"timewindowMs\":60000}},\"showTitle\":true,\"backgroundColor\":\"#fff\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"8px\",\"settings\":{},\"title\":\"Photo camera input\",\"showTitleIcon\":false,\"titleIcon\":\"more_horiz\",\"iconColor\":\"rgba(0, 0, 0, 0.87)\",\"iconSize\":\"24px\",\"titleTooltip\":\"\",\"dropShadow\":true,\"enableFullscreen\":false,\"widgetStyle\":{},\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"useDashboardTimewindow\":true,\"displayTimewindow\":true,\"showLegend\":false,\"actions\":{}}"
457 457 }
  458 + },
  459 + {
  460 + "alias": "update_json_attribute",
  461 + "name": "Update JSON attribute",
  462 + "image": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAUoAAADhCAMAAACZWwyuAAAB71BMVEX////w8PDt7e3z8/Pg4ODAwMDc3Nz19fUZhJQ4lKK9vb17e3v9/f2mpqbj4+P4+Pi+vr58fHzT09P7+/uTxcz2+/ucy9GpqakCAgK93OHNzc0eh5b09PSw1dusrKwvkZ+ampqysrIzMzPV1dXCwsKurq4iiZnZ2dnX19fIyMgrj50ABsiKiopmZmbo8/XQ5+ro6OjPz89JnqqCgoLX6u2cnJwmjJv39/ff39+12N7ExMQ2NjaioqKYmJjs7OzD4OTS0tLKysrh8PLq6uq6uroCCMjDw8OOjo6hzdO0tLQuj56UlJS4uvDZ7O7l5eVvsrw0k6EchZWEhIRwcHDU6ezG4eaGv8d1tb+3t7dCmqeIiIj4+/3j8fO62+AKD8tWpbGgoKBqamouLi7u7u47lqTP0PWr0tgXHM1/u8N6uMFqsLpfqrVNoKxFRUXU1faYyM92dnY7Ozvz+Pry8vK5ubm4uLh+fn5sbGzGx/OipOtzduG42t8uM9KNw8pTo690dHT6+vrt9viOkefb29um0NYfHx/p6vu9vvGqrO2YmulXW9uhztRnrrgmJiYQEBDt7fzk5frf4PjL4+eMj+a/3eJpbN9MUNk7P9SQxMuNwslfX19TU1OcnurI4uY9QdYyN9ImK9BVVVVPT097fuNYWFjSJwPyAAALvElEQVR42uzbTWviQBjA8ad5qgNONI05FCSIshUNKERCSFlM2WIxSKCH5FI8RfoFCrvVYwv7xTfG4susxqgpqJkfHoLM6c9MTCYROI7jOC4doiIRoqrEkhQRuIOJEsEVROI1Dw2pIkPlMQ8PyWMez8ItLOD2QnArAlxyIsEYhK/x5CSMJQGX0Cfu8AmXTCEqbkWUPQaBiDtd8hJXMJ6SbNByeWd3iROMRxIPAhEx09MSd1ATDwIJMdPTEndJNIid4D/kkLk4yMbFZTop2fXdonSZktb2XuFKpwRnBzeoGoeklNZS1tjj+BVu2hDKfYhxKXUXTtnXHIqgXd+esk/pNSK+GrQcjZsbuotBVrKUFmzSGs++b1djZqVV1m01D6crqlSpVOldpYKFSmzKWUCN0nI0bq5bWAwiuHquNNnj+JOlSDWA144OJW86KUcp38oAtQZIPZ/mICQEBvWGcLpw7i6acu0iCkXDtQ1hcos4MtdTOt4VYs2h5dk42y4azj3ejhYpVUyEwEZ1F+BpBJKviQVfWUkZuOTZz0e5ba8FJ4xNWZcLPw0De97vezpYTzmUK1iiL18p5T+aEaymxGRU2OhhTMAbgFISATvCMqU0LgEUo4U/KOreKV9LsSlHAeKtgY+09STr6ylvzABfRuWvlC5i4DCz8oiU4Az6Uwug25blzsMyZb8zDpkQkgj04YSxKSf16FwpTOquzZwrnx5lvT3sLlP21lKSoxY4aM4wANCn10DmKemvaFZ2HuBMMCnDT5QSe205x6R8ufICWqowKQ/92WFJ/lsTID+9vhp29FlKpye1/AbUXELqTTgDbMq60S2PDMRHKutsSqzTGrIpD74YYvUohBr+x1D+O0tZMqaO0wASfPjmWdwjbfgFd0wDUZjY+F/Ke6ptSRl/iZ6Nm3Dc4sq7Se/GMRtbQ7hZvjrR+XZGKimrhoZ7pOSbbKntV/Kt39R20fkDiZSf7Yi4i3rBkzLVJ46g4M7mHH+l4Bjpv+hiXfTyTr9lVk+U38Diqzs1n1l8XeibiJaKLP7O74FEiYdMT/RfE0RVJZICe8txSSRKmU9KEIRm8V0QnitNIWvST6m93whhy3/sm/lTEmEYx7/SOLPbdFgjCDGEWm0FBUVEGRRF0WEmlCgxeFSaeKHpNF1ajWW3V4cddh9/aLs078PqCMOCxjrs55dn3mff9/3hM7x7fGfYrSs1ll9leUWFrmrK+ERXahSk0uc9srTKJ7c31+hKjQJUHnnorc2g0lijK9eVGgWovHF1fUaV5zSVyg54RUaVNzWVearcK5FWWWPcqanMU2VjU1NTI6kcNjbpNJX5HvDGq43pA7510/Q+TaVylcyl/F65z1iuqVSi8vgpX23VqaUfO5c1lUpUrq+V2LXUh6PxnPbhuExxhnHrfi3OKFylbseV8ic/tz/WlRoroFK8V9ZMGad0pUZuKstyBSWMpnJ1qfS0tXmk6hhFHmRfR/sXnQJUVswPJy8dy0Vlvd9fL1WDFXmRfR3tv5hn39oT9+JU5TyyNwBQi8rOz3vWVnurc1HZ5XR2rZhK2n8x68buNbwNPqIq43lCVSrLpB/k1aZcVD5wODoAXOQk9ND3hD39DrzhzR39QgiIhs22Xj1YH4EQL5hjQIQ3C5OO9DrbWaCSZ9dpPu2PjdeuHZK7BPD+JdU0g4nrQVWplPizJxeVAaAVgLvF5na7gT6+rnlgAJZ6p6ujWfCD72uesEWpDxP3qvlrGzA+6hwNh2gdU8mus/m0PzYYjYexkO/3qBLxsbtQnUpf8vDCRi4HNcBFADcXsPDoDcF1FnwlYOFaWV9UpQdjiGfrSCW7TvPTVB/FQl4knlIlfr+H6lRWDZ8uU66yjjOLcM2Syj64DCmV41wd65PK1sl6m9WWUSXNz8zd9jtUiaftg6pTuXX4VFkeKk2c84KIXlTZE2IqRzgT65PKrgF/pEem0jpEKuX7ZDPZQDXNC3swGLSnnkNqUbnfW6PwFb1bgEgr1w0JUSXAVJq4AOszVSNcHTBho3VwRUkl7bOQg9WQMdj+nOo/vnwBMDMoEnwxA0AtKm/MbxE5qUBlhGt5Z9AjKtw3WSwylTFLd7gfrM9Uge/wO3ts6XWfhFf+PlJJ84nFj52XH66LxKli1m5/DQl2wM9MX1aFyl//8koFKvHRY3Y5sO5+2Gxtkau0CpMjYH1SdaFDMNf3p9fpo8LF+hBdp/nEopehH3aJ11QRHxuLL1D5y3hbFSqXAvnAV6JIbJuu1lQuC0eStRs1lctC1aU16njsaCFb8VRW5pCxvWnBauW/5ZXZDvKQJ0K6ednYMarGXHIFVFZ99ib36BTklRlVRjmTXCWNDdaccsmgXaIBSlGPSt9BMa/0KcgrM6rUOyFTSWNSmT2XxB2RucQsFKMalRLztxTklbxVEKJ6FktQXhngOK4OIiOTgjXGszHllA5p1Mo1L5FLErPtd6EcFansXDt8TkFeyff7J4RPTCXllXG3+2JKXX/YYhFVsjHllLFewCLEs+WSc2MoOoWoXFtbu6kzg8pM74+9LlJJeSWQUhfg/Kk+G9MBb+GB3g5kySWfioFF0SlE5b4TV4YvKVQ5ZCWVLK9k6tq4kaVVOjk3YkPIwtuECv4gV+C90uc9pkzlWRvljiyvZOpMmVSiq2WciyALH+ZQfApUuV65SsodKRkCPN2p/NGS6rMx5ZQYCk+Es+SSmAk+Q/EpQOX5mgpf8mGZYpUsd5SpfDBgMugR8hikPhtTTolxwdqDzLkkntlHUHzyV9l5I+lNHmhUrpLljjKVzpg55kC8x2a2hsDGlFMCvVwEmXNJPEpABayOOMPggvpZBSrHnRaPCepnBVRuOFFefmIDlg3TX/buXqVhKIzD+FuonEEJJQ4eKogEOrjFQRRSisEiuIl3YPYOvQId7Kg34OSdGgd1SaD5aPmH8zwQsv8g5Jx3OOf08c0GUP+UUezMXDzA8/3lKHNnZS630Oqf8sAK//5QvkKrG+VVsqygXEQvGyibUc5WlZTl44+gbEJ5u5pm1ZT3/hjKBpSLr5NRDeWFf4WyyR78eVRHeecnUG5PebOOaynt0K8ttNpTzpMsy5LkvIry+uNpZqHVnjK6LMvm4yrKqXd84A2X6PzBd0mZux/KERvHfsYZE884o5ch2/LscxOe5C4orfDFxMJrAFP0oQQllHpBCaVeUEKpF5RQ6gUllHpBCaVeUEKpF5RQ6gUllHpBCaVeUEKpF5RQ6gUllHpBCaVeUEKpF5RQ6gUllHpBCaVeUEKpF5RQ6gUllHpBCaVeUEKpF5RQ6gUllHpBCaVeUEKpF5RQ6gUllHpBuWdK2qLwDj8lIiIiIiIKLpdG45ZFqTP6y407heV/aTfK1Oi3qBtlgNdmfLdrxypyw0AAhifJ2AeDZtcohUAEgZGFrdJVjIsgk2DY5urt9xFu9wn2xWMFLklzV3gb45u/GHD7YSML5s3wwUASSqHcbkIplNtLKIVyewll7onaZR7oB/yfJ/UYZfvLmbMXyscpy2CKxplOKB+mtBwRNRcflLJJvhh/Anybir4nBV9sMeJKyonnZaYO/cm4GX1+JC6xr02dPgAlpaFpFMTq7onUsRkx0WEd5RD42ucP3YWJeMJQI4YTJj7H2tz3TzkBlPR0oQEgkUK6AEzz2mPnxhx6LPsW0RA2XHYc8ebKwXPcP2UPgPTynAk9KV2pTHtcRZkxZ8Ma9dkZvqJmO3KLjnPFTimP1EEm/PyP8tMfSp8p7/R9FWWyy9BMrTnp1lwRA53zNx70UrtTSmjiMhIdXykvdADQpDCT2katoiTWiC1Xli0OmbJyZkQ8m4XR7/XYASQ7JNLwSglxfh4qUl+bETUNsIqyM66YAyfPdaz5hpiYuzzDWLHeKyUcYhEH9Zcy/wzZRApebDUOa2873dWZ2iJG54oQENHVuGRrE+Ju30q5g28qoRTK7SWUQrm9hFIot5dQCuX2kvUrWQrcXrKqKgvUkiRJkiRJkiS9328dj4CaN1dagAAAAABJRU5ErkJggg==",
  463 + "description": "Simple form to input new JSON value for pre-defined attribute/timeseries key.",
  464 + "descriptor": {
  465 + "type": "latest",
  466 + "sizeX": 7.5,
  467 + "sizeY": 3,
  468 + "resources": [],
  469 + "templateHtml": "<tb-json-input-widget \n [ctx]=\"ctx\">\n</tb-json-input-widget>",
  470 + "templateCss": ".attribute-update-form {\n overflow: hidden;\n height: 100%;\n display: flex;\n flex-direction: column;\n}\n\n.attribute-update-form__grid {\n display: flex;\n}\n.grid__element:first-child {\n flex: 1;\n}\n.grid__element:last-child {\n margin-top: 19px;\n margin-left: 7px;\n}\n.grid__element {\n display: flex;\n}\n\n.attribute-update-form .mat-button.mat-icon-button {\n width: 32px;\n min-width: 32px;\n height: 32px;\n min-height: 32px;\n padding: 0 !important;\n margin: 0 !important;\n line-height: 20px;\n}\n\n.attribute-update-form .mat-icon-button mat-icon {\n width: 20px;\n min-width: 20px;\n height: 20px;\n min-height: 20px;\n font-size: 20px;\n}\n\n.tb-toast {\n font-size: 14px!important;\n}",
  471 + "controllerScript": "self.onInit = function() {\n}\n\nself.onDataUpdated = function() {\n self.ctx.$scope.jsonInputWidget.onDataUpdated();\n}\n\nself.onResize = function() {\n}\n\nself.typeParameters = function() {\n return {\n maxDatasources: 1,\n maxDataKeys: 1,\n singleEntity: true\n }\n}\n\nself.onDestroy = function() {\n}",
  472 + "settingsSchema": "{\n \"schema\": {\n \"type\": \"object\",\n \"title\": \"AdvancedSettings\",\n \"properties\": {\n \"widgetTitle\": {\n \"title\": \"Widget title\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"widgetMode\": {\n \"title\": \"Widget mode\",\n \"type\": \"string\",\n \"default\": \"ATTRIBUTE\"\n },\n \"attributeScope\": {\n \"title\": \"Attribute scope\",\n \"type\": \"string\",\n \"default\": \"SERVER_SCOPE\"\n },\n \"showLabel\":{\n \"title\": \"Show label\",\n \"type\": \"boolean\",\n \"default\": true\n },\n \"labelValue\": {\n \"title\": \"Label\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"attributeRequired\": {\n \"title\": \"Value required\",\n \"type\": \"boolean\",\n \"default\": true\n },\n \"showResultMessage\": {\n \"title\": \"Show result message\",\n \"type\": \"boolean\",\n \"default\": true\n }\n },\n \"required\": []\n },\n \"form\": [\n \"widgetTitle\",\n {\n \"key\": \"widgetMode\",\n \"type\": \"rc-select\",\n \"multiple\": false,\n \"items\": [\n {\n \"value\": \"ATTRIBUTE\",\n \"label\": \"Update attribute\"\n },\n {\n \"value\": \"TIME_SERIES\",\n \"label\": \"Update timeseries\"\n }\n ]\n },\n {\n \"key\": \"attributeScope\",\n \"type\": \"rc-select\",\n \"multiple\": false,\n \"condition\": \"model.widgetMode === 'ATTRIBUTE'\",\n \"items\": [\n {\n \"value\": \"SERVER_SCOPE\",\n \"label\": \"Server attribute\"\n },\n {\n \"value\": \"SHARED_SCOPE\",\n \"label\": \"Shared attribute\"\n }\n ]\n },\n \"showLabel\",\n {\n \"key\": \"labelValue\",\n \"condition\": \"model.showLabel\"\n },\n \"attributeRequired\",\n \"showResultMessage\"\n ]\n}",
  473 + "dataKeySettingsSchema": "{}",
  474 + "defaultConfig": "{\"datasources\":[{\"type\":\"function\",\"name\":\"function\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Random\",\"color\":\"#2196f3\",\"settings\":{},\"_hash\":0.15479322438769105,\"funcBody\":\"var value = prevValue + Math.random() * 100 - 50;\\nvar multiplier = Math.pow(10, 2 || 0);\\nvar value = Math.round(value * multiplier) / multiplier;\\nif (value < -1000) {\\n\\tvalue = -1000;\\n} else if (value > 1000) {\\n\\tvalue = 1000;\\n}\\nreturn value;\"}]}],\"timewindow\":{\"realtime\":{\"timewindowMs\":60000}},\"showTitle\":true,\"backgroundColor\":\"#fff\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"8px\",\"settings\":{\"attributeScope\":\"SERVER_SCOPE\",\"showLabel\":true,\"attributeRequired\":true,\"showResultMessage\":true},\"title\":\"Update JSON attribute\",\"showTitleIcon\":false,\"iconColor\":\"rgba(0, 0, 0, 0.87)\",\"iconSize\":\"24px\",\"titleTooltip\":\"\",\"dropShadow\":true,\"enableFullscreen\":false,\"widgetStyle\":{},\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"showLegend\":false}"
  475 + }
458 476 }
459 477 ]
460 478 }
... ...
... ... @@ -21,7 +21,7 @@ import org.springframework.web.bind.annotation.RequestMapping;
21 21 @Controller
22 22 public class WebConfig {
23 23
24   - @RequestMapping(value = "/{path:^(?!api$)(?!assets$)(?!static$)(?!webjars$)[^\\.]*}/**")
  24 + @RequestMapping(value = {"/assets", "/assets/", "/{path:^(?!api$)(?!assets$)(?!static$)(?!webjars$)[^\\.]*}/**"})
25 25 public String redirect() {
26 26 return "forward:/index.html";
27 27 }
... ...
... ... @@ -46,8 +46,6 @@ import org.thingsboard.server.queue.util.TbCoreComponent;
46 46 import org.thingsboard.server.service.security.permission.Operation;
47 47 import org.thingsboard.server.service.security.permission.Resource;
48 48
49   -import java.util.UUID;
50   -
51 49 @RestController
52 50 @TbCoreComponent
53 51 @RequestMapping("/api")
... ... @@ -177,7 +175,6 @@ public class AlarmController extends BaseController {
177 175 @RequestParam(required = false) String sortOrder,
178 176 @RequestParam(required = false) Long startTime,
179 177 @RequestParam(required = false) Long endTime,
180   - @RequestParam(required = false) String offset,
181 178 @RequestParam(required = false) Boolean fetchOriginator
182 179 ) throws ThingsboardException {
183 180 checkParameter("EntityId", strEntityId);
... ... @@ -191,12 +188,9 @@ public class AlarmController extends BaseController {
191 188 }
192 189 checkEntityId(entityId, Operation.READ);
193 190 TimePageLink pageLink = createTimePageLink(pageSize, page, textSearch, sortProperty, sortOrder, startTime, endTime);
194   - UUID idOffsetUuid = null;
195   - if (StringUtils.isNotEmpty(offset)) {
196   - idOffsetUuid = toUUID(offset);
197   - }
  191 +
198 192 try {
199   - return checkNotNull(alarmService.findAlarms(getCurrentUser().getTenantId(), new AlarmQuery(entityId, pageLink, alarmSearchStatus, alarmStatus, fetchOriginator, idOffsetUuid)).get());
  193 + return checkNotNull(alarmService.findAlarms(getCurrentUser().getTenantId(), new AlarmQuery(entityId, pageLink, alarmSearchStatus, alarmStatus, fetchOriginator)).get());
200 194 } catch (Exception e) {
201 195 throw handleException(e);
202 196 }
... ...
... ... @@ -110,7 +110,6 @@ import org.thingsboard.server.dao.model.ModelConstants;
110 110 import org.thingsboard.server.dao.oauth2.OAuth2ConfigTemplateService;
111 111 import org.thingsboard.server.dao.oauth2.OAuth2Service;
112 112 import org.thingsboard.server.dao.relation.RelationService;
113   -import org.thingsboard.server.dao.resource.TbResourceService;
114 113 import org.thingsboard.server.dao.rule.RuleChainService;
115 114 import org.thingsboard.server.dao.tenant.TbTenantProfileCache;
116 115 import org.thingsboard.server.dao.tenant.TenantProfileService;
... ... @@ -130,6 +129,7 @@ import org.thingsboard.server.service.edge.rpc.init.SyncEdgeService;
130 129 import org.thingsboard.server.service.lwm2m.LwM2MModelsRepository;
131 130 import org.thingsboard.server.service.profile.TbDeviceProfileCache;
132 131 import org.thingsboard.server.service.queue.TbClusterService;
  132 +import org.thingsboard.server.service.resource.TbResourceService;
133 133 import org.thingsboard.server.service.security.model.SecurityUser;
134 134 import org.thingsboard.server.service.security.permission.AccessControlService;
135 135 import org.thingsboard.server.service.security.permission.Operation;
... ...
... ... @@ -18,12 +18,14 @@ package org.thingsboard.server.controller;
18 18 import org.springframework.beans.factory.annotation.Autowired;
19 19 import org.springframework.security.access.prepost.PreAuthorize;
20 20 import org.springframework.web.bind.annotation.PathVariable;
  21 +import org.springframework.web.bind.annotation.RequestBody;
21 22 import org.springframework.web.bind.annotation.RequestMapping;
22 23 import org.springframework.web.bind.annotation.RequestMethod;
23 24 import org.springframework.web.bind.annotation.RequestParam;
24 25 import org.springframework.web.bind.annotation.ResponseBody;
25 26 import org.springframework.web.bind.annotation.RestController;
26 27 import org.thingsboard.server.common.data.Event;
  28 +import org.thingsboard.server.common.data.event.EventFilter;
27 29 import org.thingsboard.server.common.data.exception.ThingsboardException;
28 30 import org.thingsboard.server.common.data.id.EntityId;
29 31 import org.thingsboard.server.common.data.id.EntityIdFactory;
... ... @@ -31,6 +33,7 @@ import org.thingsboard.server.common.data.id.TenantId;
31 33 import org.thingsboard.server.common.data.page.PageData;
32 34 import org.thingsboard.server.common.data.page.TimePageLink;
33 35 import org.thingsboard.server.dao.event.EventService;
  36 +import org.thingsboard.server.dao.model.ModelConstants;
34 37 import org.thingsboard.server.queue.util.TbCoreComponent;
35 38 import org.thingsboard.server.service.security.permission.Operation;
36 39
... ... @@ -101,4 +104,38 @@ public class EventController extends BaseController {
101 104 }
102 105 }
103 106
  107 + @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')")
  108 + @RequestMapping(value = "/events/{entityType}/{entityId}", method = RequestMethod.POST)
  109 + @ResponseBody
  110 + public PageData<Event> getEvents(
  111 + @PathVariable("entityType") String strEntityType,
  112 + @PathVariable("entityId") String strEntityId,
  113 + @RequestParam("tenantId") String strTenantId,
  114 + @RequestParam int pageSize,
  115 + @RequestParam int page,
  116 + @RequestBody EventFilter eventFilter,
  117 + @RequestParam(required = false) String textSearch,
  118 + @RequestParam(required = false) String sortProperty,
  119 + @RequestParam(required = false) String sortOrder,
  120 + @RequestParam(required = false) Long startTime,
  121 + @RequestParam(required = false) Long endTime) throws ThingsboardException {
  122 + checkParameter("EntityId", strEntityId);
  123 + checkParameter("EntityType", strEntityType);
  124 + try {
  125 + TenantId tenantId = new TenantId(toUUID(strTenantId));
  126 +
  127 + EntityId entityId = EntityIdFactory.getByTypeAndId(strEntityType, strEntityId);
  128 + checkEntityId(entityId, Operation.READ);
  129 +
  130 + if(sortProperty != null && sortProperty.equals("createdTime") && eventFilter.hasFilterForJsonBody()) {
  131 + sortProperty = ModelConstants.CREATED_TIME_PROPERTY;
  132 + }
  133 +
  134 + TimePageLink pageLink = createTimePageLink(pageSize, page, textSearch, sortProperty, sortOrder, startTime, endTime);
  135 + return checkNotNull(eventService.findEventsByFilter(tenantId, entityId, eventFilter, pageLink));
  136 + } catch (Exception e) {
  137 + throw handleException(e);
  138 + }
  139 + }
  140 +
104 141 }
... ...
... ... @@ -244,7 +244,8 @@ public class RuleChainController extends BaseController {
244 244 }
245 245
246 246 RuleChain ruleChain = checkRuleChain(ruleChainMetaData.getRuleChainId(), Operation.WRITE);
247   - RuleChainMetaData savedRuleChainMetaData = checkNotNull(ruleChainService.saveRuleChainMetaData(tenantId, ruleChainMetaData));
  247 + checkNotNull(ruleChainService.saveRuleChainMetaData(tenantId, ruleChainMetaData) ? true : null);
  248 + RuleChainMetaData savedRuleChainMetaData = checkNotNull(ruleChainService.loadRuleChainMetaData(tenantId, ruleChainMetaData.getRuleChainId()));
248 249
249 250 if (RuleChainType.CORE.equals(ruleChain.getType())) {
250 251 tbClusterService.onEntityStateChange(ruleChain.getTenantId(), ruleChain.getId(), ComponentLifecycleEvent.UPDATED);
... ...
... ... @@ -36,8 +36,8 @@ import org.thingsboard.server.common.data.lwm2m.LwM2mObject;
36 36 import org.thingsboard.server.common.data.page.PageData;
37 37 import org.thingsboard.server.common.data.page.PageLink;
38 38 import org.thingsboard.server.common.data.security.Authority;
39   -import org.thingsboard.server.dao.resource.TbResourceService;
40 39 import org.thingsboard.server.queue.util.TbCoreComponent;
  40 +import org.thingsboard.server.service.resource.TbResourceService;
41 41 import org.thingsboard.server.service.security.permission.Operation;
42 42 import org.thingsboard.server.service.security.permission.Resource;
43 43
... ... @@ -52,12 +52,6 @@ public class TbResourceController extends BaseController {
52 52
53 53 public static final String RESOURCE_ID = "resourceId";
54 54
55   - private final TbResourceService resourceService;
56   -
57   - public TbResourceController(TbResourceService resourceService) {
58   - this.resourceService = resourceService;
59   - }
60   -
61 55 @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')")
62 56 @RequestMapping(value = "/resource/{resourceId}/download", method = RequestMethod.GET)
63 57 @ResponseBody
... ...
... ... @@ -40,8 +40,6 @@ public class DeviceProfileMsgConstructor {
40 40 .setName(deviceProfile.getName())
41 41 .setDefault(deviceProfile.isDefault())
42 42 .setType(deviceProfile.getType().name())
43   - .setTransportType(deviceProfile.getTransportType().name())
44   - .setProvisionType(deviceProfile.getProvisionType().name())
45 43 .setProfileDataBytes(ByteString.copyFrom(dataDecodingEncodingService.encode(deviceProfile.getProfileData())));
46 44 // TODO: voba - should this be always null at the moment??
47 45 // if (deviceProfile.getDefaultRuleChainId() != null) {
... ... @@ -54,6 +52,12 @@ public class DeviceProfileMsgConstructor {
54 52 if (deviceProfile.getDescription() != null) {
55 53 builder.setDescription(deviceProfile.getDescription());
56 54 }
  55 + if (deviceProfile.getTransportType() != null) {
  56 + builder.setTransportType(deviceProfile.getTransportType().name());
  57 + }
  58 + if (deviceProfile.getProvisionType() != null) {
  59 + builder.setProvisionType(deviceProfile.getProvisionType().name());
  60 + }
57 61 if (deviceProfile.getProvisionDeviceKey() != null) {
58 62 builder.setProvisionDeviceKey(deviceProfile.getProvisionDeviceKey());
59 63 }
... ...
... ... @@ -15,13 +15,13 @@
15 15 */
16 16 package org.thingsboard.server.service.edge.rpc.constructor;
17 17
  18 +import com.google.gson.reflect.TypeToken;
18 19 import com.google.gson.Gson;
19 20 import com.google.gson.JsonArray;
20 21 import com.google.gson.JsonElement;
21 22 import com.google.gson.JsonObject;
22 23 import lombok.extern.slf4j.Slf4j;
23 24 import org.springframework.stereotype.Component;
24   -import org.thingsboard.server.common.data.audit.ActionType;
25 25 import org.thingsboard.server.common.data.edge.EdgeEventActionType;
26 26 import org.thingsboard.server.common.data.id.EntityId;
27 27 import org.thingsboard.server.common.transport.adaptor.JsonConverter;
... ... @@ -82,7 +82,7 @@ public class EntityDataMsgConstructor {
82 82 AttributeDeleteMsg.Builder attributeDeleteMsg = AttributeDeleteMsg.newBuilder();
83 83 attributeDeleteMsg.setScope(entityData.getAsJsonObject().getAsJsonPrimitive("scope").getAsString());
84 84 JsonArray jsonArray = entityData.getAsJsonObject().getAsJsonArray("keys");
85   - List<String> keys = new Gson().fromJson(jsonArray.toString(), List.class);
  85 + List<String> keys = new Gson().fromJson(jsonArray.toString(), new TypeToken<>(){}.getType());
86 86 attributeDeleteMsg.addAllAttributeNames(keys);
87 87 attributeDeleteMsg.build();
88 88 builder.setAttributeDeleteMsg(attributeDeleteMsg);
... ...
... ... @@ -58,11 +58,8 @@ import org.thingsboard.server.common.data.page.PageLink;
58 58 import org.thingsboard.server.common.data.query.BooleanFilterPredicate;
59 59 import org.thingsboard.server.common.data.query.DynamicValue;
60 60 import org.thingsboard.server.common.data.query.DynamicValueSourceType;
61   -import org.thingsboard.server.common.data.query.EntityKey;
62   -import org.thingsboard.server.common.data.query.EntityKeyType;
63 61 import org.thingsboard.server.common.data.query.EntityKeyValueType;
64 62 import org.thingsboard.server.common.data.query.FilterPredicateValue;
65   -import org.thingsboard.server.common.data.query.KeyFilter;
66 63 import org.thingsboard.server.common.data.query.NumericFilterPredicate;
67 64 import org.thingsboard.server.common.data.rule.RuleChainType;
68 65 import org.thingsboard.server.common.data.security.Authority;
... ...
... ... @@ -35,7 +35,7 @@ import org.thingsboard.server.common.data.widget.WidgetsBundle;
35 35 import org.thingsboard.server.dao.dashboard.DashboardService;
36 36 import org.thingsboard.server.dao.exception.DataValidationException;
37 37 import org.thingsboard.server.dao.oauth2.OAuth2ConfigTemplateService;
38   -import org.thingsboard.server.dao.resource.TbResourceService;
  38 +import org.thingsboard.server.dao.resource.ResourceService;
39 39 import org.thingsboard.server.dao.rule.RuleChainService;
40 40 import org.thingsboard.server.dao.widget.WidgetTypeService;
41 41 import org.thingsboard.server.dao.widget.WidgetsBundleService;
... ... @@ -97,7 +97,7 @@ public class InstallScripts {
97 97 private OAuth2ConfigTemplateService oAuth2TemplateService;
98 98
99 99 @Autowired
100   - private TbResourceService resourceService;
  100 + private ResourceService resourceService;
101 101
102 102 private Path getTenantRuleChainsDir() {
103 103 return Paths.get(getDataDir(), JSON_DIR, TENANT_DIR, RULE_CHAINS_DIR);
... ... @@ -259,18 +259,12 @@ public class InstallScripts {
259 259 try {
260 260 createDefaultRuleChains(tenantId);
261 261 createDefaultRuleChain(tenantId, "Thermostat");
262   - loadEdgeDemoRuleChains(tenantId);
263 262 } catch (Exception e) {
264 263 log.error("Unable to load dashboard from json", e);
265 264 throw new RuntimeException("Unable to load dashboard from json", e);
266 265 }
267 266 }
268 267
269   - private void loadEdgeDemoRuleChains(TenantId tenantId) throws Exception {
270   - Path edgeDemoRuleChainsDir = Paths.get(getDataDir(), JSON_DIR, DEMO_DIR, EDGE_MANAGEMENT, RULE_CHAINS_DIR);
271   - loadRuleChainsFromPath(tenantId, edgeDemoRuleChainsDir);
272   - }
273   -
274 268 public void createOAuth2Templates() throws Exception {
275 269 Path oauth2ConfigTemplatesDir = Paths.get(getDataDir(), JSON_DIR, SYSTEM_DIR, OAUTH2_CONFIG_TEMPLATES_DIR);
276 270 try (DirectoryStream<Path> dirStream = Files.newDirectoryStream(oauth2ConfigTemplatesDir, path -> path.toString().endsWith(JSON_EXT))) {
... ...
... ... @@ -159,7 +159,7 @@ public class CassandraDbHelper {
159 159 } else if (type.getProtocolCode() == ProtocolConstants.DataType.TIMESTAMP) {
160 160 str = ""+row.getInstant(index).toEpochMilli();
161 161 } else if (type.getProtocolCode() == ProtocolConstants.DataType.BOOLEAN) {
162   - str = new Boolean(row.getBoolean(index)).toString();
  162 + str = Boolean.valueOf(row.getBoolean(index)).toString();
163 163 } else {
164 164 str = row.getString(index);
165 165 }
... ...
application/src/main/java/org/thingsboard/server/service/resource/DefaultTbResourceService.java renamed from dao/src/main/java/org/thingsboard/server/dao/resource/BaseTbResourceService.java
... ... @@ -13,7 +13,7 @@
13 13 * See the License for the specific language governing permissions and
14 14 * limitations under the License.
15 15 */
16   -package org.thingsboard.server.dao.resource;
  16 +package org.thingsboard.server.service.resource;
17 17
18 18 import lombok.extern.slf4j.Slf4j;
19 19 import org.apache.commons.lang3.StringUtils;
... ... @@ -21,12 +21,12 @@ import org.eclipse.leshan.core.model.DDFFileParser;
21 21 import org.eclipse.leshan.core.model.DefaultDDFFileValidator;
22 22 import org.eclipse.leshan.core.model.InvalidDDFFileException;
23 23 import org.eclipse.leshan.core.model.ObjectModel;
24   -import org.hibernate.exception.ConstraintViolationException;
25 24 import org.springframework.stereotype.Service;
26 25 import org.thingsboard.server.common.data.ResourceType;
27 26 import org.thingsboard.server.common.data.TbResource;
28 27 import org.thingsboard.server.common.data.TbResourceInfo;
29   -import org.thingsboard.server.common.data.Tenant;
  28 +import org.thingsboard.server.common.data.exception.ThingsboardErrorCode;
  29 +import org.thingsboard.server.common.data.exception.ThingsboardException;
30 30 import org.thingsboard.server.common.data.id.TbResourceId;
31 31 import org.thingsboard.server.common.data.id.TenantId;
32 32 import org.thingsboard.server.common.data.lwm2m.LwM2mInstance;
... ... @@ -35,11 +35,7 @@ import org.thingsboard.server.common.data.lwm2m.LwM2mResourceObserve;
35 35 import org.thingsboard.server.common.data.page.PageData;
36 36 import org.thingsboard.server.common.data.page.PageLink;
37 37 import org.thingsboard.server.dao.exception.DataValidationException;
38   -import org.thingsboard.server.dao.model.ModelConstants;
39   -import org.thingsboard.server.dao.service.DataValidator;
40   -import org.thingsboard.server.dao.service.PaginatedRemover;
41   -import org.thingsboard.server.dao.service.Validator;
42   -import org.thingsboard.server.dao.tenant.TenantDao;
  38 +import org.thingsboard.server.dao.resource.ResourceService;
43 39
44 40 import java.io.ByteArrayInputStream;
45 41 import java.io.IOException;
... ... @@ -47,7 +43,6 @@ import java.util.ArrayList;
47 43 import java.util.Base64;
48 44 import java.util.Comparator;
49 45 import java.util.List;
50   -import java.util.Optional;
51 46 import java.util.stream.Collectors;
52 47
53 48 import static org.thingsboard.server.common.data.lwm2m.LwM2mConstants.LWM2M_SEPARATOR_KEY;
... ... @@ -55,139 +50,120 @@ import static org.thingsboard.server.common.data.lwm2m.LwM2mConstants.LWM2M_SEPA
55 50 import static org.thingsboard.server.dao.device.DeviceServiceImpl.INCORRECT_TENANT_ID;
56 51 import static org.thingsboard.server.dao.service.Validator.validateId;
57 52
58   -@Service
59 53 @Slf4j
60   -public class BaseTbResourceService implements TbResourceService {
  54 +@Service
  55 +public class DefaultTbResourceService implements TbResourceService {
61 56
62   - public static final String INCORRECT_RESOURCE_ID = "Incorrect resourceId ";
63   - private final TbResourceDao resourceDao;
64   - private final TbResourceInfoDao resourceInfoDao;
65   - private final TenantDao tenantDao;
  57 + private final ResourceService resourceService;
66 58 private final DDFFileParser ddfFileParser;
67 59
68   - public BaseTbResourceService(TbResourceDao resourceDao, TbResourceInfoDao resourceInfoDao, TenantDao tenantDao) {
69   - this.resourceDao = resourceDao;
70   - this.resourceInfoDao = resourceInfoDao;
71   - this.tenantDao = tenantDao;
  60 + public DefaultTbResourceService(ResourceService resourceService) {
  61 + this.resourceService = resourceService;
72 62 this.ddfFileParser = new DDFFileParser(new DefaultDDFFileValidator());
73 63 }
74 64
75 65 @Override
76   - public TbResource saveResource(TbResource resource) throws InvalidDDFFileException, IOException {
  66 + public TbResource saveResource(TbResource resource) throws ThingsboardException {
77 67 log.trace("Executing saveResource [{}]", resource);
78 68 if (StringUtils.isEmpty(resource.getData())) {
79 69 throw new DataValidationException("Resource data should be specified!");
80 70 }
81 71 if (ResourceType.LWM2M_MODEL.equals(resource.getResourceType())) {
82   - List<ObjectModel> objectModels =
83   - ddfFileParser.parseEx(new ByteArrayInputStream(Base64.getDecoder().decode(resource.getData())), resource.getSearchText());
84   - if (!objectModels.isEmpty()) {
85   - ObjectModel objectModel = objectModels.get(0);
86   -
87   - String resourceKey = objectModel.id + LWM2M_SEPARATOR_KEY + objectModel.getVersion();
88   - String name = objectModel.name;
89   - resource.setResourceKey(resourceKey);
90   - if (resource.getId() == null) {
91   - resource.setTitle(name + " id=" + objectModel.id + " v" + objectModel.getVersion());
  72 + try {
  73 + List<ObjectModel> objectModels =
  74 + ddfFileParser.parseEx(new ByteArrayInputStream(Base64.getDecoder().decode(resource.getData())), resource.getSearchText());
  75 + if (!objectModels.isEmpty()) {
  76 + ObjectModel objectModel = objectModels.get(0);
  77 +
  78 + String resourceKey = objectModel.id + LWM2M_SEPARATOR_KEY + objectModel.getVersion();
  79 + String name = objectModel.name;
  80 + resource.setResourceKey(resourceKey);
  81 + if (resource.getId() == null) {
  82 + resource.setTitle(name + " id=" + objectModel.id + " v" + objectModel.getVersion());
  83 + }
  84 + resource.setSearchText(resourceKey + LWM2M_SEPARATOR_SEARCH_TEXT + name);
  85 + } else {
  86 + throw new DataValidationException(String.format("Could not parse the XML of objectModel with name %s", resource.getSearchText()));
92 87 }
93   - resource.setSearchText(resourceKey + LWM2M_SEPARATOR_SEARCH_TEXT + name);
94   - } else {
  88 + } catch (InvalidDDFFileException | IOException e) {
  89 + throw new ThingsboardException(e, ThingsboardErrorCode.GENERAL);
  90 + }
  91 + if (resource.getResourceType().equals(ResourceType.LWM2M_MODEL) && toLwM2mObject(resource) == null) {
95 92 throw new DataValidationException(String.format("Could not parse the XML of objectModel with name %s", resource.getSearchText()));
96 93 }
97 94 } else {
98 95 resource.setResourceKey(resource.getFileName());
99 96 }
100 97
101   - resourceValidator.validate(resource, TbResourceInfo::getTenantId);
102   -
103   - try {
104   - return resourceDao.save(resource.getTenantId(), resource);
105   - } catch (Exception t) {
106   - ConstraintViolationException e = extractConstraintViolationException(t).orElse(null);
107   - if (e != null && e.getConstraintName() != null && e.getConstraintName().equalsIgnoreCase("resource_unq_key")) {
108   - String field = ResourceType.LWM2M_MODEL.equals(resource.getResourceType()) ? "resourceKey" : "fileName";
109   - throw new DataValidationException("Resource with such " + field + " already exists!");
110   - } else {
111   - throw t;
112   - }
113   - }
114   -
  98 + return resourceService.saveResource(resource);
115 99 }
116 100
117 101 @Override
118   - public TbResource getResource(TenantId tenantId, ResourceType resourceType, String resourceKey) {
119   - log.trace("Executing getResource [{}] [{}] [{}]", tenantId, resourceType, resourceKey);
120   - return resourceDao.getResource(tenantId, resourceType, resourceKey);
  102 + public TbResource getResource(TenantId tenantId, ResourceType resourceType, String resourceId) {
  103 + return resourceService.getResource(tenantId, resourceType, resourceId);
121 104 }
122 105
123 106 @Override
124 107 public TbResource findResourceById(TenantId tenantId, TbResourceId resourceId) {
125   - log.trace("Executing findResourceById [{}] [{}]", tenantId, resourceId);
126   - Validator.validateId(resourceId, INCORRECT_RESOURCE_ID + resourceId);
127   - return resourceDao.findById(tenantId, resourceId.getId());
  108 + return resourceService.findResourceById(tenantId, resourceId);
128 109 }
129 110
130 111 @Override
131 112 public TbResourceInfo findResourceInfoById(TenantId tenantId, TbResourceId resourceId) {
132   - log.trace("Executing findResourceInfoById [{}] [{}]", tenantId, resourceId);
133   - Validator.validateId(resourceId, INCORRECT_RESOURCE_ID + resourceId);
134   - return resourceInfoDao.findById(tenantId, resourceId.getId());
135   - }
136   -
137   - @Override
138   - public void deleteResource(TenantId tenantId, TbResourceId resourceId) {
139   - log.trace("Executing deleteResource [{}] [{}]", tenantId, resourceId);
140   - Validator.validateId(resourceId, INCORRECT_RESOURCE_ID + resourceId);
141   - resourceDao.removeById(tenantId, resourceId.getId());
  113 + return resourceService.findResourceInfoById(tenantId, resourceId);
142 114 }
143 115
144 116 @Override
145 117 public PageData<TbResourceInfo> findAllTenantResourcesByTenantId(TenantId tenantId, PageLink pageLink) {
146   - log.trace("Executing findAllTenantResourcesByTenantId [{}]", tenantId);
147   - validateId(tenantId, INCORRECT_TENANT_ID + tenantId);
148   - return resourceInfoDao.findAllTenantResourcesByTenantId(tenantId.getId(), pageLink);
  118 + return resourceService.findAllTenantResourcesByTenantId(tenantId, pageLink);
149 119 }
150 120
151 121 @Override
152 122 public PageData<TbResourceInfo> findTenantResourcesByTenantId(TenantId tenantId, PageLink pageLink) {
153   - log.trace("Executing findTenantResourcesByTenantId [{}]", tenantId);
154   - validateId(tenantId, INCORRECT_TENANT_ID + tenantId);
155   - return resourceInfoDao.findTenantResourcesByTenantId(tenantId.getId(), pageLink);
  123 + return resourceService.findTenantResourcesByTenantId(tenantId, pageLink);
156 124 }
157 125
158 126 @Override
159   - public List<LwM2mObject> findLwM2mObjectPage(TenantId tenantId, String sortProperty, String sortOrder, PageLink pageLink) {
  127 + public List<LwM2mObject> findLwM2mObject(TenantId tenantId, String sortOrder, String sortProperty, String[] objectIds) {
160 128 log.trace("Executing findByTenantId [{}]", tenantId);
161 129 validateId(tenantId, INCORRECT_TENANT_ID + tenantId);
162   - PageData<TbResource> resourcePageData = resourceDao.findResourcesByTenantIdAndResourceType(
163   - tenantId,
164   - ResourceType.LWM2M_MODEL, pageLink);
165   - return resourcePageData.getData().stream()
  130 + List<TbResource> resources = resourceService.findTenantResourcesByResourceTypeAndObjectIds(tenantId, ResourceType.LWM2M_MODEL,
  131 + objectIds);
  132 + return resources.stream()
166 133 .map(this::toLwM2mObject)
167 134 .sorted(getComparator(sortProperty, sortOrder))
168 135 .collect(Collectors.toList());
169 136 }
170 137
171 138 @Override
172   - public List<LwM2mObject> findLwM2mObject(TenantId tenantId, String sortOrder,
173   - String sortProperty,
174   - String[] objectIds) {
  139 + public List<LwM2mObject> findLwM2mObjectPage(TenantId tenantId, String sortProperty, String sortOrder, PageLink pageLink) {
175 140 log.trace("Executing findByTenantId [{}]", tenantId);
176 141 validateId(tenantId, INCORRECT_TENANT_ID + tenantId);
177   - List<TbResource> resources = resourceDao.findResourcesByTenantIdAndResourceType(tenantId, ResourceType.LWM2M_MODEL,
178   - objectIds,
179   - null);
180   - return resources.stream()
  142 + PageData<TbResource> resourcePageData = resourceService.findTenantResourcesByResourceTypeAndPageLink(tenantId, ResourceType.LWM2M_MODEL, pageLink);
  143 + return resourcePageData.getData().stream()
181 144 .map(this::toLwM2mObject)
182 145 .sorted(getComparator(sortProperty, sortOrder))
183 146 .collect(Collectors.toList());
184 147 }
185 148
186 149 @Override
  150 + public void deleteResource(TenantId tenantId, TbResourceId resourceId) {
  151 + resourceService.deleteResource(tenantId, resourceId);
  152 + }
  153 +
  154 + @Override
187 155 public void deleteResourcesByTenantId(TenantId tenantId) {
188   - log.trace("Executing deleteResourcesByTenantId, tenantId [{}]", tenantId);
189   - validateId(tenantId, INCORRECT_TENANT_ID + tenantId);
190   - tenantResourcesRemover.removeEntities(tenantId, tenantId);
  156 + resourceService.deleteResourcesByTenantId(tenantId);
  157 + }
  158 +
  159 + private Comparator<? super LwM2mObject> getComparator(String sortProperty, String sortOrder) {
  160 + Comparator<LwM2mObject> comparator;
  161 + if ("name".equals(sortProperty)) {
  162 + comparator = Comparator.comparing(LwM2mObject::getName);
  163 + } else {
  164 + comparator = Comparator.comparingLong(LwM2mObject::getId);
  165 + }
  166 + return "DESC".equals(sortOrder) ? comparator.reversed() : comparator;
191 167 }
192 168
193 169 private LwM2mObject toLwM2mObject(TbResource resource) {
... ... @@ -223,69 +199,4 @@ public class BaseTbResourceService implements TbResourceService {
223 199 return null;
224 200 }
225 201 }
226   -
227   - private Comparator<? super LwM2mObject> getComparator(String sortProperty, String sortOrder) {
228   - Comparator<LwM2mObject> comparator;
229   - if ("name".equals(sortProperty)) {
230   - comparator = Comparator.comparing(LwM2mObject::getName);
231   - } else {
232   - comparator = Comparator.comparingLong(LwM2mObject::getId);
233   - }
234   - return "DESC".equals(sortOrder) ? comparator.reversed() : comparator;
235   - }
236   -
237   - private DataValidator<TbResource> resourceValidator = new DataValidator<>() {
238   -
239   - @Override
240   - protected void validateDataImpl(TenantId tenantId, TbResource resource) {
241   - if (StringUtils.isEmpty(resource.getTitle())) {
242   - throw new DataValidationException("Resource title should be specified!");
243   - }
244   - if (resource.getResourceType() == null) {
245   - throw new DataValidationException("Resource type should be specified!");
246   - }
247   - if (StringUtils.isEmpty(resource.getFileName())) {
248   - throw new DataValidationException("Resource file name should be specified!");
249   - }
250   - if (StringUtils.isEmpty(resource.getResourceKey())) {
251   - throw new DataValidationException("Resource key should be specified!");
252   - }
253   - if (resource.getTenantId() == null) {
254   - resource.setTenantId(new TenantId(ModelConstants.NULL_UUID));
255   - }
256   - if (!resource.getTenantId().getId().equals(ModelConstants.NULL_UUID)) {
257   - Tenant tenant = tenantDao.findById(tenantId, resource.getTenantId().getId());
258   - if (tenant == null) {
259   - throw new DataValidationException("Resource is referencing to non-existent tenant!");
260   - }
261   - }
262   - if (resource.getResourceType().equals(ResourceType.LWM2M_MODEL) && toLwM2mObject(resource) == null) {
263   - throw new DataValidationException(String.format("Could not parse the XML of objectModel with name %s", resource.getSearchText()));
264   - }
265   - }
266   - };
267   -
268   - private PaginatedRemover<TenantId, TbResource> tenantResourcesRemover =
269   - new PaginatedRemover<>() {
270   -
271   - @Override
272   - protected PageData<TbResource> findEntities(TenantId tenantId, TenantId id, PageLink pageLink) {
273   - return resourceDao.findAllByTenantId(id, pageLink);
274   - }
275   -
276   - @Override
277   - protected void removeEntity(TenantId tenantId, TbResource entity) {
278   - deleteResource(tenantId, new TbResourceId(entity.getUuidId()));
279   - }
280   - };
281   -
282   - protected Optional<ConstraintViolationException> extractConstraintViolationException(Exception t) {
283   - if (t instanceof ConstraintViolationException) {
284   - return Optional.of((ConstraintViolationException) t);
285   - } else if (t.getCause() instanceof ConstraintViolationException) {
286   - return Optional.of((ConstraintViolationException) (t.getCause()));
287   - } else {
288   - return Optional.empty();
289   - }
290   - }
291 202 }
... ...
application/src/main/java/org/thingsboard/server/service/resource/TbResourceService.java renamed from common/dao-api/src/main/java/org/thingsboard/server/dao/resource/TbResourceService.java
... ... @@ -13,24 +13,23 @@
13 13 * See the License for the specific language governing permissions and
14 14 * limitations under the License.
15 15 */
16   -package org.thingsboard.server.dao.resource;
  16 +package org.thingsboard.server.service.resource;
17 17
18   -import org.eclipse.leshan.core.model.InvalidDDFFileException;
  18 +import org.thingsboard.server.common.data.ResourceType;
19 19 import org.thingsboard.server.common.data.TbResource;
20 20 import org.thingsboard.server.common.data.TbResourceInfo;
21   -import org.thingsboard.server.common.data.ResourceType;
  21 +import org.thingsboard.server.common.data.exception.ThingsboardException;
22 22 import org.thingsboard.server.common.data.id.TbResourceId;
23 23 import org.thingsboard.server.common.data.id.TenantId;
24 24 import org.thingsboard.server.common.data.lwm2m.LwM2mObject;
25 25 import org.thingsboard.server.common.data.page.PageData;
26 26 import org.thingsboard.server.common.data.page.PageLink;
27 27
28   -import java.io.IOException;
29 28 import java.util.List;
30 29
31   -
32 30 public interface TbResourceService {
33   - TbResource saveResource(TbResource resource) throws InvalidDDFFileException, IOException;
  31 +
  32 + TbResource saveResource(TbResource resource) throws ThingsboardException;
34 33
35 34 TbResource getResource(TenantId tenantId, ResourceType resourceType, String resourceId);
36 35
... ... @@ -55,4 +54,5 @@ public interface TbResourceService {
55 54 void deleteResource(TenantId tenantId, TbResourceId resourceId);
56 55
57 56 void deleteResourcesByTenantId(TenantId tenantId);
  57 +
58 58 }
... ...
... ... @@ -17,8 +17,10 @@ package org.thingsboard.server.service.security.auth.oauth2;
17 17
18 18 import com.fasterxml.jackson.databind.ObjectMapper;
19 19 import com.fasterxml.jackson.databind.node.ObjectNode;
  20 +import lombok.Getter;
20 21 import lombok.extern.slf4j.Slf4j;
21 22 import org.springframework.beans.factory.annotation.Autowired;
  23 +import org.springframework.beans.factory.annotation.Value;
22 24 import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
23 25 import org.springframework.security.core.userdetails.UsernameNotFoundException;
24 26 import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
... ... @@ -85,6 +87,10 @@ public abstract class AbstractOAuth2ClientMapper {
85 87 @Autowired
86 88 protected TbClusterService tbClusterService;
87 89
  90 + @Value("${edges.enabled}")
  91 + @Getter
  92 + private boolean edgesEnabled;
  93 +
88 94 private final Lock userCreationLock = new ReentrantLock();
89 95
90 96 protected SecurityUser getOrCreateSecurityUserFromOAuth2User(OAuth2User oauth2User, OAuth2ClientRegistrationInfo clientRegistration) {
... ... @@ -171,6 +177,9 @@ public abstract class AbstractOAuth2ClientMapper {
171 177 tenant.setTitle(tenantName);
172 178 tenant = tenantService.saveTenant(tenant);
173 179 installScripts.createDefaultRuleChains(tenant.getId());
  180 + if (edgesEnabled) {
  181 + installScripts.createDefaultEdgeRuleChains(tenant.getId());
  182 + }
174 183 tenantProfileCache.evict(tenant.getId());
175 184 tbClusterService.onTenantChange(tenant, null);
176 185 tbClusterService.onEntityStateChange(tenant.getId(), tenant.getId(),
... ...
... ... @@ -57,7 +57,7 @@ import org.thingsboard.server.dao.device.provision.ProvisionFailedException;
57 57 import org.thingsboard.server.dao.device.provision.ProvisionRequest;
58 58 import org.thingsboard.server.dao.device.provision.ProvisionResponse;
59 59 import org.thingsboard.server.dao.relation.RelationService;
60   -import org.thingsboard.server.dao.resource.TbResourceService;
  60 +import org.thingsboard.server.dao.resource.ResourceService;
61 61 import org.thingsboard.server.dao.tenant.TbTenantProfileCache;
62 62 import org.thingsboard.server.gen.transport.TransportProtos;
63 63 import org.thingsboard.server.gen.transport.TransportProtos.DeviceInfoProto;
... ... @@ -117,7 +117,7 @@ public class DefaultTransportApiService implements TransportApiService {
117 117 private final TbClusterService tbClusterService;
118 118 private final DataDecodingEncodingService dataDecodingEncodingService;
119 119 private final DeviceProvisionService deviceProvisionService;
120   - private final TbResourceService resourceService;
  120 + private final ResourceService resourceService;
121 121
122 122 private final ConcurrentMap<String, ReentrantLock> deviceCreationLocks = new ConcurrentHashMap<>();
123 123
... ... @@ -126,7 +126,7 @@ public class DefaultTransportApiService implements TransportApiService {
126 126 RelationService relationService, DeviceCredentialsService deviceCredentialsService,
127 127 DeviceStateService deviceStateService, DbCallbackExecutorService dbCallbackExecutorService,
128 128 TbClusterService tbClusterService, DataDecodingEncodingService dataDecodingEncodingService,
129   - DeviceProvisionService deviceProvisionService, TbResourceService resourceService) {
  129 + DeviceProvisionService deviceProvisionService, ResourceService resourceService) {
130 130 this.deviceProfileCache = deviceProfileCache;
131 131 this.tenantProfileCache = tenantProfileCache;
132 132 this.apiUsageStateService = apiUsageStateService;
... ...
1   - ______ __ _ __ __
2   - /_ __/ / /_ (_) ____ ____ _ _____ / /_ ____ ____ _ _____ ____/ /
3   - / / / __ \ / / / __ \ / __ `/ / ___/ / __ \ / __ \ / __ `/ / ___/ / __ /
4   - / / / / / / / / / / / / / /_/ / (__ ) / /_/ // /_/ // /_/ / / / / /_/ /
5   -/_/ /_/ /_/ /_/ /_/ /_/ \__, / /____/ /_.___/ \____/ \__,_/ /_/ \__,_/
  1 + ______ __ _ ____ __
  2 + /_ __/ / /_ (_) ____ ____ _ _____ / __ ) ____ ____ _ _____ ____/ /
  3 + / / / __ \ / / / __ \ / __ `/ / ___/ / __ | / __ \ / __ `/ / ___/ / __ /
  4 + / / / / / / / / / / / / / /_/ / (__ ) / /_/ / / /_/ // /_/ / / / / /_/ /
  5 +/_/ /_/ /_/ /_/ /_/ /_/ \__, / /____/ /_____/ \____/ \__,_/ /_/ \__,_/
6 6 /____/
7 7
8 8 ===================================================
... ...
... ... @@ -38,6 +38,9 @@
38 38 <!-- <logger name="org.eclipse.californium.scandium.DTLSConnector" level="TRACE" />-->
39 39 <!-- <logger name="org.eclipse.californium.scandium.dtls.Handshaker" level="DEBUG" />-->
40 40
  41 + <!-- Top Rule Nodes by max execution time -->
  42 +<!-- <logger name="org.thingsboard.server.service.queue.TbMsgPackProcessingContext" level="DEBUG" /> -->
  43 +
41 44 <logger name="com.microsoft.azure.servicebus.primitives.CoreMessageReceiver" level="OFF" />
42 45
43 46 <root level="INFO">
... ...
... ... @@ -243,6 +243,7 @@ sql:
243 243 batch_max_delay: "${SQL_TS_LATEST_BATCH_MAX_DELAY_MS:100}"
244 244 stats_print_interval_ms: "${SQL_TS_LATEST_BATCH_STATS_PRINT_MS:10000}"
245 245 batch_threads: "${SQL_TS_LATEST_BATCH_THREADS:4}"
  246 + update_by_latest_ts: "${SQL_TS_UPDATE_BY_LATEST_TIMESTAMP:true}"
246 247 # Specify whether to sort entities before batch update. Should be enabled for cluster mode to avoid deadlocks
247 248 batch_sort: "${SQL_BATCH_SORT:false}"
248 249 # Specify whether to remove null characters from strValue of attributes and timeseries before insert
... ... @@ -516,7 +517,7 @@ js:
516 517 # Built-in JVM JavaScript environment properties
517 518 local:
518 519 # Use Sandboxed (secured) JVM JavaScript environment
519   - use_js_sandbox: "${USE_LOCAL_JS_SANDBOX:false}"
  520 + use_js_sandbox: "${USE_LOCAL_JS_SANDBOX:true}"
520 521 # Specify thread pool size for JavaScript sandbox resource monitor
521 522 monitor_thread_pool_size: "${LOCAL_JS_SANDBOX_MONITOR_THREAD_POOL_SIZE:4}"
522 523 # Maximum CPU time in milliseconds allowed for script execution
... ...
... ... @@ -38,6 +38,7 @@ import org.thingsboard.server.common.data.security.Authority;
38 38 import org.thingsboard.server.dao.model.ModelConstants;
39 39 import org.thingsboard.server.edge.imitator.EdgeImitator;
40 40 import org.thingsboard.server.gen.edge.AssetUpdateMsg;
  41 +import org.thingsboard.server.gen.edge.DeviceProfileUpdateMsg;
41 42 import org.thingsboard.server.gen.edge.DeviceUpdateMsg;
42 43 import org.thingsboard.server.gen.edge.RuleChainUpdateMsg;
43 44 import org.thingsboard.server.gen.edge.UserCredentialsUpdateMsg;
... ... @@ -672,28 +673,32 @@ public abstract class BaseEdgeControllerTest extends AbstractControllerTest {
672 673 edgeImitator.ignoreType(UserCredentialsUpdateMsg.class);
673 674 edgeImitator.expectMessageAmount(7);
674 675 edgeImitator.connect();
675   - edgeImitator.waitForMessages();
  676 + Assert.assertTrue(edgeImitator.waitForMessages());
676 677
677 678 Assert.assertEquals(7, edgeImitator.getDownlinkMsgs().size());
678 679 Assert.assertTrue(edgeImitator.findMessageByType(RuleChainUpdateMsg.class).isPresent());
  680 + Assert.assertTrue(edgeImitator.findMessageByType(DeviceProfileUpdateMsg.class).isPresent());
679 681 Assert.assertTrue(edgeImitator.findMessageByType(DeviceUpdateMsg.class).isPresent());
680 682 Assert.assertTrue(edgeImitator.findMessageByType(AssetUpdateMsg.class).isPresent());
681 683 Assert.assertTrue(edgeImitator.findMessageByType(UserUpdateMsg.class).isPresent());
682 684
683 685 edgeImitator.getDownlinkMsgs().clear();
684 686
685   - edgeImitator.expectMessageAmount(4);
  687 + edgeImitator.expectMessageAmount(7);
686 688 doPost("/api/edge/sync/" + edge.getId());
687   - edgeImitator.waitForMessages();
  689 + Assert.assertTrue(edgeImitator.waitForMessages());
688 690
689   - Assert.assertEquals(4, edgeImitator.getDownlinkMsgs().size());
  691 + Assert.assertEquals(7, edgeImitator.getDownlinkMsgs().size());
690 692 Assert.assertTrue(edgeImitator.findMessageByType(RuleChainUpdateMsg.class).isPresent());
  693 + Assert.assertTrue(edgeImitator.findMessageByType(DeviceProfileUpdateMsg.class).isPresent());
691 694 Assert.assertTrue(edgeImitator.findMessageByType(DeviceUpdateMsg.class).isPresent());
692 695 Assert.assertTrue(edgeImitator.findMessageByType(AssetUpdateMsg.class).isPresent());
693 696 Assert.assertTrue(edgeImitator.findMessageByType(UserUpdateMsg.class).isPresent());
694 697
695 698 edgeImitator.allowIgnoredTypes();
696   - edgeImitator.disconnect();
  699 + try {
  700 + edgeImitator.disconnect();
  701 + } catch (Exception ignored) {}
697 702
698 703 doDelete("/api/device/" + savedDevice.getId().getId().toString())
699 704 .andExpect(status().isOk());
... ...
... ... @@ -42,7 +42,6 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.
42 42 public class BaseEdgeEventControllerTest extends AbstractControllerTest {
43 43
44 44 private Tenant savedTenant;
45   - private TenantId tenantId;
46 45 private User tenantAdmin;
47 46
48 47 @Before
... ... @@ -52,7 +51,6 @@ public class BaseEdgeEventControllerTest extends AbstractControllerTest {
52 51 Tenant tenant = new Tenant();
53 52 tenant.setTitle("My tenant");
54 53 savedTenant = doPost("/api/tenant", tenant, Tenant.class);
55   - tenantId = savedTenant.getId();
56 54 Assert.assertNotNull(savedTenant);
57 55
58 56 tenantAdmin = new User();
... ... @@ -63,6 +61,10 @@ public class BaseEdgeEventControllerTest extends AbstractControllerTest {
63 61 tenantAdmin.setLastName("Downs");
64 62
65 63 tenantAdmin = createUserAndLogin(tenantAdmin, "testPassword1");
  64 + // sleep 1 seconds to avoid CREDENTIALS updated message for the user
  65 + // user credentials is going to be stored and updated event pushed to edge notification service
  66 + // while service will be processing this event edge could be already added and additional message will be pushed
  67 + Thread.sleep(1000);
66 68 }
67 69
68 70 @After
... ... @@ -75,7 +77,6 @@ public class BaseEdgeEventControllerTest extends AbstractControllerTest {
75 77
76 78 @Test
77 79 public void testGetEdgeEvents() throws Exception {
78   - Thread.sleep(500);
79 80 Edge edge = constructEdge("TestEdge", "default");
80 81 edge = doPost("/api/edge", edge, Edge.class);
81 82
... ... @@ -83,29 +84,31 @@ public class BaseEdgeEventControllerTest extends AbstractControllerTest {
83 84 Device savedDevice = doPost("/api/device", device, Device.class);
84 85
85 86 doPost("/api/edge/" + edge.getId().toString() + "/device/" + savedDevice.getId().toString(), Device.class);
86   - Thread.sleep(500);
87 87
88 88 Asset asset = constructAsset("TestAsset", "default");
89 89 Asset savedAsset = doPost("/api/asset", asset, Asset.class);
90 90
91 91 doPost("/api/edge/" + edge.getId().toString() + "/asset/" + savedAsset.getId().toString(), Asset.class);
92   - Thread.sleep(500);
93 92
94 93 EntityRelation relation = new EntityRelation(savedAsset.getId(), savedDevice.getId(), EntityRelation.CONTAINS_TYPE);
95 94
96 95 doPost("/api/relation", relation);
97   - Thread.sleep(500);
98 96
99   - List<EdgeEvent> edgeEvents = doGetTypedWithTimePageLink("/api/edge/" + edge.getId().toString() + "/events?",
100   - new TypeReference<PageData<EdgeEvent>>() {
101   - }, new TimePageLink(4)).getData();
102   -
103   - Assert.assertFalse(edgeEvents.isEmpty());
  97 + // wait while edge event for the relation entity persisted to DB
  98 + Thread.sleep(100);
  99 + List<EdgeEvent> edgeEvents;
  100 + int attempt = 1;
  101 + do {
  102 + edgeEvents = doGetTypedWithTimePageLink("/api/edge/" + edge.getId().toString() + "/events?",
  103 + new TypeReference<PageData<EdgeEvent>>() {}, new TimePageLink(4)).getData();
  104 + attempt++;
  105 + Thread.sleep(100);
  106 + } while (edgeEvents.size() != 4 && attempt < 5);
104 107 Assert.assertEquals(4, edgeEvents.size());
105   - Assert.assertEquals(EdgeEventType.RULE_CHAIN, edgeEvents.get(0).getType());
106   - Assert.assertEquals(EdgeEventType.DEVICE, edgeEvents.get(1).getType());
107   - Assert.assertEquals(EdgeEventType.ASSET, edgeEvents.get(2).getType());
108   - Assert.assertEquals(EdgeEventType.RELATION, edgeEvents.get(3).getType());
  108 + Assert.assertTrue(edgeEvents.stream().anyMatch(ee -> EdgeEventType.RULE_CHAIN.equals(ee.getType())));
  109 + Assert.assertTrue(edgeEvents.stream().anyMatch(ee -> EdgeEventType.DEVICE.equals(ee.getType())));
  110 + Assert.assertTrue(edgeEvents.stream().anyMatch(ee -> EdgeEventType.ASSET.equals(ee.getType())));
  111 + Assert.assertTrue(edgeEvents.stream().anyMatch(ee -> EdgeEventType.RELATION.equals(ee.getType())));
109 112 }
110 113
111 114 private Device constructDevice(String name, String type) {
... ...
... ... @@ -32,10 +32,12 @@ import org.junit.Assert;
32 32 import org.junit.Before;
33 33 import org.junit.Test;
34 34 import org.springframework.beans.factory.annotation.Autowired;
  35 +import org.thingsboard.common.util.JacksonUtil;
35 36 import org.thingsboard.server.common.data.Customer;
36 37 import org.thingsboard.server.common.data.Dashboard;
37 38 import org.thingsboard.server.common.data.DataConstants;
38 39 import org.thingsboard.server.common.data.Device;
  40 +import org.thingsboard.server.common.data.DeviceProfile;
39 41 import org.thingsboard.server.common.data.EntityType;
40 42 import org.thingsboard.server.common.data.EntityView;
41 43 import org.thingsboard.server.common.data.Tenant;
... ... @@ -45,6 +47,15 @@ import org.thingsboard.server.common.data.alarm.AlarmInfo;
45 47 import org.thingsboard.server.common.data.alarm.AlarmSeverity;
46 48 import org.thingsboard.server.common.data.alarm.AlarmStatus;
47 49 import org.thingsboard.server.common.data.asset.Asset;
  50 +import org.thingsboard.server.common.data.device.profile.AlarmCondition;
  51 +import org.thingsboard.server.common.data.device.profile.AlarmConditionFilter;
  52 +import org.thingsboard.server.common.data.device.profile.AlarmConditionFilterKey;
  53 +import org.thingsboard.server.common.data.device.profile.AlarmConditionKeyType;
  54 +import org.thingsboard.server.common.data.device.profile.AlarmRule;
  55 +import org.thingsboard.server.common.data.device.profile.AllowCreateNewDevicesDeviceProfileProvisionConfiguration;
  56 +import org.thingsboard.server.common.data.device.profile.DeviceProfileAlarm;
  57 +import org.thingsboard.server.common.data.device.profile.DeviceProfileData;
  58 +import org.thingsboard.server.common.data.device.profile.SimpleAlarmConditionSpec;
48 59 import org.thingsboard.server.common.data.edge.Edge;
49 60 import org.thingsboard.server.common.data.edge.EdgeEvent;
50 61 import org.thingsboard.server.common.data.edge.EdgeEventActionType;
... ... @@ -57,6 +68,9 @@ import org.thingsboard.server.common.data.id.TenantId;
57 68 import org.thingsboard.server.common.data.id.UserId;
58 69 import org.thingsboard.server.common.data.page.PageData;
59 70 import org.thingsboard.server.common.data.page.PageLink;
  71 +import org.thingsboard.server.common.data.query.EntityKeyValueType;
  72 +import org.thingsboard.server.common.data.query.FilterPredicateValue;
  73 +import org.thingsboard.server.common.data.query.NumericFilterPredicate;
60 74 import org.thingsboard.server.common.data.relation.EntityRelation;
61 75 import org.thingsboard.server.common.data.relation.RelationTypeGroup;
62 76 import org.thingsboard.server.common.data.rule.RuleChain;
... ... @@ -71,7 +85,6 @@ import org.thingsboard.server.common.data.widget.WidgetsBundle;
71 85 import org.thingsboard.server.common.transport.adaptor.JsonConverter;
72 86 import org.thingsboard.server.controller.AbstractControllerTest;
73 87 import org.thingsboard.server.dao.edge.EdgeEventService;
74   -import org.thingsboard.common.util.JacksonUtil;
75 88 import org.thingsboard.server.edge.imitator.EdgeImitator;
76 89 import org.thingsboard.server.gen.edge.AlarmUpdateMsg;
77 90 import org.thingsboard.server.gen.edge.AssetUpdateMsg;
... ... @@ -81,6 +94,7 @@ import org.thingsboard.server.gen.edge.CustomerUpdateMsg;
81 94 import org.thingsboard.server.gen.edge.DashboardUpdateMsg;
82 95 import org.thingsboard.server.gen.edge.DeviceCredentialsRequestMsg;
83 96 import org.thingsboard.server.gen.edge.DeviceCredentialsUpdateMsg;
  97 +import org.thingsboard.server.gen.edge.DeviceProfileUpdateMsg;
84 98 import org.thingsboard.server.gen.edge.DeviceRpcCallMsg;
85 99 import org.thingsboard.server.gen.edge.DeviceUpdateMsg;
86 100 import org.thingsboard.server.gen.edge.EdgeConfiguration;
... ... @@ -106,6 +120,7 @@ import java.util.List;
106 120 import java.util.Map;
107 121 import java.util.Optional;
108 122 import java.util.Random;
  123 +import java.util.TreeMap;
109 124 import java.util.UUID;
110 125 import java.util.concurrent.TimeUnit;
111 126
... ... @@ -114,6 +129,8 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.
114 129 @Slf4j
115 130 abstract public class BaseEdgeTest extends AbstractControllerTest {
116 131
  132 + private static final String CUSTOM_DEVICE_PROFILE_NAME = "Thermostat";
  133 +
117 134 private Tenant savedTenant;
118 135 private TenantId tenantId;
119 136 private User tenantAdmin;
... ... @@ -145,17 +162,25 @@ abstract public class BaseEdgeTest extends AbstractControllerTest {
145 162 tenantAdmin.setLastName("Downs");
146 163
147 164 tenantAdmin = createUserAndLogin(tenantAdmin, "testPassword1");
  165 + // sleep 1 seconds to avoid CREDENTIALS updated message for the user
  166 + // user credentials is going to be stored and updated event pushed to edge notification service
  167 + // while service will be processing this event edge could be already added and additional message will be pushed
  168 + Thread.sleep(1000);
  169 +
148 170 installation();
149 171
150 172 edgeImitator = new EdgeImitator("localhost", 7070, edge.getRoutingKey(), edge.getSecret());
151   - // should be less, but events from SyncEdgeService stack with events from controller. will be fixed in next releases
152   - edgeImitator.expectMessageAmount(7);
  173 + // TODO: voba - should be less, but events from SyncEdgeService stack with events from controller. will be fixed in next releases
  174 + // so ideally sync process should check current edge queue and add only missing entities to the edge queue
  175 + edgeImitator.expectMessageAmount(10);
153 176 edgeImitator.connect();
154 177 }
155 178
156 179 @After
157 180 public void afterTest() throws Exception {
158   - edgeImitator.disconnect();
  181 + try {
  182 + edgeImitator.disconnect();
  183 + } catch (Exception ignored) {}
159 184
160 185 loginSysAdmin();
161 186
... ... @@ -163,23 +188,63 @@ abstract public class BaseEdgeTest extends AbstractControllerTest {
163 188 .andExpect(status().isOk());
164 189 }
165 190
166   -
167 191 @Test
168 192 public void test() throws Exception {
169 193 testReceivedInitialData();
  194 + int expectedDownlinkSize = 10;
  195 + Assert.assertEquals(expectedDownlinkSize, edgeImitator.getDownlinkMsgs().size());
  196 +
170 197 testDevices();
  198 + expectedDownlinkSize = expectedDownlinkSize + 4;
  199 + Assert.assertEquals(expectedDownlinkSize, edgeImitator.getDownlinkMsgs().size());
  200 +
171 201 testAssets();
  202 + expectedDownlinkSize = expectedDownlinkSize + 4;
  203 + Assert.assertEquals(expectedDownlinkSize, edgeImitator.getDownlinkMsgs().size());
  204 +
172 205 testRuleChains();
  206 + expectedDownlinkSize = expectedDownlinkSize + 3;
  207 + Assert.assertEquals(expectedDownlinkSize, edgeImitator.getDownlinkMsgs().size());
  208 +
173 209 testDashboards();
  210 + expectedDownlinkSize = expectedDownlinkSize + 3;
  211 + Assert.assertEquals(expectedDownlinkSize, edgeImitator.getDownlinkMsgs().size());
  212 +
174 213 testRelations();
  214 + expectedDownlinkSize = expectedDownlinkSize + 2;
  215 + Assert.assertEquals(expectedDownlinkSize, edgeImitator.getDownlinkMsgs().size());
  216 +
175 217 testAlarms();
  218 + expectedDownlinkSize = expectedDownlinkSize + 3;
  219 + Assert.assertEquals(expectedDownlinkSize, edgeImitator.getDownlinkMsgs().size());
  220 +
176 221 testEntityView();
  222 + expectedDownlinkSize = expectedDownlinkSize + 2;
  223 + Assert.assertEquals(expectedDownlinkSize, edgeImitator.getDownlinkMsgs().size());
  224 +
177 225 testCustomer();
  226 + expectedDownlinkSize = expectedDownlinkSize + 2;
  227 + Assert.assertEquals(expectedDownlinkSize, edgeImitator.getDownlinkMsgs().size());
  228 +
178 229 testWidgetsBundleAndWidgetType();
  230 + expectedDownlinkSize = expectedDownlinkSize + 4;
  231 + Assert.assertEquals(expectedDownlinkSize, edgeImitator.getDownlinkMsgs().size());
  232 +
179 233 testTimeseries();
  234 + expectedDownlinkSize = expectedDownlinkSize + 1;
  235 + Assert.assertEquals(expectedDownlinkSize, edgeImitator.getDownlinkMsgs().size());
  236 +
180 237 testAttributes();
  238 + expectedDownlinkSize = expectedDownlinkSize + 3;
  239 + Assert.assertEquals(expectedDownlinkSize, edgeImitator.getDownlinkMsgs().size());
  240 +
181 241 testSendMessagesToCloud();
  242 + expectedDownlinkSize = expectedDownlinkSize + 9;
  243 + Assert.assertEquals(expectedDownlinkSize, edgeImitator.getDownlinkMsgs().size());
  244 +
182 245 testRpcCall();
  246 + expectedDownlinkSize = expectedDownlinkSize + 1;
  247 + Assert.assertEquals(expectedDownlinkSize, edgeImitator.getDownlinkMsgs().size());
183 248 }
184 249
185 250 private Device findDeviceByName(String deviceName) throws Exception {
... ... @@ -204,10 +269,10 @@ abstract public class BaseEdgeTest extends AbstractControllerTest {
204 269 return asset;
205 270 }
206 271
207   - private Device saveDevice(String deviceName) throws Exception {
  272 + private Device saveDevice(String deviceName, String type) throws Exception {
208 273 Device device = new Device();
209 274 device.setName(deviceName);
210   - device.setType("test");
  275 + device.setType(type);
211 276 return doPost("/api/device", device, Device.class);
212 277 }
213 278
... ... @@ -233,7 +298,7 @@ abstract public class BaseEdgeTest extends AbstractControllerTest {
233 298 edgeImitator.expectMessageAmount(1);
234 299 edgeEventService.saveAsync(edgeEvent);
235 300 clusterService.onEdgeEventUpdate(tenantId, edge.getId());
236   - edgeImitator.waitForMessages();
  301 + Assert.assertTrue(edgeImitator.waitForMessages());
237 302
238 303 AbstractMessage latestMessage = edgeImitator.getLatestMessage();
239 304 Assert.assertTrue(latestMessage instanceof DeviceRpcCallMsg);
... ... @@ -243,7 +308,7 @@ abstract public class BaseEdgeTest extends AbstractControllerTest {
243 308
244 309 private void testReceivedInitialData() throws Exception {
245 310 log.info("Checking received data");
246   - edgeImitator.waitForMessages();
  311 + Assert.assertTrue(edgeImitator.waitForMessages());
247 312
248 313 EdgeConfiguration configuration = edgeImitator.getConfiguration();
249 314 Assert.assertNotNull(configuration);
... ... @@ -253,9 +318,9 @@ abstract public class BaseEdgeTest extends AbstractControllerTest {
253 318 UserId userId = edgeImitator.getUserId();
254 319 Assert.assertNotNull(userId);
255 320
256   - Optional<DeviceUpdateMsg> optionalMsg1 = edgeImitator.findMessageByType(DeviceUpdateMsg.class);
257   - Assert.assertTrue(optionalMsg1.isPresent());
258   - DeviceUpdateMsg deviceUpdateMsg = optionalMsg1.get();
  321 + Optional<DeviceUpdateMsg> deviceUpdateMsgOpt = edgeImitator.findMessageByType(DeviceUpdateMsg.class);
  322 + Assert.assertTrue(deviceUpdateMsgOpt.isPresent());
  323 + DeviceUpdateMsg deviceUpdateMsg = deviceUpdateMsgOpt.get();
259 324 Assert.assertEquals(UpdateMsgType.ENTITY_CREATED_RPC_MESSAGE, deviceUpdateMsg.getMsgType());
260 325 UUID deviceUUID = new UUID(deviceUpdateMsg.getIdMSB(), deviceUpdateMsg.getIdLSB());
261 326 Device device = doGet("/api/device/" + deviceUUID.toString(), Device.class);
... ... @@ -264,9 +329,25 @@ abstract public class BaseEdgeTest extends AbstractControllerTest {
264 329 new TypeReference<PageData<Device>>() {}, new PageLink(100)).getData();
265 330 Assert.assertTrue(edgeDevices.contains(device));
266 331
267   - Optional<AssetUpdateMsg> optionalMsg2 = edgeImitator.findMessageByType(AssetUpdateMsg.class);
268   - Assert.assertTrue(optionalMsg2.isPresent());
269   - AssetUpdateMsg assetUpdateMsg = optionalMsg2.get();
  332 + List<DeviceProfileUpdateMsg> deviceProfileUpdateMsgList = edgeImitator.findAllMessagesByType(DeviceProfileUpdateMsg.class);
  333 + Assert.assertEquals(3, deviceProfileUpdateMsgList.size());
  334 + Optional<DeviceProfileUpdateMsg> deviceProfileUpdateMsgOpt =
  335 + deviceProfileUpdateMsgList.stream().filter(dfum -> CUSTOM_DEVICE_PROFILE_NAME.equals(dfum.getName())).findAny();
  336 + Assert.assertTrue(deviceProfileUpdateMsgOpt.isPresent());
  337 + DeviceProfileUpdateMsg deviceProfileUpdateMsg = deviceProfileUpdateMsgOpt.get();
  338 + Assert.assertEquals(UpdateMsgType.ENTITY_CREATED_RPC_MESSAGE, deviceProfileUpdateMsg.getMsgType());
  339 + UUID deviceProfileUUID = new UUID(deviceProfileUpdateMsg.getIdMSB(), deviceProfileUpdateMsg.getIdLSB());
  340 + DeviceProfile deviceProfile = doGet("/api/deviceProfile/" + deviceProfileUUID.toString(), DeviceProfile.class);
  341 + Assert.assertNotNull(deviceProfile);
  342 + Assert.assertNotNull(deviceProfile.getProfileData());
  343 + Assert.assertNotNull(deviceProfile.getProfileData().getAlarms());
  344 + Assert.assertNotNull(deviceProfile.getProfileData().getAlarms().get(0).getClearRule());
  345 +
  346 + testAutoGeneratedCodeByProtobuf(deviceProfileUpdateMsg);
  347 +
  348 + Optional<AssetUpdateMsg> assetUpdateMsgOpt = edgeImitator.findMessageByType(AssetUpdateMsg.class);
  349 + Assert.assertTrue(assetUpdateMsgOpt.isPresent());
  350 + AssetUpdateMsg assetUpdateMsg = assetUpdateMsgOpt.get();
270 351 Assert.assertEquals(UpdateMsgType.ENTITY_CREATED_RPC_MESSAGE, assetUpdateMsg.getMsgType());
271 352 UUID assetUUID = new UUID(assetUpdateMsg.getIdMSB(), assetUpdateMsg.getIdLSB());
272 353 Asset asset = doGet("/api/asset/" + assetUUID.toString(), Asset.class);
... ... @@ -277,9 +358,9 @@ abstract public class BaseEdgeTest extends AbstractControllerTest {
277 358
278 359 testAutoGeneratedCodeByProtobuf(assetUpdateMsg);
279 360
280   - Optional<RuleChainUpdateMsg> optionalMsg3 = edgeImitator.findMessageByType(RuleChainUpdateMsg.class);
281   - Assert.assertTrue(optionalMsg3.isPresent());
282   - RuleChainUpdateMsg ruleChainUpdateMsg = optionalMsg3.get();
  361 + Optional<RuleChainUpdateMsg> ruleChainUpdateMsgOpt = edgeImitator.findMessageByType(RuleChainUpdateMsg.class);
  362 + Assert.assertTrue(ruleChainUpdateMsgOpt.isPresent());
  363 + RuleChainUpdateMsg ruleChainUpdateMsg = ruleChainUpdateMsgOpt.get();
283 364 Assert.assertEquals(UpdateMsgType.ENTITY_UPDATED_RPC_MESSAGE, ruleChainUpdateMsg.getMsgType());
284 365 UUID ruleChainUUID = new UUID(ruleChainUpdateMsg.getIdMSB(), ruleChainUpdateMsg.getIdLSB());
285 366 RuleChain ruleChain = doGet("/api/ruleChain/" + ruleChainUUID.toString(), RuleChain.class);
... ... @@ -296,13 +377,12 @@ abstract public class BaseEdgeTest extends AbstractControllerTest {
296 377 private void testDevices() throws Exception {
297 378 log.info("Testing devices");
298 379
299   - Device savedDevice = saveDevice("Edge Device 2");
300   -
  380 + // 1
301 381 edgeImitator.expectMessageAmount(1);
  382 + Device savedDevice = saveDevice("Edge Device 2", "Default");
302 383 doPost("/api/edge/" + edge.getId().getId().toString()
303 384 + "/device/" + savedDevice.getId().getId().toString(), Device.class);
304   - edgeImitator.waitForMessages();
305   -
  385 + Assert.assertTrue(edgeImitator.waitForMessages());
306 386 AbstractMessage latestMessage = edgeImitator.getLatestMessage();
307 387 Assert.assertTrue(latestMessage instanceof DeviceUpdateMsg);
308 388 DeviceUpdateMsg deviceUpdateMsg = (DeviceUpdateMsg) latestMessage;
... ... @@ -312,11 +392,11 @@ abstract public class BaseEdgeTest extends AbstractControllerTest {
312 392 Assert.assertEquals(deviceUpdateMsg.getName(), savedDevice.getName());
313 393 Assert.assertEquals(deviceUpdateMsg.getType(), savedDevice.getType());
314 394
  395 + // 2
315 396 edgeImitator.expectMessageAmount(1);
316 397 doDelete("/api/edge/" + edge.getId().getId().toString()
317 398 + "/device/" + savedDevice.getId().getId().toString(), Device.class);
318   - edgeImitator.waitForMessages();
319   -
  399 + Assert.assertTrue(edgeImitator.waitForMessages());
320 400 latestMessage = edgeImitator.getLatestMessage();
321 401 Assert.assertTrue(latestMessage instanceof DeviceUpdateMsg);
322 402 deviceUpdateMsg = (DeviceUpdateMsg) latestMessage;
... ... @@ -324,11 +404,34 @@ abstract public class BaseEdgeTest extends AbstractControllerTest {
324 404 Assert.assertEquals(deviceUpdateMsg.getIdMSB(), savedDevice.getUuidId().getMostSignificantBits());
325 405 Assert.assertEquals(deviceUpdateMsg.getIdLSB(), savedDevice.getUuidId().getLeastSignificantBits());
326 406
  407 + // 3
327 408 edgeImitator.expectMessageAmount(1);
328 409 doDelete("/api/device/" + savedDevice.getId().getId().toString())
329 410 .andExpect(status().isOk());
330   - edgeImitator.waitForMessages();
  411 + // we should not get any message because device is not assigned to edge any more
  412 + Assert.assertFalse(edgeImitator.waitForMessages(1));
331 413
  414 + // 4
  415 + edgeImitator.expectMessageAmount(1);
  416 + savedDevice = saveDevice("Edge Device 3", "Default");
  417 + doPost("/api/edge/" + edge.getId().getId().toString()
  418 + + "/device/" + savedDevice.getId().getId().toString(), Device.class);
  419 + Assert.assertTrue(edgeImitator.waitForMessages());
  420 + latestMessage = edgeImitator.getLatestMessage();
  421 + Assert.assertTrue(latestMessage instanceof DeviceUpdateMsg);
  422 + deviceUpdateMsg = (DeviceUpdateMsg) latestMessage;
  423 + Assert.assertEquals(UpdateMsgType.ENTITY_CREATED_RPC_MESSAGE, deviceUpdateMsg.getMsgType());
  424 + Assert.assertEquals(deviceUpdateMsg.getIdMSB(), savedDevice.getUuidId().getMostSignificantBits());
  425 + Assert.assertEquals(deviceUpdateMsg.getIdLSB(), savedDevice.getUuidId().getLeastSignificantBits());
  426 + Assert.assertEquals(deviceUpdateMsg.getName(), savedDevice.getName());
  427 + Assert.assertEquals(deviceUpdateMsg.getType(), savedDevice.getType());
  428 +
  429 + // 5
  430 + edgeImitator.expectMessageAmount(1);
  431 + doDelete("/api/device/" + savedDevice.getId().getId().toString())
  432 + .andExpect(status().isOk());
  433 + // in this case we should get messages because device was assigned to edge
  434 + Assert.assertTrue(edgeImitator.waitForMessages());
332 435 latestMessage = edgeImitator.getLatestMessage();
333 436 Assert.assertTrue(latestMessage instanceof DeviceUpdateMsg);
334 437 deviceUpdateMsg = (DeviceUpdateMsg) latestMessage;
... ... @@ -342,13 +445,13 @@ abstract public class BaseEdgeTest extends AbstractControllerTest {
342 445
343 446 private void testAssets() throws Exception {
344 447 log.info("Testing assets");
345   - Asset savedAsset = saveAsset("Edge Asset 2");
346 448
  449 + // 1
347 450 edgeImitator.expectMessageAmount(1);
  451 + Asset savedAsset = saveAsset("Edge Asset 2");
348 452 doPost("/api/edge/" + edge.getId().getId().toString()
349 453 + "/asset/" + savedAsset.getId().getId().toString(), Asset.class);
350   - edgeImitator.waitForMessages();
351   -
  454 + Assert.assertTrue(edgeImitator.waitForMessages());
352 455 AbstractMessage latestMessage = edgeImitator.getLatestMessage();
353 456 Assert.assertTrue(latestMessage instanceof AssetUpdateMsg);
354 457 AssetUpdateMsg assetUpdateMsg = (AssetUpdateMsg) latestMessage;
... ... @@ -358,11 +461,11 @@ abstract public class BaseEdgeTest extends AbstractControllerTest {
358 461 Assert.assertEquals(assetUpdateMsg.getName(), savedAsset.getName());
359 462 Assert.assertEquals(assetUpdateMsg.getType(), savedAsset.getType());
360 463
  464 + // 2
361 465 edgeImitator.expectMessageAmount(1);
362 466 doDelete("/api/edge/" + edge.getId().getId().toString()
363 467 + "/asset/" + savedAsset.getId().getId().toString(), Asset.class);
364   - edgeImitator.waitForMessages();
365   -
  468 + Assert.assertTrue(edgeImitator.waitForMessages());
366 469 latestMessage = edgeImitator.getLatestMessage();
367 470 Assert.assertTrue(latestMessage instanceof AssetUpdateMsg);
368 471 assetUpdateMsg = (AssetUpdateMsg) latestMessage;
... ... @@ -370,11 +473,32 @@ abstract public class BaseEdgeTest extends AbstractControllerTest {
370 473 Assert.assertEquals(assetUpdateMsg.getIdMSB(), savedAsset.getUuidId().getMostSignificantBits());
371 474 Assert.assertEquals(assetUpdateMsg.getIdLSB(), savedAsset.getUuidId().getLeastSignificantBits());
372 475
  476 + // 3
373 477 edgeImitator.expectMessageAmount(1);
374 478 doDelete("/api/asset/" + savedAsset.getId().getId().toString())
375 479 .andExpect(status().isOk());
376   - edgeImitator.waitForMessages();
  480 + Assert.assertFalse(edgeImitator.waitForMessages(1));
377 481
  482 + // 4
  483 + edgeImitator.expectMessageAmount(1);
  484 + savedAsset = saveAsset("Edge Asset 3");
  485 + doPost("/api/edge/" + edge.getId().getId().toString()
  486 + + "/asset/" + savedAsset.getId().getId().toString(), Asset.class);
  487 + Assert.assertTrue(edgeImitator.waitForMessages());
  488 + latestMessage = edgeImitator.getLatestMessage();
  489 + Assert.assertTrue(latestMessage instanceof AssetUpdateMsg);
  490 + assetUpdateMsg = (AssetUpdateMsg) latestMessage;
  491 + Assert.assertEquals(UpdateMsgType.ENTITY_CREATED_RPC_MESSAGE, assetUpdateMsg.getMsgType());
  492 + Assert.assertEquals(assetUpdateMsg.getIdMSB(), savedAsset.getUuidId().getMostSignificantBits());
  493 + Assert.assertEquals(assetUpdateMsg.getIdLSB(), savedAsset.getUuidId().getLeastSignificantBits());
  494 + Assert.assertEquals(assetUpdateMsg.getName(), savedAsset.getName());
  495 + Assert.assertEquals(assetUpdateMsg.getType(), savedAsset.getType());
  496 +
  497 + // 5
  498 + edgeImitator.expectMessageAmount(1);
  499 + doDelete("/api/asset/" + savedAsset.getId().getId().toString())
  500 + .andExpect(status().isOk());
  501 + Assert.assertTrue(edgeImitator.waitForMessages());
378 502 latestMessage = edgeImitator.getLatestMessage();
379 503 Assert.assertTrue(latestMessage instanceof AssetUpdateMsg);
380 504 assetUpdateMsg = (AssetUpdateMsg) latestMessage;
... ... @@ -387,21 +511,21 @@ abstract public class BaseEdgeTest extends AbstractControllerTest {
387 511
388 512 private void testRuleChains() throws Exception {
389 513 log.info("Testing RuleChains");
  514 +
  515 + // 1
  516 + edgeImitator.expectMessageAmount(1);
390 517 RuleChain ruleChain = new RuleChain();
391 518 ruleChain.setName("Edge Test Rule Chain");
392 519 ruleChain.setType(RuleChainType.EDGE);
393 520 RuleChain savedRuleChain = doPost("/api/ruleChain", ruleChain, RuleChain.class);
394   -
395 521 createRuleChainMetadata(savedRuleChain);
396   -
397   - // Wait before rule chain metadata saved to database before rule chain is assigned to edge
  522 + // sleep 1 seconds to avoid ENTITY_UPDATED_RPC_MESSAGE for the rule chain
  523 + // rule chain metadata is going to be stored and updated event pushed to edge notification service
  524 + // while service will be processing this event assignment rule chain to edge will be completed if bad timing
398 525 Thread.sleep(1000);
399   -
400   - edgeImitator.expectMessageAmount(1);
401 526 doPost("/api/edge/" + edge.getId().getId().toString()
402 527 + "/ruleChain/" + savedRuleChain.getId().getId().toString(), RuleChain.class);
403   - edgeImitator.waitForMessages();
404   -
  528 + Assert.assertTrue(edgeImitator.waitForMessages());
405 529 AbstractMessage latestMessage = edgeImitator.getLatestMessage();
406 530 Assert.assertTrue(latestMessage instanceof RuleChainUpdateMsg);
407 531 RuleChainUpdateMsg ruleChainUpdateMsg = (RuleChainUpdateMsg) latestMessage;
... ... @@ -410,13 +534,14 @@ abstract public class BaseEdgeTest extends AbstractControllerTest {
410 534 Assert.assertEquals(ruleChainUpdateMsg.getIdLSB(), savedRuleChain.getUuidId().getLeastSignificantBits());
411 535 Assert.assertEquals(ruleChainUpdateMsg.getName(), savedRuleChain.getName());
412 536
  537 + // 2
413 538 testRuleChainMetadataRequestMsg(savedRuleChain.getId());
414 539
  540 + // 3
415 541 edgeImitator.expectMessageAmount(1);
416 542 doDelete("/api/edge/" + edge.getId().getId().toString()
417 543 + "/ruleChain/" + savedRuleChain.getId().getId().toString(), RuleChain.class);
418   - edgeImitator.waitForMessages();
419   -
  544 + Assert.assertTrue(edgeImitator.waitForMessages());
420 545 latestMessage = edgeImitator.getLatestMessage();
421 546 Assert.assertTrue(latestMessage instanceof RuleChainUpdateMsg);
422 547 ruleChainUpdateMsg = (RuleChainUpdateMsg) latestMessage;
... ... @@ -424,17 +549,11 @@ abstract public class BaseEdgeTest extends AbstractControllerTest {
424 549 Assert.assertEquals(ruleChainUpdateMsg.getIdMSB(), savedRuleChain.getUuidId().getMostSignificantBits());
425 550 Assert.assertEquals(ruleChainUpdateMsg.getIdLSB(), savedRuleChain.getUuidId().getLeastSignificantBits());
426 551
  552 + // 4
427 553 edgeImitator.expectMessageAmount(1);
428 554 doDelete("/api/ruleChain/" + savedRuleChain.getId().getId().toString())
429 555 .andExpect(status().isOk());
430   - edgeImitator.waitForMessages();
431   -
432   - latestMessage = edgeImitator.getLatestMessage();
433   - Assert.assertTrue(latestMessage instanceof RuleChainUpdateMsg);
434   - ruleChainUpdateMsg = (RuleChainUpdateMsg) latestMessage;
435   - Assert.assertEquals(UpdateMsgType.ENTITY_DELETED_RPC_MESSAGE, ruleChainUpdateMsg.getMsgType());
436   - Assert.assertEquals(ruleChainUpdateMsg.getIdMSB(), savedRuleChain.getUuidId().getMostSignificantBits());
437   - Assert.assertEquals(ruleChainUpdateMsg.getIdLSB(), savedRuleChain.getUuidId().getLeastSignificantBits());
  556 + Assert.assertFalse(edgeImitator.waitForMessages(1));
438 557
439 558 log.info("RuleChains tested successfully");
440 559 }
... ... @@ -452,8 +571,8 @@ abstract public class BaseEdgeTest extends AbstractControllerTest {
452 571 edgeImitator.expectResponsesAmount(1);
453 572 edgeImitator.expectMessageAmount(1);
454 573 edgeImitator.sendUplinkMsg(uplinkMsgBuilder.build());
455   - edgeImitator.waitForResponses();
456   - edgeImitator.waitForMessages();
  574 + Assert.assertTrue(edgeImitator.waitForResponses());
  575 + Assert.assertTrue(edgeImitator.waitForMessages());
457 576
458 577 AbstractMessage latestMessage = edgeImitator.getLatestMessage();
459 578 Assert.assertTrue(latestMessage instanceof RuleChainMetadataUpdateMsg);
... ... @@ -502,15 +621,15 @@ abstract public class BaseEdgeTest extends AbstractControllerTest {
502 621
503 622 private void testDashboards() throws Exception {
504 623 log.info("Testing Dashboards");
  624 +
  625 + // 1
  626 + edgeImitator.expectMessageAmount(1);
505 627 Dashboard dashboard = new Dashboard();
506 628 dashboard.setTitle("Edge Test Dashboard");
507 629 Dashboard savedDashboard = doPost("/api/dashboard", dashboard, Dashboard.class);
508   -
509   - edgeImitator.expectMessageAmount(1);
510 630 doPost("/api/edge/" + edge.getId().getId().toString()
511 631 + "/dashboard/" + savedDashboard.getId().getId().toString(), Dashboard.class);
512   - edgeImitator.waitForMessages();
513   -
  632 + Assert.assertTrue(edgeImitator.waitForMessages());
514 633 AbstractMessage latestMessage = edgeImitator.getLatestMessage();
515 634 Assert.assertTrue(latestMessage instanceof DashboardUpdateMsg);
516 635 DashboardUpdateMsg dashboardUpdateMsg = (DashboardUpdateMsg) latestMessage;
... ... @@ -518,25 +637,24 @@ abstract public class BaseEdgeTest extends AbstractControllerTest {
518 637 Assert.assertEquals(dashboardUpdateMsg.getIdMSB(), savedDashboard.getUuidId().getMostSignificantBits());
519 638 Assert.assertEquals(dashboardUpdateMsg.getIdLSB(), savedDashboard.getUuidId().getLeastSignificantBits());
520 639 Assert.assertEquals(dashboardUpdateMsg.getTitle(), savedDashboard.getName());
521   -
522 640 testAutoGeneratedCodeByProtobuf(dashboardUpdateMsg);
523 641
  642 + // 2
524 643 edgeImitator.expectMessageAmount(1);
525 644 savedDashboard.setTitle("Updated Edge Test Dashboard");
526 645 doPost("/api/dashboard", savedDashboard, Dashboard.class);
527   - edgeImitator.waitForMessages();
528   -
  646 + Assert.assertTrue(edgeImitator.waitForMessages());
529 647 latestMessage = edgeImitator.getLatestMessage();
530 648 Assert.assertTrue(latestMessage instanceof DashboardUpdateMsg);
531 649 dashboardUpdateMsg = (DashboardUpdateMsg) latestMessage;
532 650 Assert.assertEquals(UpdateMsgType.ENTITY_UPDATED_RPC_MESSAGE, dashboardUpdateMsg.getMsgType());
533 651 Assert.assertEquals(dashboardUpdateMsg.getTitle(), savedDashboard.getName());
534 652
  653 + // 3
535 654 edgeImitator.expectMessageAmount(1);
536 655 doDelete("/api/edge/" + edge.getId().getId().toString()
537 656 + "/dashboard/" + savedDashboard.getId().getId().toString(), Dashboard.class);
538   - edgeImitator.waitForMessages();
539   -
  657 + Assert.assertTrue(edgeImitator.waitForMessages());
540 658 latestMessage = edgeImitator.getLatestMessage();
541 659 Assert.assertTrue(latestMessage instanceof DashboardUpdateMsg);
542 660 dashboardUpdateMsg = (DashboardUpdateMsg) latestMessage;
... ... @@ -544,17 +662,11 @@ abstract public class BaseEdgeTest extends AbstractControllerTest {
544 662 Assert.assertEquals(dashboardUpdateMsg.getIdMSB(), savedDashboard.getUuidId().getMostSignificantBits());
545 663 Assert.assertEquals(dashboardUpdateMsg.getIdLSB(), savedDashboard.getUuidId().getLeastSignificantBits());
546 664
  665 + // 4
547 666 edgeImitator.expectMessageAmount(1);
548 667 doDelete("/api/dashboard/" + savedDashboard.getId().getId().toString())
549 668 .andExpect(status().isOk());
550   - edgeImitator.waitForMessages();
551   -
552   - latestMessage = edgeImitator.getLatestMessage();
553   - Assert.assertTrue(latestMessage instanceof DashboardUpdateMsg);
554   - dashboardUpdateMsg = (DashboardUpdateMsg) latestMessage;
555   - Assert.assertEquals(UpdateMsgType.ENTITY_DELETED_RPC_MESSAGE, dashboardUpdateMsg.getMsgType());
556   - Assert.assertEquals(dashboardUpdateMsg.getIdMSB(), savedDashboard.getUuidId().getMostSignificantBits());
557   - Assert.assertEquals(dashboardUpdateMsg.getIdLSB(), savedDashboard.getUuidId().getLeastSignificantBits());
  669 + Assert.assertFalse(edgeImitator.waitForMessages(1));
558 670
559 671 log.info("Dashboards tested successfully");
560 672 }
... ... @@ -562,19 +674,17 @@ abstract public class BaseEdgeTest extends AbstractControllerTest {
562 674 private void testRelations() throws Exception {
563 675 log.info("Testing Relations");
564 676
  677 + // 1
  678 + edgeImitator.expectMessageAmount(1);
565 679 Device device = findDeviceByName("Edge Device 1");
566 680 Asset asset = findAssetByName("Edge Asset 1");
567   -
568 681 EntityRelation relation = new EntityRelation();
569 682 relation.setType("test");
570 683 relation.setFrom(device.getId());
571 684 relation.setTo(asset.getId());
572 685 relation.setTypeGroup(RelationTypeGroup.COMMON);
573   -
574   - edgeImitator.expectMessageAmount(1);
575 686 doPost("/api/relation", relation);
576   - edgeImitator.waitForMessages();
577   -
  687 + Assert.assertTrue(edgeImitator.waitForMessages());
578 688 AbstractMessage latestMessage = edgeImitator.getLatestMessage();
579 689 Assert.assertTrue(latestMessage instanceof RelationUpdateMsg);
580 690 RelationUpdateMsg relationUpdateMsg = (RelationUpdateMsg) latestMessage;
... ... @@ -588,6 +698,7 @@ abstract public class BaseEdgeTest extends AbstractControllerTest {
588 698 Assert.assertEquals(relationUpdateMsg.getToEntityType(), relation.getTo().getEntityType().name());
589 699 Assert.assertEquals(relationUpdateMsg.getTypeGroup(), relation.getTypeGroup().name());
590 700
  701 + // 2
591 702 edgeImitator.expectMessageAmount(1);
592 703 doDelete("/api/relation?" +
593 704 "fromId=" + relation.getFrom().getId().toString() +
... ... @@ -597,8 +708,7 @@ abstract public class BaseEdgeTest extends AbstractControllerTest {
597 708 "&toId=" + relation.getTo().getId().toString() +
598 709 "&toType=" + relation.getTo().getEntityType().name())
599 710 .andExpect(status().isOk());
600   - edgeImitator.waitForMessages();
601   -
  711 + Assert.assertTrue(edgeImitator.waitForMessages());
602 712 latestMessage = edgeImitator.getLatestMessage();
603 713 Assert.assertTrue(latestMessage instanceof RelationUpdateMsg);
604 714 relationUpdateMsg = (RelationUpdateMsg) latestMessage;
... ... @@ -617,18 +727,17 @@ abstract public class BaseEdgeTest extends AbstractControllerTest {
617 727
618 728 private void testAlarms() throws Exception {
619 729 log.info("Testing Alarms");
620   - Device device = findDeviceByName("Edge Device 1");
621 730
  731 + // 1
  732 + edgeImitator.expectMessageAmount(1);
  733 + Device device = findDeviceByName("Edge Device 1");
622 734 Alarm alarm = new Alarm();
623 735 alarm.setOriginator(device.getId());
624 736 alarm.setStatus(AlarmStatus.ACTIVE_UNACK);
625 737 alarm.setType("alarm");
626 738 alarm.setSeverity(AlarmSeverity.CRITICAL);
627   -
628   - edgeImitator.expectMessageAmount(1);
629 739 Alarm savedAlarm = doPost("/api/alarm", alarm, Alarm.class);
630   - edgeImitator.waitForMessages();
631   -
  740 + Assert.assertTrue(edgeImitator.waitForMessages());
632 741 AbstractMessage latestMessage = edgeImitator.getLatestMessage();
633 742 Assert.assertTrue(latestMessage instanceof AlarmUpdateMsg);
634 743 AlarmUpdateMsg alarmUpdateMsg = (AlarmUpdateMsg) latestMessage;
... ... @@ -639,10 +748,10 @@ abstract public class BaseEdgeTest extends AbstractControllerTest {
639 748 Assert.assertEquals(alarmUpdateMsg.getStatus(), savedAlarm.getStatus().name());
640 749 Assert.assertEquals(alarmUpdateMsg.getSeverity(), savedAlarm.getSeverity().name());
641 750
  751 + // 2
642 752 edgeImitator.expectMessageAmount(1);
643 753 doPost("/api/alarm/" + savedAlarm.getId().getId().toString() + "/ack");
644   - edgeImitator.waitForMessages();
645   -
  754 + Assert.assertTrue(edgeImitator.waitForMessages());
646 755 latestMessage = edgeImitator.getLatestMessage();
647 756 Assert.assertTrue(latestMessage instanceof AlarmUpdateMsg);
648 757 alarmUpdateMsg = (AlarmUpdateMsg) latestMessage;
... ... @@ -652,10 +761,10 @@ abstract public class BaseEdgeTest extends AbstractControllerTest {
652 761 Assert.assertEquals(alarmUpdateMsg.getOriginatorName(), device.getName());
653 762 Assert.assertEquals(alarmUpdateMsg.getStatus(), AlarmStatus.ACTIVE_ACK.name());
654 763
  764 + // 3
655 765 edgeImitator.expectMessageAmount(1);
656 766 doPost("/api/alarm/" + savedAlarm.getId().getId().toString() + "/clear");
657   - edgeImitator.waitForMessages();
658   -
  767 + Assert.assertTrue(edgeImitator.waitForMessages());
659 768 latestMessage = edgeImitator.getLatestMessage();
660 769 Assert.assertTrue(latestMessage instanceof AlarmUpdateMsg);
661 770 alarmUpdateMsg = (AlarmUpdateMsg) latestMessage;
... ... @@ -665,26 +774,29 @@ abstract public class BaseEdgeTest extends AbstractControllerTest {
665 774 Assert.assertEquals(alarmUpdateMsg.getOriginatorName(), device.getName());
666 775 Assert.assertEquals(alarmUpdateMsg.getStatus(), AlarmStatus.CLEARED_ACK.name());
667 776
  777 + // 4
  778 + edgeImitator.expectMessageAmount(1);
668 779 doDelete("/api/alarm/" + savedAlarm.getId().getId().toString())
669 780 .andExpect(status().isOk());
  781 + Assert.assertFalse(edgeImitator.waitForMessages(1));
  782 +
670 783 log.info("Alarms tested successfully");
671 784 }
672 785
673 786 private void testEntityView() throws Exception {
674 787 log.info("Testing EntityView");
675   - Device device = findDeviceByName("Edge Device 1");
676 788
  789 + // 1
  790 + edgeImitator.expectMessageAmount(1);
  791 + Device device = findDeviceByName("Edge Device 1");
677 792 EntityView entityView = new EntityView();
678 793 entityView.setName("Edge EntityView 1");
679 794 entityView.setType("test");
680 795 entityView.setEntityId(device.getId());
681 796 EntityView savedEntityView = doPost("/api/entityView", entityView, EntityView.class);
682   -
683   - edgeImitator.expectMessageAmount(1);
684 797 doPost("/api/edge/" + edge.getId().getId().toString()
685 798 + "/entityView/" + savedEntityView.getId().getId().toString(), EntityView.class);
686   - edgeImitator.waitForMessages();
687   -
  799 + Assert.assertTrue(edgeImitator.waitForMessages());
688 800 AbstractMessage latestMessage = edgeImitator.getLatestMessage();
689 801 Assert.assertTrue(latestMessage instanceof EntityViewUpdateMsg);
690 802 EntityViewUpdateMsg entityViewUpdateMsg = (EntityViewUpdateMsg) latestMessage;
... ... @@ -697,11 +809,11 @@ abstract public class BaseEdgeTest extends AbstractControllerTest {
697 809 Assert.assertEquals(entityViewUpdateMsg.getEntityIdLSB(), device.getUuidId().getLeastSignificantBits());
698 810 Assert.assertEquals(entityViewUpdateMsg.getEntityType().name(), device.getId().getEntityType().name());
699 811
  812 + // 2
700 813 edgeImitator.expectMessageAmount(1);
701 814 doDelete("/api/edge/" + edge.getId().getId().toString()
702 815 + "/entityView/" + savedEntityView.getId().getId().toString(), EntityView.class);
703   - edgeImitator.waitForMessages();
704   -
  816 + Assert.assertTrue(edgeImitator.waitForMessages());
705 817 latestMessage = edgeImitator.getLatestMessage();
706 818 Assert.assertTrue(latestMessage instanceof EntityViewUpdateMsg);
707 819 entityViewUpdateMsg = (EntityViewUpdateMsg) latestMessage;
... ... @@ -709,17 +821,11 @@ abstract public class BaseEdgeTest extends AbstractControllerTest {
709 821 Assert.assertEquals(entityViewUpdateMsg.getIdMSB(), savedEntityView.getUuidId().getMostSignificantBits());
710 822 Assert.assertEquals(entityViewUpdateMsg.getIdLSB(), savedEntityView.getUuidId().getLeastSignificantBits());
711 823
  824 + // 3
712 825 edgeImitator.expectMessageAmount(1);
713 826 doDelete("/api/entityView/" + savedEntityView.getId().getId().toString())
714 827 .andExpect(status().isOk());
715   - edgeImitator.waitForMessages();
716   -
717   - latestMessage = edgeImitator.getLatestMessage();
718   - Assert.assertTrue(latestMessage instanceof EntityViewUpdateMsg);
719   - entityViewUpdateMsg = (EntityViewUpdateMsg) latestMessage;
720   - Assert.assertEquals(UpdateMsgType.ENTITY_DELETED_RPC_MESSAGE, entityViewUpdateMsg.getMsgType());
721   - Assert.assertEquals(entityViewUpdateMsg.getIdMSB(), savedEntityView.getUuidId().getMostSignificantBits());
722   - Assert.assertEquals(entityViewUpdateMsg.getIdLSB(), savedEntityView.getUuidId().getLeastSignificantBits());
  828 + Assert.assertFalse(edgeImitator.waitForMessages(1));
723 829
724 830 log.info("EntityView tested successfully");
725 831 }
... ... @@ -727,15 +833,14 @@ abstract public class BaseEdgeTest extends AbstractControllerTest {
727 833 private void testCustomer() throws Exception {
728 834 log.info("Testing Customer");
729 835
  836 + // 1
  837 + edgeImitator.expectMessageAmount(1);
730 838 Customer customer = new Customer();
731 839 customer.setTitle("Edge Customer 1");
732 840 Customer savedCustomer = doPost("/api/customer", customer, Customer.class);
733   -
734   - edgeImitator.expectMessageAmount(1);
735 841 doPost("/api/customer/" + savedCustomer.getId().getId().toString()
736 842 + "/edge/" + edge.getId().getId().toString(), Edge.class);
737   - edgeImitator.waitForMessages();
738   -
  843 + Assert.assertTrue(edgeImitator.waitForMessages());
739 844 AbstractMessage latestMessage = edgeImitator.getLatestMessage();
740 845 Assert.assertTrue(latestMessage instanceof CustomerUpdateMsg);
741 846 CustomerUpdateMsg customerUpdateMsg = (CustomerUpdateMsg) latestMessage;
... ... @@ -743,13 +848,12 @@ abstract public class BaseEdgeTest extends AbstractControllerTest {
743 848 Assert.assertEquals(customerUpdateMsg.getIdMSB(), savedCustomer.getUuidId().getMostSignificantBits());
744 849 Assert.assertEquals(customerUpdateMsg.getIdLSB(), savedCustomer.getUuidId().getLeastSignificantBits());
745 850 Assert.assertEquals(customerUpdateMsg.getTitle(), savedCustomer.getTitle());
746   -
747 851 testAutoGeneratedCodeByProtobuf(customerUpdateMsg);
748 852
  853 + // 2
749 854 edgeImitator.expectMessageAmount(1);
750 855 doDelete("/api/customer/edge/" + edge.getId().getId().toString(), Edge.class);
751   - edgeImitator.waitForMessages();
752   -
  856 + Assert.assertTrue(edgeImitator.waitForMessages());
753 857 latestMessage = edgeImitator.getLatestMessage();
754 858 Assert.assertTrue(latestMessage instanceof CustomerUpdateMsg);
755 859 customerUpdateMsg = (CustomerUpdateMsg) latestMessage;
... ... @@ -757,17 +861,11 @@ abstract public class BaseEdgeTest extends AbstractControllerTest {
757 861 Assert.assertEquals(customerUpdateMsg.getIdMSB(), savedCustomer.getUuidId().getMostSignificantBits());
758 862 Assert.assertEquals(customerUpdateMsg.getIdLSB(), savedCustomer.getUuidId().getLeastSignificantBits());
759 863
  864 + // 3
760 865 edgeImitator.expectMessageAmount(1);
761 866 doDelete("/api/customer/" + savedCustomer.getId().getId().toString())
762 867 .andExpect(status().isOk());
763   - edgeImitator.waitForMessages();
764   -
765   - latestMessage = edgeImitator.getLatestMessage();
766   - Assert.assertTrue(latestMessage instanceof CustomerUpdateMsg);
767   - customerUpdateMsg = (CustomerUpdateMsg) latestMessage;
768   - Assert.assertEquals(UpdateMsgType.ENTITY_DELETED_RPC_MESSAGE, customerUpdateMsg.getMsgType());
769   - Assert.assertEquals(customerUpdateMsg.getIdMSB(), savedCustomer.getUuidId().getMostSignificantBits());
770   - Assert.assertEquals(customerUpdateMsg.getIdLSB(), savedCustomer.getUuidId().getLeastSignificantBits());
  868 + Assert.assertFalse(edgeImitator.waitForMessages(1));
771 869
772 870 log.info("Customer tested successfully");
773 871 }
... ... @@ -775,13 +873,12 @@ abstract public class BaseEdgeTest extends AbstractControllerTest {
775 873 private void testWidgetsBundleAndWidgetType() throws Exception {
776 874 log.info("Testing WidgetsBundle and WidgetType");
777 875
  876 + // 1
  877 + edgeImitator.expectMessageAmount(1);
778 878 WidgetsBundle widgetsBundle = new WidgetsBundle();
779 879 widgetsBundle.setTitle("Test Widget Bundle");
780   -
781   - edgeImitator.expectMessageAmount(1);
782 880 WidgetsBundle savedWidgetsBundle = doPost("/api/widgetsBundle", widgetsBundle, WidgetsBundle.class);
783   - edgeImitator.waitForMessages();
784   -
  881 + Assert.assertTrue(edgeImitator.waitForMessages());
785 882 AbstractMessage latestMessage = edgeImitator.getLatestMessage();
786 883 Assert.assertTrue(latestMessage instanceof WidgetsBundleUpdateMsg);
787 884 WidgetsBundleUpdateMsg widgetsBundleUpdateMsg = (WidgetsBundleUpdateMsg) latestMessage;
... ... @@ -790,20 +887,18 @@ abstract public class BaseEdgeTest extends AbstractControllerTest {
790 887 Assert.assertEquals(widgetsBundleUpdateMsg.getIdLSB(), savedWidgetsBundle.getUuidId().getLeastSignificantBits());
791 888 Assert.assertEquals(widgetsBundleUpdateMsg.getAlias(), savedWidgetsBundle.getAlias());
792 889 Assert.assertEquals(widgetsBundleUpdateMsg.getTitle(), savedWidgetsBundle.getTitle());
793   -
794 890 testAutoGeneratedCodeByProtobuf(widgetsBundleUpdateMsg);
795 891
  892 + // 2
  893 + edgeImitator.expectMessageAmount(1);
796 894 WidgetType widgetType = new WidgetType();
797 895 widgetType.setName("Test Widget Type");
798 896 widgetType.setBundleAlias(savedWidgetsBundle.getAlias());
799 897 ObjectNode descriptor = mapper.createObjectNode();
800 898 descriptor.put("key", "value");
801 899 widgetType.setDescriptor(descriptor);
802   -
803   - edgeImitator.expectMessageAmount(1);
804 900 WidgetType savedWidgetType = doPost("/api/widgetType", widgetType, WidgetType.class);
805   - edgeImitator.waitForMessages();
806   -
  901 + Assert.assertTrue(edgeImitator.waitForMessages());
807 902 latestMessage = edgeImitator.getLatestMessage();
808 903 Assert.assertTrue(latestMessage instanceof WidgetTypeUpdateMsg);
809 904 WidgetTypeUpdateMsg widgetTypeUpdateMsg = (WidgetTypeUpdateMsg) latestMessage;
... ... @@ -814,11 +909,11 @@ abstract public class BaseEdgeTest extends AbstractControllerTest {
814 909 Assert.assertEquals(widgetTypeUpdateMsg.getName(), savedWidgetType.getName());
815 910 Assert.assertEquals(JacksonUtil.toJsonNode(widgetTypeUpdateMsg.getDescriptorJson()), savedWidgetType.getDescriptor());
816 911
  912 + // 3
817 913 edgeImitator.expectMessageAmount(1);
818 914 doDelete("/api/widgetType/" + savedWidgetType.getId().getId().toString())
819 915 .andExpect(status().isOk());
820   - edgeImitator.waitForMessages();
821   -
  916 + Assert.assertTrue(edgeImitator.waitForMessages());
822 917 latestMessage = edgeImitator.getLatestMessage();
823 918 Assert.assertTrue(latestMessage instanceof WidgetTypeUpdateMsg);
824 919 widgetTypeUpdateMsg = (WidgetTypeUpdateMsg) latestMessage;
... ... @@ -826,11 +921,11 @@ abstract public class BaseEdgeTest extends AbstractControllerTest {
826 921 Assert.assertEquals(widgetTypeUpdateMsg.getIdMSB(), savedWidgetType.getUuidId().getMostSignificantBits());
827 922 Assert.assertEquals(widgetTypeUpdateMsg.getIdLSB(), savedWidgetType.getUuidId().getLeastSignificantBits());
828 923
  924 + // 4
829 925 edgeImitator.expectMessageAmount(1);
830 926 doDelete("/api/widgetsBundle/" + savedWidgetsBundle.getId().getId().toString())
831 927 .andExpect(status().isOk());
832   - edgeImitator.waitForMessages();
833   -
  928 + Assert.assertTrue(edgeImitator.waitForMessages());
834 929 latestMessage = edgeImitator.getLatestMessage();
835 930 Assert.assertTrue(latestMessage instanceof WidgetsBundleUpdateMsg);
836 931 widgetsBundleUpdateMsg = (WidgetsBundleUpdateMsg) latestMessage;
... ... @@ -843,15 +938,15 @@ abstract public class BaseEdgeTest extends AbstractControllerTest {
843 938
844 939 private void testTimeseries() throws Exception {
845 940 log.info("Testing timeseries");
846   - Device device = findDeviceByName("Edge Device 1");
847 941
  942 + edgeImitator.expectMessageAmount(1);
  943 + Device device = findDeviceByName("Edge Device 1");
848 944 String timeseriesData = "{\"data\":{\"temperature\":25},\"ts\":" + System.currentTimeMillis() + "}";
849 945 JsonNode timeseriesEntityData = mapper.readTree(timeseriesData);
850   - EdgeEvent edgeEvent1 = constructEdgeEvent(tenantId, edge.getId(), EdgeEventActionType.TIMESERIES_UPDATED, device.getId().getId(), EdgeEventType.DEVICE, timeseriesEntityData);
851   - edgeImitator.expectMessageAmount(1);
852   - edgeEventService.saveAsync(edgeEvent1);
  946 + EdgeEvent edgeEvent = constructEdgeEvent(tenantId, edge.getId(), EdgeEventActionType.TIMESERIES_UPDATED, device.getId().getId(), EdgeEventType.DEVICE, timeseriesEntityData);
  947 + edgeEventService.saveAsync(edgeEvent);
853 948 clusterService.onEdgeEventUpdate(tenantId, edge.getId());
854   - edgeImitator.waitForMessages();
  949 + Assert.assertTrue(edgeImitator.waitForMessages());
855 950
856 951 AbstractMessage latestMessage = edgeImitator.getLatestMessage();
857 952 Assert.assertTrue(latestMessage instanceof EntityDataProto);
... ... @@ -890,7 +985,7 @@ abstract public class BaseEdgeTest extends AbstractControllerTest {
890 985 edgeImitator.expectMessageAmount(1);
891 986 edgeEventService.saveAsync(edgeEvent);
892 987 clusterService.onEdgeEventUpdate(tenantId, edge.getId());
893   - edgeImitator.waitForMessages();
  988 + Assert.assertTrue(edgeImitator.waitForMessages());
894 989
895 990 AbstractMessage latestMessage = edgeImitator.getLatestMessage();
896 991 Assert.assertTrue(latestMessage instanceof EntityDataProto);
... ... @@ -916,7 +1011,7 @@ abstract public class BaseEdgeTest extends AbstractControllerTest {
916 1011 edgeImitator.expectMessageAmount(1);
917 1012 edgeEventService.saveAsync(edgeEvent);
918 1013 clusterService.onEdgeEventUpdate(tenantId, edge.getId());
919   - edgeImitator.waitForMessages();
  1014 + Assert.assertTrue(edgeImitator.waitForMessages());
920 1015
921 1016 AbstractMessage latestMessage = edgeImitator.getLatestMessage();
922 1017 Assert.assertTrue(latestMessage instanceof EntityDataProto);
... ... @@ -941,7 +1036,7 @@ abstract public class BaseEdgeTest extends AbstractControllerTest {
941 1036 edgeImitator.expectMessageAmount(1);
942 1037 edgeEventService.saveAsync(edgeEvent1);
943 1038 clusterService.onEdgeEventUpdate(tenantId, edge.getId());
944   - edgeImitator.waitForMessages();
  1039 + Assert.assertTrue(edgeImitator.waitForMessages());
945 1040
946 1041 AbstractMessage latestMessage = edgeImitator.getLatestMessage();
947 1042 Assert.assertTrue(latestMessage instanceof EntityDataProto);
... ... @@ -996,8 +1091,8 @@ abstract public class BaseEdgeTest extends AbstractControllerTest {
996 1091
997 1092 edgeImitator.sendUplinkMsg(uplinkMsgBuilder.build());
998 1093
999   - edgeImitator.waitForResponses();
1000   - edgeImitator.waitForMessages();
  1094 + Assert.assertTrue(edgeImitator.waitForResponses());
  1095 + Assert.assertTrue(edgeImitator.waitForMessages());
1001 1096
1002 1097 AbstractMessage latestMessage = edgeImitator.getLatestMessage();
1003 1098 Assert.assertTrue(latestMessage instanceof DeviceUpdateMsg);
... ... @@ -1013,7 +1108,7 @@ abstract public class BaseEdgeTest extends AbstractControllerTest {
1013 1108
1014 1109 private void sendDeviceWithNameThatAlreadyExistsOnCloud() throws Exception {
1015 1110 String deviceOnCloudName = RandomStringUtils.randomAlphanumeric(15);
1016   - Device deviceOnCloud = saveDevice(deviceOnCloudName);
  1111 + Device deviceOnCloud = saveDevice(deviceOnCloudName, "Default");
1017 1112
1018 1113 UUID uuid = Uuids.timeBased();
1019 1114
... ... @@ -1033,8 +1128,8 @@ abstract public class BaseEdgeTest extends AbstractControllerTest {
1033 1128
1034 1129 edgeImitator.sendUplinkMsg(uplinkMsgBuilder.build());
1035 1130
1036   - edgeImitator.waitForResponses();
1037   - edgeImitator.waitForMessages();
  1131 + Assert.assertTrue(edgeImitator.waitForResponses());
  1132 + Assert.assertTrue(edgeImitator.waitForMessages());
1038 1133
1039 1134 AbstractMessage latestMessage = edgeImitator.getLatestMessage();
1040 1135 Assert.assertTrue(latestMessage instanceof DeviceUpdateMsg);
... ... @@ -1063,7 +1158,7 @@ abstract public class BaseEdgeTest extends AbstractControllerTest {
1063 1158
1064 1159 edgeImitator.expectMessageAmount(1);
1065 1160 doPost("/api/relation", relation);
1066   - edgeImitator.waitForMessages();
  1161 + Assert.assertTrue(edgeImitator.waitForMessages());
1067 1162
1068 1163 UplinkMsg.Builder uplinkMsgBuilder = UplinkMsg.newBuilder();
1069 1164 RelationRequestMsg.Builder relationRequestMsgBuilder = RelationRequestMsg.newBuilder();
... ... @@ -1078,8 +1173,8 @@ abstract public class BaseEdgeTest extends AbstractControllerTest {
1078 1173 edgeImitator.expectResponsesAmount(1);
1079 1174 edgeImitator.expectMessageAmount(1);
1080 1175 edgeImitator.sendUplinkMsg(uplinkMsgBuilder.build());
1081   - edgeImitator.waitForResponses();
1082   - edgeImitator.waitForMessages();
  1176 + Assert.assertTrue(edgeImitator.waitForResponses());
  1177 + Assert.assertTrue(edgeImitator.waitForMessages());
1083 1178
1084 1179 AbstractMessage latestMessage = edgeImitator.getLatestMessage();
1085 1180 Assert.assertTrue(latestMessage instanceof RelationUpdateMsg);
... ... @@ -1115,7 +1210,7 @@ abstract public class BaseEdgeTest extends AbstractControllerTest {
1115 1210
1116 1211 edgeImitator.expectResponsesAmount(1);
1117 1212 edgeImitator.sendUplinkMsg(uplinkMsgBuilder.build());
1118   - edgeImitator.waitForResponses();
  1213 + Assert.assertTrue(edgeImitator.waitForResponses());
1119 1214
1120 1215
1121 1216 List<AlarmInfo> alarms = doGetTypedWithPageLink("/api/alarm/{entityType}/{entityId}?",
... ... @@ -1158,7 +1253,7 @@ abstract public class BaseEdgeTest extends AbstractControllerTest {
1158 1253
1159 1254 edgeImitator.expectResponsesAmount(1);
1160 1255 edgeImitator.sendUplinkMsg(uplinkMsgBuilder.build());
1161   - edgeImitator.waitForResponses();
  1256 + Assert.assertTrue(edgeImitator.waitForResponses());
1162 1257
1163 1258 EntityRelation relation = doGet("/api/relation?" +
1164 1259 "&fromId=" + device2.getId().getId().toString() +
... ... @@ -1212,7 +1307,7 @@ abstract public class BaseEdgeTest extends AbstractControllerTest {
1212 1307 testAutoGeneratedCodeByProtobuf(uplinkMsgBuilder2);
1213 1308
1214 1309 edgeImitator.sendUplinkMsg(uplinkMsgBuilder2.build());
1215   - edgeImitator.waitForResponses();
  1310 + Assert.assertTrue(edgeImitator.waitForResponses());
1216 1311
1217 1312 // Wait before device attributes saved to database before requesting them from controller
1218 1313 Thread.sleep(1000);
... ... @@ -1243,8 +1338,8 @@ abstract public class BaseEdgeTest extends AbstractControllerTest {
1243 1338 edgeImitator.expectResponsesAmount(1);
1244 1339 edgeImitator.expectMessageAmount(1);
1245 1340 edgeImitator.sendUplinkMsg(uplinkMsgBuilder.build());
1246   - edgeImitator.waitForResponses();
1247   - edgeImitator.waitForMessages();
  1341 + Assert.assertTrue(edgeImitator.waitForResponses());
  1342 + Assert.assertTrue(edgeImitator.waitForMessages());;
1248 1343
1249 1344 AbstractMessage latestMessage = edgeImitator.getLatestMessage();
1250 1345 Assert.assertTrue(latestMessage instanceof RuleChainMetadataUpdateMsg);
... ... @@ -1270,8 +1365,8 @@ abstract public class BaseEdgeTest extends AbstractControllerTest {
1270 1365 edgeImitator.expectResponsesAmount(1);
1271 1366 edgeImitator.expectMessageAmount(1);
1272 1367 edgeImitator.sendUplinkMsg(uplinkMsgBuilder.build());
1273   - edgeImitator.waitForResponses();
1274   - edgeImitator.waitForMessages();
  1368 + Assert.assertTrue(edgeImitator.waitForResponses());
  1369 + Assert.assertTrue(edgeImitator.waitForMessages());
1275 1370
1276 1371 AbstractMessage latestMessage = edgeImitator.getLatestMessage();
1277 1372 Assert.assertTrue(latestMessage instanceof UserCredentialsUpdateMsg);
... ... @@ -1299,8 +1394,8 @@ abstract public class BaseEdgeTest extends AbstractControllerTest {
1299 1394 edgeImitator.expectResponsesAmount(1);
1300 1395 edgeImitator.expectMessageAmount(1);
1301 1396 edgeImitator.sendUplinkMsg(uplinkMsgBuilder.build());
1302   - edgeImitator.waitForResponses();
1303   - edgeImitator.waitForMessages();
  1397 + Assert.assertTrue(edgeImitator.waitForResponses());
  1398 + Assert.assertTrue(edgeImitator.waitForMessages());
1304 1399
1305 1400 AbstractMessage latestMessage = edgeImitator.getLatestMessage();
1306 1401 Assert.assertTrue(latestMessage instanceof DeviceCredentialsUpdateMsg);
... ... @@ -1327,7 +1422,7 @@ abstract public class BaseEdgeTest extends AbstractControllerTest {
1327 1422
1328 1423 edgeImitator.expectResponsesAmount(1);
1329 1424 edgeImitator.sendUplinkMsg(uplinkMsgBuilder.build());
1330   - edgeImitator.waitForResponses();
  1425 + Assert.assertTrue(edgeImitator.waitForResponses());
1331 1426 }
1332 1427
1333 1428 private void sendDeviceRpcResponse() throws Exception {
... ... @@ -1352,7 +1447,7 @@ abstract public class BaseEdgeTest extends AbstractControllerTest {
1352 1447
1353 1448 edgeImitator.expectResponsesAmount(1);
1354 1449 edgeImitator.sendUplinkMsg(uplinkMsgBuilder.build());
1355   - edgeImitator.waitForResponses();
  1450 + Assert.assertTrue(edgeImitator.waitForResponses());
1356 1451 }
1357 1452
1358 1453 private void sendAttributesRequest() throws Exception {
... ... @@ -1383,8 +1478,8 @@ abstract public class BaseEdgeTest extends AbstractControllerTest {
1383 1478 edgeImitator.expectResponsesAmount(1);
1384 1479 edgeImitator.expectMessageAmount(1);
1385 1480 edgeImitator.sendUplinkMsg(uplinkMsgBuilder.build());
1386   - edgeImitator.waitForResponses();
1387   - edgeImitator.waitForMessages();
  1481 + Assert.assertTrue(edgeImitator.waitForResponses());
  1482 + Assert.assertTrue(edgeImitator.waitForMessages());
1388 1483
1389 1484 AbstractMessage latestMessage = edgeImitator.getLatestMessage();
1390 1485 Assert.assertTrue(latestMessage instanceof EntityDataProto);
... ... @@ -1416,7 +1511,7 @@ abstract public class BaseEdgeTest extends AbstractControllerTest {
1416 1511
1417 1512 edgeImitator.expectResponsesAmount(1);
1418 1513 edgeImitator.sendUplinkMsg(upLinkMsgBuilder.build());
1419   - edgeImitator.waitForResponses();
  1514 + Assert.assertTrue(edgeImitator.waitForResponses());
1420 1515 device = doGet("/api/device/" + device.getId().getId().toString(), Device.class);
1421 1516 Assert.assertNotNull(device);
1422 1517 List<Device> edgeDevices = doGetTypedWithPageLink("/api/edge/" + edge.getId().getId().toString() + "/devices?",
... ... @@ -1428,7 +1523,11 @@ abstract public class BaseEdgeTest extends AbstractControllerTest {
1428 1523 private void installation() throws Exception {
1429 1524 edge = doPost("/api/edge", constructEdge("Test Edge", "test"), Edge.class);
1430 1525
1431   - Device savedDevice = saveDevice("Edge Device 1");
  1526 + DeviceProfile deviceProfile = this.createDeviceProfile(CUSTOM_DEVICE_PROFILE_NAME, null);
  1527 + extendDeviceProfileData(deviceProfile);
  1528 + doPost("/api/deviceProfile", deviceProfile, DeviceProfile.class);
  1529 +
  1530 + Device savedDevice = saveDevice("Edge Device 1", CUSTOM_DEVICE_PROFILE_NAME);
1432 1531 doPost("/api/edge/" + edge.getId().getId().toString()
1433 1532 + "/device/" + savedDevice.getId().getId().toString(), Device.class);
1434 1533
... ... @@ -1437,6 +1536,35 @@ abstract public class BaseEdgeTest extends AbstractControllerTest {
1437 1536 + "/asset/" + savedAsset.getId().getId().toString(), Asset.class);
1438 1537 }
1439 1538
  1539 + private void extendDeviceProfileData(DeviceProfile deviceProfile) {
  1540 + DeviceProfileData profileData = deviceProfile.getProfileData();
  1541 + List<DeviceProfileAlarm> alarms = new ArrayList<>();
  1542 + DeviceProfileAlarm deviceProfileAlarm = new DeviceProfileAlarm();
  1543 + deviceProfileAlarm.setAlarmType("High Temperature");
  1544 + AlarmRule alarmRule = new AlarmRule();
  1545 + alarmRule.setAlarmDetails("Alarm Details");
  1546 + AlarmCondition alarmCondition = new AlarmCondition();
  1547 + alarmCondition.setSpec(new SimpleAlarmConditionSpec());
  1548 + List<AlarmConditionFilter> condition = new ArrayList<>();
  1549 + AlarmConditionFilter alarmConditionFilter = new AlarmConditionFilter();
  1550 + alarmConditionFilter.setKey(new AlarmConditionFilterKey(AlarmConditionKeyType.ATTRIBUTE, "temperature"));
  1551 + NumericFilterPredicate predicate = new NumericFilterPredicate();
  1552 + predicate.setOperation(NumericFilterPredicate.NumericOperation.GREATER);
  1553 + predicate.setValue(new FilterPredicateValue<>(55.0));
  1554 + alarmConditionFilter.setPredicate(predicate);
  1555 + alarmConditionFilter.setValueType(EntityKeyValueType.NUMERIC);
  1556 + condition.add(alarmConditionFilter);
  1557 + alarmCondition.setCondition(condition);
  1558 + alarmRule.setCondition(alarmCondition);
  1559 + deviceProfileAlarm.setClearRule(alarmRule);
  1560 + TreeMap<AlarmSeverity, AlarmRule> createRules = new TreeMap<>();
  1561 + createRules.put(AlarmSeverity.CRITICAL, alarmRule);
  1562 + deviceProfileAlarm.setCreateRules(createRules);
  1563 + alarms.add(deviceProfileAlarm);
  1564 + profileData.setAlarms(alarms);
  1565 + profileData.setProvisionConfiguration(new AllowCreateNewDevicesDeviceProfileProvisionConfiguration("123"));
  1566 + }
  1567 +
1440 1568 private EdgeEvent constructEdgeEvent(TenantId tenantId, EdgeId edgeId, EdgeEventActionType edgeEventAction, UUID entityId, EdgeEventType edgeEventType, JsonNode entityBody) {
1441 1569 EdgeEvent edgeEvent = new EdgeEvent();
1442 1570 edgeEvent.setEdgeId(edgeId);
... ...
... ... @@ -32,6 +32,7 @@ import org.thingsboard.server.gen.edge.CustomerUpdateMsg;
32 32 import org.thingsboard.server.gen.edge.DashboardUpdateMsg;
33 33 import org.thingsboard.server.gen.edge.DeviceCredentialsRequestMsg;
34 34 import org.thingsboard.server.gen.edge.DeviceCredentialsUpdateMsg;
  35 +import org.thingsboard.server.gen.edge.DeviceProfileUpdateMsg;
35 36 import org.thingsboard.server.gen.edge.DeviceRpcCallMsg;
36 37 import org.thingsboard.server.gen.edge.DeviceUpdateMsg;
37 38 import org.thingsboard.server.gen.edge.DownlinkMsg;
... ... @@ -58,6 +59,7 @@ import java.util.concurrent.CountDownLatch;
58 59 import java.util.concurrent.TimeUnit;
59 60 import java.util.concurrent.locks.Lock;
60 61 import java.util.concurrent.locks.ReentrantLock;
  62 +import java.util.stream.Collectors;
61 63
62 64 @Slf4j
63 65 public class EdgeImitator {
... ... @@ -154,88 +156,93 @@ public class EdgeImitator {
154 156
155 157 private ListenableFuture<List<Void>> processDownlinkMsg(DownlinkMsg downlinkMsg) {
156 158 List<ListenableFuture<Void>> result = new ArrayList<>();
157   - if (downlinkMsg.getDeviceUpdateMsgList() != null && !downlinkMsg.getDeviceUpdateMsgList().isEmpty()) {
  159 + if (downlinkMsg.getDeviceUpdateMsgCount() > 0) {
158 160 for (DeviceUpdateMsg deviceUpdateMsg: downlinkMsg.getDeviceUpdateMsgList()) {
159 161 result.add(saveDownlinkMsg(deviceUpdateMsg));
160 162 }
161 163 }
162   - if (downlinkMsg.getDeviceCredentialsUpdateMsgList() != null && !downlinkMsg.getDeviceCredentialsUpdateMsgList().isEmpty()) {
  164 + if (downlinkMsg.getDeviceProfileUpdateMsgCount() > 0) {
  165 + for (DeviceProfileUpdateMsg deviceProfileUpdateMsg : downlinkMsg.getDeviceProfileUpdateMsgList()) {
  166 + result.add(saveDownlinkMsg(deviceProfileUpdateMsg));
  167 + }
  168 + }
  169 + if (downlinkMsg.getDeviceCredentialsUpdateMsgCount() > 0) {
163 170 for (DeviceCredentialsUpdateMsg deviceCredentialsUpdateMsg: downlinkMsg.getDeviceCredentialsUpdateMsgList()) {
164 171 result.add(saveDownlinkMsg(deviceCredentialsUpdateMsg));
165 172 }
166 173 }
167   - if (downlinkMsg.getAssetUpdateMsgList() != null && !downlinkMsg.getAssetUpdateMsgList().isEmpty()) {
  174 + if (downlinkMsg.getAssetUpdateMsgCount() > 0) {
168 175 for (AssetUpdateMsg assetUpdateMsg: downlinkMsg.getAssetUpdateMsgList()) {
169 176 result.add(saveDownlinkMsg(assetUpdateMsg));
170 177 }
171 178 }
172   - if (downlinkMsg.getRuleChainUpdateMsgList() != null && !downlinkMsg.getRuleChainUpdateMsgList().isEmpty()) {
  179 + if (downlinkMsg.getRuleChainUpdateMsgCount() > 0) {
173 180 for (RuleChainUpdateMsg ruleChainUpdateMsg: downlinkMsg.getRuleChainUpdateMsgList()) {
174 181 result.add(saveDownlinkMsg(ruleChainUpdateMsg));
175 182 }
176 183 }
177   - if (downlinkMsg.getRuleChainMetadataUpdateMsgList() != null && !downlinkMsg.getRuleChainMetadataUpdateMsgList().isEmpty()) {
  184 + if (downlinkMsg.getRuleChainMetadataUpdateMsgCount() > 0) {
178 185 for (RuleChainMetadataUpdateMsg ruleChainMetadataUpdateMsg: downlinkMsg.getRuleChainMetadataUpdateMsgList()) {
179 186 result.add(saveDownlinkMsg(ruleChainMetadataUpdateMsg));
180 187 }
181 188 }
182   - if (downlinkMsg.getDashboardUpdateMsgList() != null && !downlinkMsg.getDashboardUpdateMsgList().isEmpty()) {
  189 + if (downlinkMsg.getDashboardUpdateMsgCount() > 0) {
183 190 for (DashboardUpdateMsg dashboardUpdateMsg: downlinkMsg.getDashboardUpdateMsgList()) {
184 191 result.add(saveDownlinkMsg(dashboardUpdateMsg));
185 192 }
186 193 }
187   - if (downlinkMsg.getRelationUpdateMsgList() != null && !downlinkMsg.getRelationUpdateMsgList().isEmpty()) {
  194 + if (downlinkMsg.getRelationUpdateMsgCount() > 0) {
188 195 for (RelationUpdateMsg relationUpdateMsg: downlinkMsg.getRelationUpdateMsgList()) {
189 196 result.add(saveDownlinkMsg(relationUpdateMsg));
190 197 }
191 198 }
192   - if (downlinkMsg.getAlarmUpdateMsgList() != null && !downlinkMsg.getAlarmUpdateMsgList().isEmpty()) {
  199 + if (downlinkMsg.getAlarmUpdateMsgCount() > 0) {
193 200 for (AlarmUpdateMsg alarmUpdateMsg: downlinkMsg.getAlarmUpdateMsgList()) {
194 201 result.add(saveDownlinkMsg(alarmUpdateMsg));
195 202 }
196 203 }
197   - if (downlinkMsg.getEntityDataList() != null && !downlinkMsg.getEntityDataList().isEmpty()) {
  204 + if (downlinkMsg.getEntityDataCount() > 0) {
198 205 for (EntityDataProto entityData: downlinkMsg.getEntityDataList()) {
199 206 result.add(saveDownlinkMsg(entityData));
200 207 }
201 208 }
202   - if (downlinkMsg.getEntityViewUpdateMsgList() != null && !downlinkMsg.getEntityViewUpdateMsgList().isEmpty()) {
  209 + if (downlinkMsg.getEntityViewUpdateMsgCount() > 0) {
203 210 for (EntityViewUpdateMsg entityViewUpdateMsg: downlinkMsg.getEntityViewUpdateMsgList()) {
204 211 result.add(saveDownlinkMsg(entityViewUpdateMsg));
205 212 }
206 213 }
207   - if (downlinkMsg.getCustomerUpdateMsgList() != null && !downlinkMsg.getCustomerUpdateMsgList().isEmpty()) {
  214 + if (downlinkMsg.getCustomerUpdateMsgCount() > 0) {
208 215 for (CustomerUpdateMsg customerUpdateMsg: downlinkMsg.getCustomerUpdateMsgList()) {
209 216 result.add(saveDownlinkMsg(customerUpdateMsg));
210 217 }
211 218 }
212   - if (downlinkMsg.getWidgetsBundleUpdateMsgList() != null && !downlinkMsg.getWidgetsBundleUpdateMsgList().isEmpty()) {
  219 + if (downlinkMsg.getWidgetsBundleUpdateMsgCount() > 0) {
213 220 for (WidgetsBundleUpdateMsg widgetsBundleUpdateMsg: downlinkMsg.getWidgetsBundleUpdateMsgList()) {
214 221 result.add(saveDownlinkMsg(widgetsBundleUpdateMsg));
215 222 }
216 223 }
217   - if (downlinkMsg.getWidgetTypeUpdateMsgList() != null && !downlinkMsg.getWidgetTypeUpdateMsgList().isEmpty()) {
  224 + if (downlinkMsg.getWidgetTypeUpdateMsgCount() > 0) {
218 225 for (WidgetTypeUpdateMsg widgetTypeUpdateMsg: downlinkMsg.getWidgetTypeUpdateMsgList()) {
219 226 result.add(saveDownlinkMsg(widgetTypeUpdateMsg));
220 227 }
221 228 }
222   - if (downlinkMsg.getUserUpdateMsgList() != null && !downlinkMsg.getUserUpdateMsgList().isEmpty()) {
  229 + if (downlinkMsg.getUserUpdateMsgCount() > 0) {
223 230 for (UserUpdateMsg userUpdateMsg: downlinkMsg.getUserUpdateMsgList()) {
224 231 onUserUpdate(userUpdateMsg);
225 232 result.add(saveDownlinkMsg(userUpdateMsg));
226 233 }
227 234 }
228   - if (downlinkMsg.getUserCredentialsUpdateMsgList() != null && !downlinkMsg.getUserCredentialsUpdateMsgList().isEmpty()) {
  235 + if (downlinkMsg.getUserCredentialsUpdateMsgCount() > 0) {
229 236 for (UserCredentialsUpdateMsg userCredentialsUpdateMsg: downlinkMsg.getUserCredentialsUpdateMsgList()) {
230 237 result.add(saveDownlinkMsg(userCredentialsUpdateMsg));
231 238 }
232 239 }
233   - if (downlinkMsg.getDeviceRpcCallMsgList() != null && !downlinkMsg.getDeviceRpcCallMsgList().isEmpty()) {
  240 + if (downlinkMsg.getDeviceRpcCallMsgCount() > 0) {
234 241 for (DeviceRpcCallMsg deviceRpcCallMsg: downlinkMsg.getDeviceRpcCallMsgList()) {
235 242 result.add(saveDownlinkMsg(deviceRpcCallMsg));
236 243 }
237 244 }
238   - if (downlinkMsg.getDeviceCredentialsRequestMsgList() != null && !downlinkMsg.getDeviceCredentialsRequestMsgList().isEmpty()) {
  245 + if (downlinkMsg.getDeviceCredentialsRequestMsgCount() > 0) {
239 246 for (DeviceCredentialsRequestMsg deviceCredentialsRequestMsg: downlinkMsg.getDeviceCredentialsRequestMsgList()) {
240 247 result.add(saveDownlinkMsg(deviceCredentialsRequestMsg));
241 248 }
... ... @@ -256,21 +263,28 @@ public class EdgeImitator {
256 263 return Futures.immediateFuture(null);
257 264 }
258 265
259   - public void waitForMessages() throws InterruptedException {
260   - messagesLatch.await(5, TimeUnit.SECONDS);
  266 + public boolean waitForMessages() throws InterruptedException {
  267 + return waitForMessages(5);
  268 + }
  269 +
  270 + public boolean waitForMessages(int timeout) throws InterruptedException {
  271 + return messagesLatch.await(timeout, TimeUnit.SECONDS);
261 272 }
262 273
263 274 public void expectMessageAmount(int messageAmount) {
264 275 messagesLatch = new CountDownLatch(messageAmount);
265 276 }
266 277
267   - public void waitForResponses() throws InterruptedException { responsesLatch.await(5, TimeUnit.SECONDS); }
  278 + public boolean waitForResponses() throws InterruptedException {
  279 + return responsesLatch.await(5, TimeUnit.SECONDS);
  280 + }
268 281
269 282 public void expectResponsesAmount(int messageAmount) {
270 283 responsesLatch = new CountDownLatch(messageAmount);
271 284 }
272 285
273   - public <T> Optional<T> findMessageByType(Class<T> tClass) {
  286 + @SuppressWarnings("unchecked")
  287 + public <T extends AbstractMessage> Optional<T> findMessageByType(Class<T> tClass) {
274 288 Optional<T> result;
275 289 try {
276 290 lock.lock();
... ... @@ -281,6 +295,18 @@ public class EdgeImitator {
281 295 return result;
282 296 }
283 297
  298 + @SuppressWarnings("unchecked")
  299 + public <T extends AbstractMessage> List<T> findAllMessagesByType(Class<T> tClass) {
  300 + List<T> result;
  301 + try {
  302 + lock.lock();
  303 + result = (List<T>) downlinkMsgs.stream().filter(downlinkMsg -> downlinkMsg.getClass().isAssignableFrom(tClass)).collect(Collectors.toList());
  304 + } finally {
  305 + lock.unlock();
  306 + }
  307 + return result;
  308 + }
  309 +
284 310 public AbstractMessage getLatestMessage() {
285 311 return downlinkMsgs.get(downlinkMsgs.size() - 1);
286 312 }
... ...
  1 +/**
  2 + * Copyright © 2016-2021 The Thingsboard Authors
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +package org.thingsboard.server.service;
  17 +
  18 +import org.junit.BeforeClass;
  19 +import org.junit.ClassRule;
  20 +import org.junit.extensions.cpsuite.ClasspathSuite;
  21 +import org.junit.runner.RunWith;
  22 +import org.thingsboard.server.dao.CustomSqlUnit;
  23 +import org.thingsboard.server.queue.memory.InMemoryStorage;
  24 +
  25 +import java.util.Arrays;
  26 +
  27 +@RunWith(ClasspathSuite.class)
  28 +@ClasspathSuite.ClassnameFilters({
  29 + "org.thingsboard.server.service.resource.*Test",
  30 + })
  31 +public class ServiceSqlTestSuite {
  32 +
  33 + @ClassRule
  34 + public static CustomSqlUnit sqlUnit = new CustomSqlUnit(
  35 + Arrays.asList("sql/schema-types-hsql.sql", "sql/schema-ts-hsql.sql", "sql/schema-entities-hsql.sql", "sql/schema-entities-idx.sql", "sql/system-data.sql"),
  36 + "sql/hsql/drop-all-tables.sql",
  37 + "sql-test.properties");
  38 +
  39 + @BeforeClass
  40 + public static void cleanupInMemStorage(){
  41 + InMemoryStorage.getInstance().cleanup();
  42 + }
  43 +}
... ...
application/src/test/java/org/thingsboard/server/service/resource/BaseTbResourceServiceTest.java renamed from dao/src/test/java/org/thingsboard/server/dao/service/BaseTbResourceServiceTest.java
... ... @@ -13,28 +13,37 @@
13 13 * See the License for the specific language governing permissions and
14 14 * limitations under the License.
15 15 */
16   -package org.thingsboard.server.dao.service;
  16 +package org.thingsboard.server.service.resource;
17 17
18 18 import com.datastax.oss.driver.api.core.uuid.Uuids;
19 19 import org.junit.After;
20 20 import org.junit.Assert;
21 21 import org.junit.Before;
22 22 import org.junit.Test;
  23 +import org.springframework.beans.factory.annotation.Autowired;
23 24 import org.thingsboard.server.common.data.ResourceType;
24 25 import org.thingsboard.server.common.data.TbResource;
25 26 import org.thingsboard.server.common.data.TbResourceInfo;
26 27 import org.thingsboard.server.common.data.Tenant;
  28 +import org.thingsboard.server.common.data.User;
27 29 import org.thingsboard.server.common.data.id.TenantId;
28 30 import org.thingsboard.server.common.data.page.PageData;
29 31 import org.thingsboard.server.common.data.page.PageLink;
  32 +import org.thingsboard.server.common.data.security.Authority;
  33 +import org.thingsboard.server.controller.AbstractControllerTest;
30 34 import org.thingsboard.server.dao.exception.DataValidationException;
  35 +import org.thingsboard.server.dao.service.AbstractServiceTest;
  36 +import org.thingsboard.server.dao.service.DaoSqlTest;
31 37
32 38 import java.util.ArrayList;
33 39 import java.util.Base64;
34 40 import java.util.Collections;
35 41 import java.util.List;
36 42
37   -public abstract class BaseTbResourceServiceTest extends AbstractServiceTest {
  43 +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
  44 +
  45 +@DaoSqlTest
  46 +public class BaseTbResourceServiceTest extends AbstractControllerTest {
38 47
39 48 private static final String LWM2M_TEST_MODEL = "<LWM2M xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:noNamespaceSchemaLocation=\"http://www.openmobilealliance.org/tech/profiles/LWM2M-v1_1.xsd\">\n" +
40 49 "<Object ObjectType=\"MODefinition\">\n" +
... ... @@ -67,18 +76,38 @@ public abstract class BaseTbResourceServiceTest extends AbstractServiceTest {
67 76
68 77 private TenantId tenantId;
69 78
  79 + @Autowired
  80 + private TbResourceService resourceService;
  81 +
  82 + private Tenant savedTenant;
  83 + private User tenantAdmin;
  84 +
70 85 @Before
71   - public void before() {
  86 + public void beforeTest() throws Exception {
  87 + loginSysAdmin();
  88 +
72 89 Tenant tenant = new Tenant();
73 90 tenant.setTitle("My tenant");
74   - Tenant savedTenant = tenantService.saveTenant(tenant);
75   - Assert.assertNotNull(savedTenant);
  91 + savedTenant = doPost("/api/tenant", tenant, Tenant.class);
76 92 tenantId = savedTenant.getId();
  93 + Assert.assertNotNull(savedTenant);
  94 +
  95 + tenantAdmin = new User();
  96 + tenantAdmin.setAuthority(Authority.TENANT_ADMIN);
  97 + tenantAdmin.setTenantId(savedTenant.getId());
  98 + tenantAdmin.setEmail("tenant2@thingsboard.org");
  99 + tenantAdmin.setFirstName("Joe");
  100 + tenantAdmin.setLastName("Downs");
  101 +
  102 + tenantAdmin = createUserAndLogin(tenantAdmin, "testPassword1");
77 103 }
78 104
79 105 @After
80   - public void after() {
81   - tenantService.deleteTenant(tenantId);
  106 + public void afterTest() throws Exception {
  107 + loginSysAdmin();
  108 +
  109 + doDelete("/api/tenant/" + savedTenant.getId().getId().toString())
  110 + .andExpect(status().isOk());
82 111 }
83 112
84 113 @Test
... ... @@ -239,9 +268,10 @@ public abstract class BaseTbResourceServiceTest extends AbstractServiceTest {
239 268
240 269 @Test
241 270 public void testFindTenantResourcesByTenantId() throws Exception {
  271 + loginSysAdmin();
242 272 Tenant tenant = new Tenant();
243 273 tenant.setTitle("Test tenant");
244   - tenant = tenantService.saveTenant(tenant);
  274 + tenant = doPost("/api/tenant", tenant, Tenant.class);
245 275
246 276 TenantId tenantId = tenant.getId();
247 277
... ... @@ -279,14 +309,17 @@ public abstract class BaseTbResourceServiceTest extends AbstractServiceTest {
279 309 Assert.assertFalse(pageData.hasNext());
280 310 Assert.assertTrue(pageData.getData().isEmpty());
281 311
282   - tenantService.deleteTenant(tenantId);
  312 + doDelete("/api/tenant/" + tenantId.getId().toString())
  313 + .andExpect(status().isOk());
283 314 }
284 315
285 316 @Test
286 317 public void testFindAllTenantResourcesByTenantId() throws Exception {
  318 + loginSysAdmin();
  319 +
287 320 Tenant tenant = new Tenant();
288 321 tenant.setTitle("Test tenant");
289   - tenant = tenantService.saveTenant(tenant);
  322 + tenant = doPost("/api/tenant", tenant, Tenant.class);
290 323
291 324 TenantId tenantId = tenant.getId();
292 325
... ... @@ -344,7 +377,8 @@ public abstract class BaseTbResourceServiceTest extends AbstractServiceTest {
344 377 Assert.assertFalse(pageData.hasNext());
345 378 Assert.assertTrue(pageData.getData().isEmpty());
346 379
347   - tenantService.deleteTenant(tenantId);
  380 + doDelete("/api/tenant/" + tenantId.getId().toString())
  381 + .andExpect(status().isOk());
348 382 }
349 383
350 384 }
... ...
... ... @@ -15,35 +15,11 @@
15 15 */
16 16 package org.thingsboard.server.transport;
17 17
18   -import com.fasterxml.jackson.databind.node.ObjectNode;
19 18 import lombok.extern.slf4j.Slf4j;
20   -import org.eclipse.paho.client.mqttv3.MqttAsyncClient;
21   -import org.eclipse.paho.client.mqttv3.MqttConnectOptions;
22   -import org.eclipse.paho.client.mqttv3.MqttException;
23   -import org.eclipse.paho.client.mqttv3.MqttMessage;
24   -import org.eclipse.paho.client.mqttv3.persist.MemoryPersistence;
25   -import org.junit.Assert;
26   -import org.springframework.util.StringUtils;
27 19 import org.thingsboard.server.common.data.Device;
28 20 import org.thingsboard.server.common.data.DeviceProfile;
29   -import org.thingsboard.server.common.data.DeviceProfileProvisionType;
30   -import org.thingsboard.server.common.data.DeviceProfileType;
31   -import org.thingsboard.server.common.data.DeviceTransportType;
32 21 import org.thingsboard.server.common.data.Tenant;
33   -import org.thingsboard.server.common.data.TransportPayloadType;
34 22 import org.thingsboard.server.common.data.User;
35   -import org.thingsboard.server.common.data.device.profile.AllowCreateNewDevicesDeviceProfileProvisionConfiguration;
36   -import org.thingsboard.server.common.data.device.profile.CheckPreProvisionedDevicesDeviceProfileProvisionConfiguration;
37   -import org.thingsboard.server.common.data.device.profile.DefaultDeviceProfileConfiguration;
38   -import org.thingsboard.server.common.data.device.profile.DeviceProfileData;
39   -import org.thingsboard.server.common.data.device.profile.DeviceProfileProvisionConfiguration;
40   -import org.thingsboard.server.common.data.device.profile.DisabledDeviceProfileProvisionConfiguration;
41   -import org.thingsboard.server.common.data.device.profile.JsonTransportPayloadConfiguration;
42   -import org.thingsboard.server.common.data.device.profile.MqttDeviceProfileTransportConfiguration;
43   -import org.thingsboard.server.common.data.device.profile.ProtoTransportPayloadConfiguration;
44   -import org.thingsboard.server.common.data.device.profile.TransportPayloadTypeConfiguration;
45   -import org.thingsboard.server.common.data.security.Authority;
46   -import org.thingsboard.server.common.data.security.DeviceCredentials;
47 23 import org.thingsboard.server.controller.AbstractControllerTest;
48 24 import org.thingsboard.server.gen.transport.TransportProtos;
49 25
... ... @@ -51,8 +27,6 @@ import java.util.ArrayList;
51 27 import java.util.List;
52 28 import java.util.concurrent.atomic.AtomicInteger;
53 29
54   -import static org.junit.Assert.assertEquals;
55   -import static org.junit.Assert.assertNotNull;
56 30 import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
57 31
58 32 @Slf4j
... ... @@ -105,6 +79,22 @@ public abstract class AbstractTransportIntegrationTest extends AbstractControlle
105 79 " }\n" +
106 80 "}";
107 81
  82 + protected static final String DEVICE_RPC_RESPONSE_PROTO_SCHEMA = "syntax =\"proto3\";\n" +
  83 + "package rpc;\n" +
  84 + "\n" +
  85 + "message RpcResponseMsg {\n" +
  86 + " string payload = 1;\n" +
  87 + "}";
  88 +
  89 + protected static final String DEVICE_RPC_REQUEST_PROTO_SCHEMA = "syntax =\"proto3\";\n" +
  90 + "package rpc;\n" +
  91 + "\n" +
  92 + "message RpcRequestMsg {\n" +
  93 + " string method = 1;\n" +
  94 + " int32 requestId = 2;\n" +
  95 + " string params = 3;\n" +
  96 + "}";
  97 +
108 98 protected Tenant savedTenant;
109 99 protected User tenantAdmin;
110 100
... ...
... ... @@ -53,7 +53,7 @@ import static org.junit.Assert.assertNotNull;
53 53 public abstract class AbstractCoapIntegrationTest extends AbstractTransportIntegrationTest {
54 54
55 55 protected void processBeforeTest(String deviceName, CoapDeviceType coapDeviceType, TransportPayloadType payloadType) throws Exception {
56   - this.processBeforeTest(deviceName, coapDeviceType, payloadType, null, null, DeviceProfileProvisionType.DISABLED, null, null);
  56 + this.processBeforeTest(deviceName, coapDeviceType, payloadType, null, null, null, null, null, null, DeviceProfileProvisionType.DISABLED);
57 57 }
58 58
59 59 protected void processBeforeTest(String deviceName,
... ... @@ -61,8 +61,11 @@ public abstract class AbstractCoapIntegrationTest extends AbstractTransportInteg
61 61 TransportPayloadType payloadType,
62 62 String telemetryProtoSchema,
63 63 String attributesProtoSchema,
64   - DeviceProfileProvisionType provisionType,
65   - String provisionKey, String provisionSecret
  64 + String rpcResponseProtoSchema,
  65 + String rpcRequestProtoSchema,
  66 + String provisionKey,
  67 + String provisionSecret,
  68 + DeviceProfileProvisionType provisionType
66 69 ) throws Exception {
67 70 loginSysAdmin();
68 71
... ... @@ -85,7 +88,7 @@ public abstract class AbstractCoapIntegrationTest extends AbstractTransportInteg
85 88 device.setType("default");
86 89
87 90 if (coapDeviceType != null) {
88   - DeviceProfile coapDeviceProfile = createCoapDeviceProfile(payloadType, coapDeviceType, attributesProtoSchema, provisionType, provisionKey, provisionSecret, telemetryProtoSchema);
  91 + DeviceProfile coapDeviceProfile = createCoapDeviceProfile(payloadType, coapDeviceType, provisionSecret, provisionType, provisionKey, attributesProtoSchema, telemetryProtoSchema, rpcResponseProtoSchema, rpcRequestProtoSchema);
89 92 deviceProfile = doPost("/api/deviceProfile", coapDeviceProfile, DeviceProfile.class);
90 93 device.setType(deviceProfile.getName());
91 94 device.setDeviceProfileId(deviceProfile.getId());
... ... @@ -103,8 +106,9 @@ public abstract class AbstractCoapIntegrationTest extends AbstractTransportInteg
103 106 }
104 107
105 108 protected DeviceProfile createCoapDeviceProfile(TransportPayloadType transportPayloadType, CoapDeviceType coapDeviceType,
106   - String attributesProtoSchema, DeviceProfileProvisionType provisionType,
107   - String provisionKey, String provisionSecret, String telemetryProtoSchema) {
  109 + String provisionSecret, DeviceProfileProvisionType provisionType,
  110 + String provisionKey, String attributesProtoSchema,
  111 + String telemetryProtoSchema, String rpcResponseProtoSchema, String rpcRequestProtoSchema) {
108 112 DeviceProfile deviceProfile = new DeviceProfile();
109 113 deviceProfile.setName(transportPayloadType.name());
110 114 deviceProfile.setType(DeviceProfileType.DEFAULT);
... ... @@ -127,8 +131,16 @@ public abstract class AbstractCoapIntegrationTest extends AbstractTransportInteg
127 131 if (StringUtils.isEmpty(attributesProtoSchema)) {
128 132 attributesProtoSchema = DEVICE_ATTRIBUTES_PROTO_SCHEMA;
129 133 }
  134 + if (StringUtils.isEmpty(rpcResponseProtoSchema)) {
  135 + rpcResponseProtoSchema = DEVICE_RPC_RESPONSE_PROTO_SCHEMA;
  136 + }
  137 + if (StringUtils.isEmpty(rpcRequestProtoSchema)) {
  138 + rpcRequestProtoSchema = DEVICE_RPC_REQUEST_PROTO_SCHEMA;
  139 + }
130 140 protoTransportPayloadConfiguration.setDeviceTelemetryProtoSchema(telemetryProtoSchema);
131 141 protoTransportPayloadConfiguration.setDeviceAttributesProtoSchema(attributesProtoSchema);
  142 + protoTransportPayloadConfiguration.setDeviceRpcResponseProtoSchema(rpcResponseProtoSchema);
  143 + protoTransportPayloadConfiguration.setDeviceRpcRequestProtoSchema(rpcRequestProtoSchema);
132 144 transportPayloadTypeConfiguration = protoTransportPayloadConfiguration;
133 145 } else {
134 146 transportPayloadTypeConfiguration = new JsonTransportPayloadConfiguration();
... ...
... ... @@ -79,7 +79,7 @@ public abstract class AbstractCoapAttributesRequestProtoIntegrationTest extends
79 79 @Test
80 80 public void testRequestAttributesValuesFromTheServer() throws Exception {
81 81 super.processBeforeTest("Test Request attribute values from the server proto", CoapDeviceType.DEFAULT,
82   - TransportPayloadType.PROTOBUF, null, ATTRIBUTES_SCHEMA_STR, DeviceProfileProvisionType.DISABLED, null, null);
  82 + TransportPayloadType.PROTOBUF, null, ATTRIBUTES_SCHEMA_STR, null, null, null, null, DeviceProfileProvisionType.DISABLED);
83 83 processTestRequestAttributesValuesFromTheServer();
84 84 }
85 85
... ...
... ... @@ -88,7 +88,7 @@ public abstract class AbstractCoapProvisionJsonDeviceTest extends AbstractCoapIn
88 88
89 89
90 90 private void processTestProvisioningDisabledDevice() throws Exception {
91   - super.processBeforeTest("Test Provision device", CoapDeviceType.DEFAULT, TransportPayloadType.JSON, null, null, DeviceProfileProvisionType.DISABLED, null, null);
  91 + super.processBeforeTest("Test Provision device", CoapDeviceType.DEFAULT, TransportPayloadType.JSON, null, null, null, null, null, null, DeviceProfileProvisionType.DISABLED);
92 92 byte[] result = createCoapClientAndPublish().getPayload();
93 93 JsonObject response = JsonUtils.parse(new String(result)).getAsJsonObject();
94 94 Assert.assertEquals("Provision data was not found!", response.get("errorMsg").getAsString());
... ... @@ -97,7 +97,7 @@ public abstract class AbstractCoapProvisionJsonDeviceTest extends AbstractCoapIn
97 97
98 98
99 99 private void processTestProvisioningCreateNewDeviceWithoutCredentials() throws Exception {
100   - super.processBeforeTest("Test Provision device3", CoapDeviceType.DEFAULT, TransportPayloadType.JSON, null, null, DeviceProfileProvisionType.ALLOW_CREATE_NEW_DEVICES, "testProvisionKey", "testProvisionSecret");
  100 + super.processBeforeTest("Test Provision device3", CoapDeviceType.DEFAULT, TransportPayloadType.JSON, null, null, null, null, "testProvisionKey", "testProvisionSecret", DeviceProfileProvisionType.ALLOW_CREATE_NEW_DEVICES);
101 101 byte[] result = createCoapClientAndPublish().getPayload();
102 102 JsonObject response = JsonUtils.parse(new String(result)).getAsJsonObject();
103 103
... ... @@ -113,7 +113,7 @@ public abstract class AbstractCoapProvisionJsonDeviceTest extends AbstractCoapIn
113 113
114 114
115 115 private void processTestProvisioningCreateNewDeviceWithAccessToken() throws Exception {
116   - super.processBeforeTest("Test Provision device3", CoapDeviceType.DEFAULT, TransportPayloadType.JSON, null, null, DeviceProfileProvisionType.ALLOW_CREATE_NEW_DEVICES, "testProvisionKey", "testProvisionSecret");
  116 + super.processBeforeTest("Test Provision device3", CoapDeviceType.DEFAULT, TransportPayloadType.JSON, null, null, null, null, "testProvisionKey", "testProvisionSecret", DeviceProfileProvisionType.ALLOW_CREATE_NEW_DEVICES);
117 117 String requestCredentials = ",\"credentialsType\": \"ACCESS_TOKEN\",\"token\": \"test_token\"";
118 118 byte[] result = createCoapClientAndPublish(requestCredentials).getPayload();
119 119 JsonObject response = JsonUtils.parse(new String(result)).getAsJsonObject();
... ... @@ -132,7 +132,7 @@ public abstract class AbstractCoapProvisionJsonDeviceTest extends AbstractCoapIn
132 132
133 133
134 134 private void processTestProvisioningCreateNewDeviceWithCert() throws Exception {
135   - super.processBeforeTest("Test Provision device3", CoapDeviceType.DEFAULT, TransportPayloadType.JSON, null, null, DeviceProfileProvisionType.ALLOW_CREATE_NEW_DEVICES, "testProvisionKey", "testProvisionSecret");
  135 + super.processBeforeTest("Test Provision device3", CoapDeviceType.DEFAULT, TransportPayloadType.JSON, null, null, null, null, "testProvisionKey", "testProvisionSecret", DeviceProfileProvisionType.ALLOW_CREATE_NEW_DEVICES);
136 136 String requestCredentials = ",\"credentialsType\": \"X509_CERTIFICATE\",\"hash\": \"testHash\"";
137 137 byte[] result = createCoapClientAndPublish(requestCredentials).getPayload();
138 138 JsonObject response = JsonUtils.parse(new String(result)).getAsJsonObject();
... ... @@ -156,7 +156,7 @@ public abstract class AbstractCoapProvisionJsonDeviceTest extends AbstractCoapIn
156 156 }
157 157
158 158 private void processTestProvisioningCheckPreProvisionedDevice() throws Exception {
159   - super.processBeforeTest("Test Provision device", CoapDeviceType.DEFAULT, TransportPayloadType.JSON, null, null, DeviceProfileProvisionType.CHECK_PRE_PROVISIONED_DEVICES, "testProvisionKey", "testProvisionSecret");
  159 + super.processBeforeTest("Test Provision device", CoapDeviceType.DEFAULT, TransportPayloadType.JSON, null, null, null, null, "testProvisionKey", "testProvisionSecret", DeviceProfileProvisionType.CHECK_PRE_PROVISIONED_DEVICES);
160 160 byte[] result = createCoapClientAndPublish().getPayload();
161 161 JsonObject response = JsonUtils.parse(new String(result)).getAsJsonObject();
162 162
... ... @@ -167,7 +167,7 @@ public abstract class AbstractCoapProvisionJsonDeviceTest extends AbstractCoapIn
167 167 }
168 168
169 169 private void processTestProvisioningWithBadKeyDevice() throws Exception {
170   - super.processBeforeTest("Test Provision device", CoapDeviceType.DEFAULT, TransportPayloadType.JSON, null, null, DeviceProfileProvisionType.CHECK_PRE_PROVISIONED_DEVICES, "testProvisionKeyOrig", "testProvisionSecret");
  170 + super.processBeforeTest("Test Provision device", CoapDeviceType.DEFAULT, TransportPayloadType.JSON, null, null, null, null, "testProvisionKeyOrig", "testProvisionSecret", DeviceProfileProvisionType.CHECK_PRE_PROVISIONED_DEVICES);
171 171 byte[] result = createCoapClientAndPublish().getPayload();
172 172 JsonObject response = JsonUtils.parse(new String(result)).getAsJsonObject();
173 173 Assert.assertEquals("Provision data was not found!", response.get("errorMsg").getAsString());
... ...
... ... @@ -92,14 +92,14 @@ public abstract class AbstractCoapProvisionProtoDeviceTest extends AbstractCoapI
92 92
93 93
94 94 private void processTestProvisioningDisabledDevice() throws Exception {
95   - super.processBeforeTest("Test Provision device", CoapDeviceType.DEFAULT, TransportPayloadType.PROTOBUF, null, null, DeviceProfileProvisionType.DISABLED, null, null);
  95 + super.processBeforeTest("Test Provision device", CoapDeviceType.DEFAULT, TransportPayloadType.PROTOBUF, null, null, null, null, null, null, DeviceProfileProvisionType.DISABLED);
96 96 ProvisionDeviceResponseMsg result = ProvisionDeviceResponseMsg.parseFrom(createCoapClientAndPublish().getPayload());
97 97 Assert.assertNotNull(result);
98 98 Assert.assertEquals(ProvisionResponseStatus.NOT_FOUND.name(), result.getStatus().toString());
99 99 }
100 100
101 101 private void processTestProvisioningCreateNewDeviceWithoutCredentials() throws Exception {
102   - super.processBeforeTest("Test Provision device3", CoapDeviceType.DEFAULT, TransportPayloadType.PROTOBUF, null, null, DeviceProfileProvisionType.ALLOW_CREATE_NEW_DEVICES, "testProvisionKey", "testProvisionSecret");
  102 + super.processBeforeTest("Test Provision device3", CoapDeviceType.DEFAULT, TransportPayloadType.PROTOBUF, null, null, null, null, "testProvisionKey", "testProvisionSecret", DeviceProfileProvisionType.ALLOW_CREATE_NEW_DEVICES);
103 103 ProvisionDeviceResponseMsg response = ProvisionDeviceResponseMsg.parseFrom(createCoapClientAndPublish().getPayload());
104 104
105 105 Device createdDevice = deviceService.findDeviceByTenantIdAndName(savedTenant.getTenantId(), "Test Provision device");
... ... @@ -113,7 +113,7 @@ public abstract class AbstractCoapProvisionProtoDeviceTest extends AbstractCoapI
113 113 }
114 114
115 115 private void processTestProvisioningCreateNewDeviceWithAccessToken() throws Exception {
116   - super.processBeforeTest("Test Provision device3", CoapDeviceType.DEFAULT, TransportPayloadType.PROTOBUF, null, null, DeviceProfileProvisionType.ALLOW_CREATE_NEW_DEVICES, "testProvisionKey", "testProvisionSecret");
  116 + super.processBeforeTest("Test Provision device3", CoapDeviceType.DEFAULT, TransportPayloadType.PROTOBUF, null, null, null, null, "testProvisionKey", "testProvisionSecret", DeviceProfileProvisionType.ALLOW_CREATE_NEW_DEVICES);
117 117 CredentialsDataProto requestCredentials = CredentialsDataProto.newBuilder().setValidateDeviceTokenRequestMsg(ValidateDeviceTokenRequestMsg.newBuilder().setToken("test_token").build()).build();
118 118
119 119 ProvisionDeviceResponseMsg response = ProvisionDeviceResponseMsg.parseFrom(createCoapClientAndPublish(createTestsProvisionMessage(CredentialsType.ACCESS_TOKEN, requestCredentials)).getPayload());
... ... @@ -131,7 +131,7 @@ public abstract class AbstractCoapProvisionProtoDeviceTest extends AbstractCoapI
131 131 }
132 132
133 133 private void processTestProvisioningCreateNewDeviceWithCert() throws Exception {
134   - super.processBeforeTest("Test Provision device3", CoapDeviceType.DEFAULT, TransportPayloadType.PROTOBUF, null, null, DeviceProfileProvisionType.ALLOW_CREATE_NEW_DEVICES, "testProvisionKey", "testProvisionSecret");
  134 + super.processBeforeTest("Test Provision device3", CoapDeviceType.DEFAULT, TransportPayloadType.PROTOBUF, null, null, null, null, "testProvisionKey", "testProvisionSecret", DeviceProfileProvisionType.ALLOW_CREATE_NEW_DEVICES);
135 135 CredentialsDataProto requestCredentials = CredentialsDataProto.newBuilder().setValidateDeviceX509CertRequestMsg(ValidateDeviceX509CertRequestMsg.newBuilder().setHash("testHash").build()).build();
136 136
137 137 ProvisionDeviceResponseMsg response = ProvisionDeviceResponseMsg.parseFrom(createCoapClientAndPublish(createTestsProvisionMessage(CredentialsType.X509_CERTIFICATE, requestCredentials)).getPayload());
... ... @@ -155,7 +155,7 @@ public abstract class AbstractCoapProvisionProtoDeviceTest extends AbstractCoapI
155 155 }
156 156
157 157 private void processTestProvisioningCheckPreProvisionedDevice() throws Exception {
158   - super.processBeforeTest("Test Provision device", CoapDeviceType.DEFAULT, TransportPayloadType.PROTOBUF, null, null, DeviceProfileProvisionType.CHECK_PRE_PROVISIONED_DEVICES, "testProvisionKey", "testProvisionSecret");
  158 + super.processBeforeTest("Test Provision device", CoapDeviceType.DEFAULT, TransportPayloadType.PROTOBUF, null, null, null, null, "testProvisionKey", "testProvisionSecret", DeviceProfileProvisionType.CHECK_PRE_PROVISIONED_DEVICES);
159 159 ProvisionDeviceResponseMsg response = ProvisionDeviceResponseMsg.parseFrom(createCoapClientAndPublish().getPayload());
160 160
161 161 DeviceCredentials deviceCredentials = deviceCredentialsService.findDeviceCredentialsByDeviceId(savedTenant.getTenantId(), savedDevice.getId());
... ... @@ -165,7 +165,7 @@ public abstract class AbstractCoapProvisionProtoDeviceTest extends AbstractCoapI
165 165 }
166 166
167 167 private void processTestProvisioningWithBadKeyDevice() throws Exception {
168   - super.processBeforeTest("Test Provision device", CoapDeviceType.DEFAULT, TransportPayloadType.PROTOBUF, null, null, DeviceProfileProvisionType.CHECK_PRE_PROVISIONED_DEVICES, "testProvisionKeyOrig", "testProvisionSecret");
  168 + super.processBeforeTest("Test Provision device", CoapDeviceType.DEFAULT, TransportPayloadType.PROTOBUF, null, null, null, null, "testProvisionKeyOrig", "testProvisionSecret", DeviceProfileProvisionType.CHECK_PRE_PROVISIONED_DEVICES);
169 169 ProvisionDeviceResponseMsg response = ProvisionDeviceResponseMsg.parseFrom(createCoapClientAndPublish().getPayload());
170 170 Assert.assertEquals(ProvisionResponseStatus.NOT_FOUND.name(), response.getStatus().toString());
171 171 }
... ...
... ... @@ -124,7 +124,7 @@ public abstract class AbstractCoapServerSideRpcIntegrationTest extends AbstractC
124 124 return COAP_BASE_URL + token + "/" + FeatureType.RPC.name().toLowerCase() + "/" + requestId;
125 125 }
126 126
127   - private class TestCoapCallback implements CoapHandler {
  127 + protected class TestCoapCallback implements CoapHandler {
128 128
129 129 private final CoapClient client;
130 130 private final CountDownLatch latch;
... ... @@ -136,7 +136,7 @@ public abstract class AbstractCoapServerSideRpcIntegrationTest extends AbstractC
136 136
137 137 private Integer observe;
138 138
139   - private TestCoapCallback(CoapClient client, CountDownLatch latch, boolean isOneWayRpc) {
  139 + TestCoapCallback(CoapClient client, CountDownLatch latch, boolean isOneWayRpc) {
140 140 this.client = client;
141 141 this.latch = latch;
142 142 this.isOneWayRpc = isOneWayRpc;
... ... @@ -144,7 +144,7 @@ public abstract class AbstractCoapServerSideRpcIntegrationTest extends AbstractC
144 144
145 145 @Override
146 146 public void onLoad(CoapResponse response) {
147   - log.warn("coap response: {}, {}", response, response.getCode());
  147 + log.warn("coap response: {}, {}", response.getResponseText(), response.getCode());
148 148 assertNotNull(response.getPayload());
149 149 assertEquals(response.getCode(), CoAP.ResponseCode.CONTENT);
150 150 observe = response.getOptions().getObserve();
... ...
... ... @@ -36,12 +36,12 @@ public abstract class AbstractCoapServerSideRpcJsonIntegrationTest extends Abstr
36 36 }
37 37
38 38 @Test
39   - public void testServerMqttOneWayRpc() throws Exception {
  39 + public void testServerCoapOneWayRpc() throws Exception {
40 40 processOneWayRpcTest();
41 41 }
42 42
43 43 @Test
44   - public void testServerMqttTwoWayRpc() throws Exception {
  44 + public void testServerCoapTwoWayRpc() throws Exception {
45 45 processTwoWayRpcTest();
46 46 }
47 47
... ...
... ... @@ -15,26 +15,62 @@
15 15 */
16 16 package org.thingsboard.server.transport.coap.rpc;
17 17
  18 +import com.github.os72.protobuf.dynamic.DynamicSchema;
  19 +import com.google.protobuf.Descriptors;
  20 +import com.google.protobuf.DynamicMessage;
  21 +import com.google.protobuf.InvalidProtocolBufferException;
  22 +import com.squareup.wire.schema.internal.parser.ProtoFileElement;
18 23 import lombok.extern.slf4j.Slf4j;
19 24 import org.eclipse.californium.core.CoapClient;
20 25 import org.eclipse.californium.core.CoapHandler;
  26 +import org.eclipse.californium.core.CoapObserveRelation;
21 27 import org.eclipse.californium.core.CoapResponse;
  28 +import org.eclipse.californium.core.coap.CoAP;
22 29 import org.eclipse.californium.core.coap.MediaTypeRegistry;
  30 +import org.eclipse.californium.core.coap.Request;
23 31 import org.junit.After;
24 32 import org.junit.Before;
25 33 import org.junit.Test;
26 34 import org.thingsboard.server.common.data.CoapDeviceType;
  35 +import org.thingsboard.server.common.data.DeviceProfileProvisionType;
27 36 import org.thingsboard.server.common.data.TransportPayloadType;
28   -import org.thingsboard.server.gen.transport.TransportProtos;
  37 +import org.thingsboard.server.common.data.device.profile.CoapDeviceProfileTransportConfiguration;
  38 +import org.thingsboard.server.common.data.device.profile.CoapDeviceTypeConfiguration;
  39 +import org.thingsboard.server.common.data.device.profile.DefaultCoapDeviceTypeConfiguration;
  40 +import org.thingsboard.server.common.data.device.profile.DeviceProfileTransportConfiguration;
  41 +import org.thingsboard.server.common.data.device.profile.ProtoTransportPayloadConfiguration;
  42 +import org.thingsboard.server.common.data.device.profile.TransportPayloadTypeConfiguration;
  43 +import org.thingsboard.server.common.msg.session.FeatureType;
29 44
  45 +import java.util.List;
30 46 import java.util.concurrent.CountDownLatch;
  47 +import java.util.concurrent.TimeUnit;
  48 +
  49 +import static org.junit.Assert.assertEquals;
  50 +import static org.junit.Assert.assertNotNull;
  51 +import static org.junit.Assert.assertTrue;
  52 +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
31 53
32 54 @Slf4j
33 55 public abstract class AbstractCoapServerSideRpcProtoIntegrationTest extends AbstractCoapServerSideRpcIntegrationTest {
34 56
  57 + private static final String RPC_REQUEST_PROTO_SCHEMA = "syntax =\"proto3\";\n" +
  58 + "package rpc;\n" +
  59 + "\n" +
  60 + "message RpcRequestMsg {\n" +
  61 + " string method = 1;\n" +
  62 + " int32 requestId = 2;\n" +
  63 + " Params params = 3;\n" +
  64 + "\n" +
  65 + " message Params {\n" +
  66 + " string pin = 1;\n" +
  67 + " int32 value = 2;\n" +
  68 + " }\n" +
  69 + "}";
  70 +
35 71 @Before
36 72 public void beforeTest() throws Exception {
37   - processBeforeTest("RPC test device", CoapDeviceType.DEFAULT, TransportPayloadType.PROTOBUF);
  73 + processBeforeTest("RPC test device", CoapDeviceType.DEFAULT, TransportPayloadType.PROTOBUF, null, null, null, RPC_REQUEST_PROTO_SCHEMA, null, null, DeviceProfileProvisionType.DISABLED);
38 74 }
39 75
40 76 @After
... ... @@ -43,33 +79,91 @@ public abstract class AbstractCoapServerSideRpcProtoIntegrationTest extends Abst
43 79 }
44 80
45 81 @Test
46   - public void testServerMqttOneWayRpc() throws Exception {
  82 + public void testServerCoapOneWayRpc() throws Exception {
47 83 processOneWayRpcTest();
48 84 }
49 85
50 86 @Test
51   - public void testServerMqttTwoWayRpc() throws Exception {
  87 + public void testServerCoapTwoWayRpc() throws Exception {
52 88 processTwoWayRpcTest();
53 89 }
54 90
  91 + protected void processTwoWayRpcTest() throws Exception {
  92 + CoapClient client = getCoapClient(FeatureType.RPC);
  93 + client.useCONs();
  94 +
  95 + CountDownLatch latch = new CountDownLatch(1);
  96 + TestCoapCallback testCoapCallback = new TestCoapCallback(client, latch, false);
  97 +
  98 + Request request = Request.newGet().setObserve();
  99 + request.setType(CoAP.Type.CON);
  100 + CoapObserveRelation observeRelation = client.observe(request, testCoapCallback);
  101 +
  102 + String setGpioRequest = "{\"method\":\"setGpio\",\"params\":{\"pin\": \"26\",\"value\": 1}}";
  103 + String deviceId = savedDevice.getId().getId().toString();
  104 +
  105 + String expected = "{\"payload\":\"{\\\"value1\\\":\\\"A\\\",\\\"value2\\\":\\\"B\\\"}\"}";
  106 +
  107 + String result = doPostAsync("/api/plugins/rpc/twoway/" + deviceId, setGpioRequest, String.class, status().isOk());
  108 + latch.await(3, TimeUnit.SECONDS);
  109 +
  110 + assertEquals(expected, result);
  111 + assertEquals(0, testCoapCallback.getObserve().intValue());
  112 + observeRelation.proactiveCancel();
  113 + assertTrue(observeRelation.isCanceled());
  114 + }
  115 +
55 116 @Override
56 117 protected void processOnLoadResponse(CoapResponse response, CoapClient client, Integer observe, CountDownLatch latch) {
57 118 client.setURI(getRpcResponseFeatureTokenUrl(accessToken, observe));
58   - TransportProtos.ToDeviceRpcResponseMsg toDeviceRpcResponseMsg = TransportProtos.ToDeviceRpcResponseMsg.newBuilder()
59   - .setPayload(DEVICE_RESPONSE)
60   - .setRequestId(observe)
61   - .build();
62   - client.post(new CoapHandler() {
63   - @Override
64   - public void onLoad(CoapResponse response) {
65   - log.warn("Command Response Ack: {}, {}", response.getCode(), response.getResponseText());
66   - latch.countDown();
67   - }
  119 + ProtoTransportPayloadConfiguration protoTransportPayloadConfiguration = getProtoTransportPayloadConfiguration();
  120 + ProtoFileElement rpcRequestProtoSchemaFile = protoTransportPayloadConfiguration.getTransportProtoSchema(RPC_REQUEST_PROTO_SCHEMA);
  121 + DynamicSchema rpcRequestProtoSchema = protoTransportPayloadConfiguration.getDynamicSchema(rpcRequestProtoSchemaFile, ProtoTransportPayloadConfiguration.RPC_REQUEST_PROTO_SCHEMA);
68 122
69   - @Override
70   - public void onError() {
71   - log.warn("Command Response Ack Error, No connect");
  123 + byte[] requestPayload = response.getPayload();
  124 + DynamicMessage.Builder rpcRequestMsg = rpcRequestProtoSchema.newMessageBuilder("RpcRequestMsg");
  125 + Descriptors.Descriptor rpcRequestMsgDescriptor = rpcRequestMsg.getDescriptorForType();
  126 + assertNotNull(rpcRequestMsgDescriptor);
  127 + try {
  128 + DynamicMessage dynamicMessage = DynamicMessage.parseFrom(rpcRequestMsgDescriptor, requestPayload);
  129 + List<Descriptors.FieldDescriptor> fields = rpcRequestMsgDescriptor.getFields();
  130 + for (Descriptors.FieldDescriptor fieldDescriptor: fields) {
  131 + assertTrue(dynamicMessage.hasField(fieldDescriptor));
72 132 }
73   - }, toDeviceRpcResponseMsg.toByteArray(), MediaTypeRegistry.APPLICATION_JSON);
  133 + ProtoFileElement rpcResponseProtoSchemaFile = protoTransportPayloadConfiguration.getTransportProtoSchema(DEVICE_RPC_RESPONSE_PROTO_SCHEMA);
  134 + DynamicSchema rpcResponseProtoSchema = protoTransportPayloadConfiguration.getDynamicSchema(rpcResponseProtoSchemaFile, ProtoTransportPayloadConfiguration.RPC_RESPONSE_PROTO_SCHEMA);
  135 + DynamicMessage.Builder rpcResponseBuilder = rpcResponseProtoSchema.newMessageBuilder("RpcResponseMsg");
  136 + Descriptors.Descriptor rpcResponseMsgDescriptor = rpcResponseBuilder.getDescriptorForType();
  137 + assertNotNull(rpcResponseMsgDescriptor);
  138 + DynamicMessage rpcResponseMsg = rpcResponseBuilder
  139 + .setField(rpcResponseMsgDescriptor.findFieldByName("payload"), DEVICE_RESPONSE)
  140 + .build();
  141 + client.post(new CoapHandler() {
  142 + @Override
  143 + public void onLoad(CoapResponse response) {
  144 + log.warn("Command Response Ack: {}, {}", response.getCode(), response.getResponseText());
  145 + latch.countDown();
  146 + }
  147 +
  148 + @Override
  149 + public void onError() {
  150 + log.warn("Command Response Ack Error, No connect");
  151 + }
  152 + }, rpcResponseMsg.toByteArray(), MediaTypeRegistry.APPLICATION_JSON);
  153 + } catch (InvalidProtocolBufferException e) {
  154 + log.warn("Command Response Ack Error, Invalid response received: ", e);
  155 + }
  156 + }
  157 +
  158 + private ProtoTransportPayloadConfiguration getProtoTransportPayloadConfiguration() {
  159 + DeviceProfileTransportConfiguration transportConfiguration = deviceProfile.getProfileData().getTransportConfiguration();
  160 + assertTrue(transportConfiguration instanceof CoapDeviceProfileTransportConfiguration);
  161 + CoapDeviceProfileTransportConfiguration coapDeviceProfileTransportConfiguration = (CoapDeviceProfileTransportConfiguration) transportConfiguration;
  162 + CoapDeviceTypeConfiguration coapDeviceTypeConfiguration = coapDeviceProfileTransportConfiguration.getCoapDeviceTypeConfiguration();
  163 + assertTrue(coapDeviceTypeConfiguration instanceof DefaultCoapDeviceTypeConfiguration);
  164 + DefaultCoapDeviceTypeConfiguration defaultCoapDeviceTypeConfiguration = (DefaultCoapDeviceTypeConfiguration) coapDeviceTypeConfiguration;
  165 + TransportPayloadTypeConfiguration transportPayloadTypeConfiguration = defaultCoapDeviceTypeConfiguration.getTransportPayloadTypeConfiguration();
  166 + assertTrue(transportPayloadTypeConfiguration instanceof ProtoTransportPayloadConfiguration);
  167 + return (ProtoTransportPayloadConfiguration) transportPayloadTypeConfiguration;
74 168 }
75 169 }
... ...
... ... @@ -114,7 +114,7 @@ public abstract class AbstractCoapTimeseriesProtoIntegrationTest extends Abstrac
114 114 " }\n" +
115 115 " }\n" +
116 116 "}";
117   - super.processBeforeTest("Test Post Telemetry device proto payload", CoapDeviceType.DEFAULT, TransportPayloadType.PROTOBUF, schemaStr, null, DeviceProfileProvisionType.DISABLED, null, null);
  117 + super.processBeforeTest("Test Post Telemetry device proto payload", CoapDeviceType.DEFAULT, TransportPayloadType.PROTOBUF, schemaStr, null, null, null, null, null, DeviceProfileProvisionType.DISABLED);
118 118 DeviceProfileTransportConfiguration transportConfiguration = deviceProfile.getProfileData().getTransportConfiguration();
119 119 assertTrue(transportConfiguration instanceof CoapDeviceProfileTransportConfiguration);
120 120 CoapDeviceProfileTransportConfiguration coapDeviceProfileTransportConfiguration = (CoapDeviceProfileTransportConfiguration) transportConfiguration;
... ...
... ... @@ -62,7 +62,7 @@ public abstract class AbstractMqttIntegrationTest extends AbstractTransportInteg
62 62 protected DeviceProfile deviceProfile;
63 63
64 64 protected void processBeforeTest (String deviceName, String gatewayName, TransportPayloadType payloadType, String telemetryTopic, String attributesTopic) throws Exception {
65   - this.processBeforeTest(deviceName, gatewayName, payloadType, telemetryTopic, attributesTopic, null, null, DeviceProfileProvisionType.DISABLED, null, null);
  65 + this.processBeforeTest(deviceName, gatewayName, payloadType, telemetryTopic, attributesTopic, null, null, null, null, null, null, DeviceProfileProvisionType.DISABLED);
66 66 }
67 67
68 68 protected void processBeforeTest(String deviceName,
... ... @@ -72,9 +72,12 @@ public abstract class AbstractMqttIntegrationTest extends AbstractTransportInteg
72 72 String attributesTopic,
73 73 String telemetryProtoSchema,
74 74 String attributesProtoSchema,
75   - DeviceProfileProvisionType provisionType,
76   - String provisionKey, String provisionSecret
77   - ) throws Exception {
  75 + String rpcResponseProtoSchema,
  76 + String rpcRequestProtoSchema,
  77 + String provisionKey,
  78 + String provisionSecret,
  79 + DeviceProfileProvisionType provisionType
  80 + ) throws Exception {
78 81 loginSysAdmin();
79 82
80 83 Tenant tenant = new Tenant();
... ... @@ -103,7 +106,7 @@ public abstract class AbstractMqttIntegrationTest extends AbstractTransportInteg
103 106 gateway.setAdditionalInfo(additionalInfo);
104 107
105 108 if (payloadType != null) {
106   - DeviceProfile mqttDeviceProfile = createMqttDeviceProfile(payloadType, telemetryTopic, attributesTopic, telemetryProtoSchema, attributesProtoSchema, provisionType, provisionKey, provisionSecret);
  109 + DeviceProfile mqttDeviceProfile = createMqttDeviceProfile(payloadType, telemetryTopic, attributesTopic, telemetryProtoSchema, attributesProtoSchema, rpcResponseProtoSchema, rpcRequestProtoSchema, provisionKey, provisionSecret, provisionType);
107 110 deviceProfile = doPost("/api/deviceProfile", mqttDeviceProfile, DeviceProfile.class);
108 111 device.setType(deviceProfile.getName());
109 112 device.setDeviceProfileId(deviceProfile.getId());
... ... @@ -157,8 +160,9 @@ public abstract class AbstractMqttIntegrationTest extends AbstractTransportInteg
157 160 protected DeviceProfile createMqttDeviceProfile(TransportPayloadType transportPayloadType,
158 161 String telemetryTopic, String attributesTopic,
159 162 String telemetryProtoSchema, String attributesProtoSchema,
160   - DeviceProfileProvisionType provisionType,
161   - String provisionKey, String provisionSecret) {
  163 + String rpcResponseProtoSchema, String rpcRequestProtoSchema,
  164 + String provisionKey, String provisionSecret,
  165 + DeviceProfileProvisionType provisionType) {
162 166 DeviceProfile deviceProfile = new DeviceProfile();
163 167 deviceProfile.setName(transportPayloadType.name());
164 168 deviceProfile.setType(DeviceProfileType.DEFAULT);
... ... @@ -186,8 +190,16 @@ public abstract class AbstractMqttIntegrationTest extends AbstractTransportInteg
186 190 if (StringUtils.isEmpty(attributesProtoSchema)) {
187 191 attributesProtoSchema = DEVICE_ATTRIBUTES_PROTO_SCHEMA;
188 192 }
  193 + if (StringUtils.isEmpty(rpcResponseProtoSchema)) {
  194 + rpcResponseProtoSchema = DEVICE_RPC_RESPONSE_PROTO_SCHEMA;
  195 + }
  196 + if (StringUtils.isEmpty(rpcRequestProtoSchema)) {
  197 + rpcRequestProtoSchema = DEVICE_RPC_REQUEST_PROTO_SCHEMA;
  198 + }
189 199 protoTransportPayloadConfiguration.setDeviceTelemetryProtoSchema(telemetryProtoSchema);
190 200 protoTransportPayloadConfiguration.setDeviceAttributesProtoSchema(attributesProtoSchema);
  201 + protoTransportPayloadConfiguration.setDeviceRpcResponseProtoSchema(rpcResponseProtoSchema);
  202 + protoTransportPayloadConfiguration.setDeviceRpcRequestProtoSchema(rpcRequestProtoSchema);
191 203 transportPayloadTypeConfiguration = protoTransportPayloadConfiguration;
192 204 }
193 205 mqttDeviceProfileTransportConfiguration.setTransportPayloadTypeConfiguration(transportPayloadTypeConfiguration);
... ...
... ... @@ -83,7 +83,7 @@ public abstract class AbstractMqttAttributesRequestProtoIntegrationTest extends
83 83 @Test
84 84 public void testRequestAttributesValuesFromTheServer() throws Exception {
85 85 super.processBeforeTest("Test Request attribute values from the server proto", "Gateway Test Request attribute values from the server proto",
86   - TransportPayloadType.PROTOBUF, null, null, null, ATTRIBUTES_SCHEMA_STR, DeviceProfileProvisionType.DISABLED, null, null);
  86 + TransportPayloadType.PROTOBUF, null, null, null, ATTRIBUTES_SCHEMA_STR, null, null, null, null, DeviceProfileProvisionType.DISABLED);
87 87 processTestRequestAttributesValuesFromTheServer();
88 88 }
89 89
... ...
... ... @@ -94,7 +94,7 @@ public abstract class AbstractMqttProvisionJsonDeviceTest extends AbstractMqttIn
94 94
95 95
96 96 protected void processTestProvisioningDisabledDevice() throws Exception {
97   - super.processBeforeTest("Test Provision device", "Test Provision gateway", TransportPayloadType.JSON, null, null, null, null, DeviceProfileProvisionType.DISABLED, null, null);
  97 + super.processBeforeTest("Test Provision device", "Test Provision gateway", TransportPayloadType.JSON, null, null, null, null, null, null, null, null, DeviceProfileProvisionType.DISABLED);
98 98 byte[] result = createMqttClientAndPublish().getPayloadBytes();
99 99 JsonObject response = JsonUtils.parse(new String(result)).getAsJsonObject();
100 100 Assert.assertEquals("Provision data was not found!", response.get("errorMsg").getAsString());
... ... @@ -103,7 +103,7 @@ public abstract class AbstractMqttProvisionJsonDeviceTest extends AbstractMqttIn
103 103
104 104
105 105 protected void processTestProvisioningCreateNewDeviceWithoutCredentials() throws Exception {
106   - super.processBeforeTest("Test Provision device3", "Test Provision gateway", TransportPayloadType.JSON, null, null, null, null, DeviceProfileProvisionType.ALLOW_CREATE_NEW_DEVICES, "testProvisionKey", "testProvisionSecret");
  106 + super.processBeforeTest("Test Provision device3", "Test Provision gateway", TransportPayloadType.JSON, null, null, null, null, null, null, "testProvisionKey", "testProvisionSecret", DeviceProfileProvisionType.ALLOW_CREATE_NEW_DEVICES);
107 107 byte[] result = createMqttClientAndPublish().getPayloadBytes();
108 108 JsonObject response = JsonUtils.parse(new String(result)).getAsJsonObject();
109 109
... ... @@ -119,7 +119,7 @@ public abstract class AbstractMqttProvisionJsonDeviceTest extends AbstractMqttIn
119 119
120 120
121 121 protected void processTestProvisioningCreateNewDeviceWithAccessToken() throws Exception {
122   - super.processBeforeTest("Test Provision device3", "Test Provision gateway", TransportPayloadType.JSON, null, null, null, null, DeviceProfileProvisionType.ALLOW_CREATE_NEW_DEVICES, "testProvisionKey", "testProvisionSecret");
  122 + super.processBeforeTest("Test Provision device3", "Test Provision gateway", TransportPayloadType.JSON, null, null, null, null, null, null, "testProvisionKey", "testProvisionSecret", DeviceProfileProvisionType.ALLOW_CREATE_NEW_DEVICES);
123 123 String requestCredentials = ",\"credentialsType\": \"ACCESS_TOKEN\",\"token\": \"test_token\"";
124 124 byte[] result = createMqttClientAndPublish(requestCredentials).getPayloadBytes();
125 125 JsonObject response = JsonUtils.parse(new String(result)).getAsJsonObject();
... ... @@ -138,7 +138,7 @@ public abstract class AbstractMqttProvisionJsonDeviceTest extends AbstractMqttIn
138 138
139 139
140 140 protected void processTestProvisioningCreateNewDeviceWithCert() throws Exception {
141   - super.processBeforeTest("Test Provision device3", "Test Provision gateway", TransportPayloadType.JSON, null, null, null, null, DeviceProfileProvisionType.ALLOW_CREATE_NEW_DEVICES, "testProvisionKey", "testProvisionSecret");
  141 + super.processBeforeTest("Test Provision device3", "Test Provision gateway", TransportPayloadType.JSON, null, null, null, null, null, null, "testProvisionKey", "testProvisionSecret", DeviceProfileProvisionType.ALLOW_CREATE_NEW_DEVICES);
142 142 String requestCredentials = ",\"credentialsType\": \"X509_CERTIFICATE\",\"hash\": \"testHash\"";
143 143 byte[] result = createMqttClientAndPublish(requestCredentials).getPayloadBytes();
144 144 JsonObject response = JsonUtils.parse(new String(result)).getAsJsonObject();
... ... @@ -163,7 +163,7 @@ public abstract class AbstractMqttProvisionJsonDeviceTest extends AbstractMqttIn
163 163
164 164
165 165 protected void processTestProvisioningCreateNewDeviceWithMqttBasic() throws Exception {
166   - super.processBeforeTest("Test Provision device3", "Test Provision gateway", TransportPayloadType.JSON, null, null, null, null, DeviceProfileProvisionType.ALLOW_CREATE_NEW_DEVICES, "testProvisionKey", "testProvisionSecret");
  166 + super.processBeforeTest("Test Provision device3", "Test Provision gateway", TransportPayloadType.JSON, null, null, null, null, null, null, "testProvisionKey", "testProvisionSecret", DeviceProfileProvisionType.ALLOW_CREATE_NEW_DEVICES);
167 167 String requestCredentials = ",\"credentialsType\": \"MQTT_BASIC\",\"clientId\": \"test_clientId\",\"username\": \"test_username\",\"password\": \"test_password\"";
168 168 byte[] result = createMqttClientAndPublish(requestCredentials).getPayloadBytes();
169 169 JsonObject response = JsonUtils.parse(new String(result)).getAsJsonObject();
... ... @@ -188,7 +188,7 @@ public abstract class AbstractMqttProvisionJsonDeviceTest extends AbstractMqttIn
188 188 }
189 189
190 190 protected void processTestProvisioningCheckPreProvisionedDevice() throws Exception {
191   - super.processBeforeTest("Test Provision device", "Test Provision gateway", TransportPayloadType.JSON, null, null, null, null, DeviceProfileProvisionType.CHECK_PRE_PROVISIONED_DEVICES, "testProvisionKey", "testProvisionSecret");
  191 + super.processBeforeTest("Test Provision device", "Test Provision gateway", TransportPayloadType.JSON, null, null, null, null, null, null, "testProvisionKey", "testProvisionSecret", DeviceProfileProvisionType.CHECK_PRE_PROVISIONED_DEVICES);
192 192 byte[] result = createMqttClientAndPublish().getPayloadBytes();
193 193 JsonObject response = JsonUtils.parse(new String(result)).getAsJsonObject();
194 194
... ... @@ -199,7 +199,7 @@ public abstract class AbstractMqttProvisionJsonDeviceTest extends AbstractMqttIn
199 199 }
200 200
201 201 protected void processTestProvisioningWithBadKeyDevice() throws Exception {
202   - super.processBeforeTest("Test Provision device", "Test Provision gateway", TransportPayloadType.JSON, null, null, null, null, DeviceProfileProvisionType.CHECK_PRE_PROVISIONED_DEVICES, "testProvisionKeyOrig", "testProvisionSecret");
  202 + super.processBeforeTest("Test Provision device", "Test Provision gateway", TransportPayloadType.JSON, null, null, null, null, null, null, "testProvisionKeyOrig", "testProvisionSecret", DeviceProfileProvisionType.CHECK_PRE_PROVISIONED_DEVICES);
203 203 byte[] result = createMqttClientAndPublish().getPayloadBytes();
204 204 JsonObject response = JsonUtils.parse(new String(result)).getAsJsonObject();
205 205 Assert.assertEquals("Provision data was not found!", response.get("errorMsg").getAsString());
... ...
... ... @@ -101,14 +101,14 @@ public abstract class AbstractMqttProvisionProtoDeviceTest extends AbstractMqttI
101 101
102 102
103 103 protected void processTestProvisioningDisabledDevice() throws Exception {
104   - super.processBeforeTest("Test Provision device", "Test Provision gateway", TransportPayloadType.PROTOBUF, null, null, null, null, DeviceProfileProvisionType.DISABLED, null, null);
  104 + super.processBeforeTest("Test Provision device", "Test Provision gateway", TransportPayloadType.PROTOBUF, null, null, null, null, null, null, null, null, DeviceProfileProvisionType.DISABLED);
105 105 ProvisionDeviceResponseMsg result = ProvisionDeviceResponseMsg.parseFrom(createMqttClientAndPublish().getPayloadBytes());
106 106 Assert.assertNotNull(result);
107 107 Assert.assertEquals(ProvisionResponseStatus.NOT_FOUND.name(), result.getStatus().toString());
108 108 }
109 109
110 110 protected void processTestProvisioningCreateNewDeviceWithoutCredentials() throws Exception {
111   - super.processBeforeTest("Test Provision device3", "Test Provision gateway", TransportPayloadType.PROTOBUF, null, null, null, null, DeviceProfileProvisionType.ALLOW_CREATE_NEW_DEVICES, "testProvisionKey", "testProvisionSecret");
  111 + super.processBeforeTest("Test Provision device3", "Test Provision gateway", TransportPayloadType.PROTOBUF, null, null, null, null, null, null, "testProvisionKey", "testProvisionSecret", DeviceProfileProvisionType.ALLOW_CREATE_NEW_DEVICES);
112 112 ProvisionDeviceResponseMsg response = ProvisionDeviceResponseMsg.parseFrom(createMqttClientAndPublish().getPayloadBytes());
113 113
114 114 Device createdDevice = deviceService.findDeviceByTenantIdAndName(savedTenant.getTenantId(), "Test Provision device");
... ... @@ -122,7 +122,7 @@ public abstract class AbstractMqttProvisionProtoDeviceTest extends AbstractMqttI
122 122 }
123 123
124 124 protected void processTestProvisioningCreateNewDeviceWithAccessToken() throws Exception {
125   - super.processBeforeTest("Test Provision device3", "Test Provision gateway", TransportPayloadType.PROTOBUF, null, null,null, null, DeviceProfileProvisionType.ALLOW_CREATE_NEW_DEVICES, "testProvisionKey", "testProvisionSecret");
  125 + super.processBeforeTest("Test Provision device3", "Test Provision gateway", TransportPayloadType.PROTOBUF, null, null,null, null, null, null, "testProvisionKey", "testProvisionSecret", DeviceProfileProvisionType.ALLOW_CREATE_NEW_DEVICES);
126 126 CredentialsDataProto requestCredentials = CredentialsDataProto.newBuilder().setValidateDeviceTokenRequestMsg(ValidateDeviceTokenRequestMsg.newBuilder().setToken("test_token").build()).build();
127 127
128 128 ProvisionDeviceResponseMsg response = ProvisionDeviceResponseMsg.parseFrom(createMqttClientAndPublish(createTestsProvisionMessage(CredentialsType.ACCESS_TOKEN, requestCredentials)).getPayloadBytes());
... ... @@ -140,7 +140,7 @@ public abstract class AbstractMqttProvisionProtoDeviceTest extends AbstractMqttI
140 140 }
141 141
142 142 protected void processTestProvisioningCreateNewDeviceWithCert() throws Exception {
143   - super.processBeforeTest("Test Provision device3", "Test Provision gateway", TransportPayloadType.PROTOBUF, null, null, null, null, DeviceProfileProvisionType.ALLOW_CREATE_NEW_DEVICES, "testProvisionKey", "testProvisionSecret");
  143 + super.processBeforeTest("Test Provision device3", "Test Provision gateway", TransportPayloadType.PROTOBUF, null, null, null, null, null, null, "testProvisionKey", "testProvisionSecret", DeviceProfileProvisionType.ALLOW_CREATE_NEW_DEVICES);
144 144 CredentialsDataProto requestCredentials = CredentialsDataProto.newBuilder().setValidateDeviceX509CertRequestMsg(ValidateDeviceX509CertRequestMsg.newBuilder().setHash("testHash").build()).build();
145 145
146 146 ProvisionDeviceResponseMsg response = ProvisionDeviceResponseMsg.parseFrom(createMqttClientAndPublish(createTestsProvisionMessage(CredentialsType.X509_CERTIFICATE, requestCredentials)).getPayloadBytes());
... ... @@ -164,7 +164,7 @@ public abstract class AbstractMqttProvisionProtoDeviceTest extends AbstractMqttI
164 164 }
165 165
166 166 protected void processTestProvisioningCreateNewDeviceWithMqttBasic() throws Exception {
167   - super.processBeforeTest("Test Provision device3", "Test Provision gateway", TransportPayloadType.PROTOBUF, null, null, null, null, DeviceProfileProvisionType.ALLOW_CREATE_NEW_DEVICES, "testProvisionKey", "testProvisionSecret");
  167 + super.processBeforeTest("Test Provision device3", "Test Provision gateway", TransportPayloadType.PROTOBUF, null, null, null, null, null, null, "testProvisionKey", "testProvisionSecret", DeviceProfileProvisionType.ALLOW_CREATE_NEW_DEVICES);
168 168 CredentialsDataProto requestCredentials = CredentialsDataProto.newBuilder().setValidateBasicMqttCredRequestMsg(
169 169 ValidateBasicMqttCredRequestMsg.newBuilder()
170 170 .setClientId("test_clientId")
... ... @@ -195,7 +195,7 @@ public abstract class AbstractMqttProvisionProtoDeviceTest extends AbstractMqttI
195 195 }
196 196
197 197 protected void processTestProvisioningCheckPreProvisionedDevice() throws Exception {
198   - super.processBeforeTest("Test Provision device", "Test Provision gateway", TransportPayloadType.PROTOBUF, null, null, null, null, DeviceProfileProvisionType.CHECK_PRE_PROVISIONED_DEVICES, "testProvisionKey", "testProvisionSecret");
  198 + super.processBeforeTest("Test Provision device", "Test Provision gateway", TransportPayloadType.PROTOBUF, null, null, null, null, null, null, "testProvisionKey", "testProvisionSecret", DeviceProfileProvisionType.CHECK_PRE_PROVISIONED_DEVICES);
199 199 ProvisionDeviceResponseMsg response = ProvisionDeviceResponseMsg.parseFrom(createMqttClientAndPublish().getPayloadBytes());
200 200
201 201 DeviceCredentials deviceCredentials = deviceCredentialsService.findDeviceCredentialsByDeviceId(savedTenant.getTenantId(), savedDevice.getId());
... ... @@ -205,7 +205,7 @@ public abstract class AbstractMqttProvisionProtoDeviceTest extends AbstractMqttI
205 205 }
206 206
207 207 protected void processTestProvisioningWithBadKeyDevice() throws Exception {
208   - super.processBeforeTest("Test Provision device", "Test Provision gateway", TransportPayloadType.PROTOBUF, null, null, null, null, DeviceProfileProvisionType.CHECK_PRE_PROVISIONED_DEVICES, "testProvisionKeyOrig", "testProvisionSecret");
  208 + super.processBeforeTest("Test Provision device", "Test Provision gateway", TransportPayloadType.PROTOBUF, null, null, null, null, null, null, "testProvisionKeyOrig", "testProvisionSecret", DeviceProfileProvisionType.CHECK_PRE_PROVISIONED_DEVICES);
209 209 ProvisionDeviceResponseMsg response = ProvisionDeviceResponseMsg.parseFrom(createMqttClientAndPublish().getPayloadBytes());
210 210 Assert.assertEquals(ProvisionResponseStatus.NOT_FOUND.name(), response.getStatus().toString());
211 211 }
... ...
... ... @@ -180,7 +180,7 @@ public abstract class AbstractMqttServerSideRpcIntegrationTest extends AbstractM
180 180 return message;
181 181 }
182 182
183   - private class TestMqttCallback implements MqttCallback {
  183 + protected class TestMqttCallback implements MqttCallback {
184 184
185 185 private final MqttAsyncClient client;
186 186 private final CountDownLatch latch;
... ...
... ... @@ -15,25 +15,60 @@
15 15 */
16 16 package org.thingsboard.server.transport.mqtt.rpc;
17 17
  18 +import com.github.os72.protobuf.dynamic.DynamicSchema;
  19 +import com.google.protobuf.Descriptors;
  20 +import com.google.protobuf.DynamicMessage;
18 21 import com.google.protobuf.InvalidProtocolBufferException;
  22 +import com.squareup.wire.schema.internal.parser.ProtoFileElement;
19 23 import lombok.extern.slf4j.Slf4j;
  24 +import org.eclipse.californium.core.CoapHandler;
  25 +import org.eclipse.californium.core.CoapResponse;
  26 +import org.eclipse.californium.core.coap.MediaTypeRegistry;
20 27 import org.eclipse.paho.client.mqttv3.MqttAsyncClient;
21 28 import org.eclipse.paho.client.mqttv3.MqttException;
22 29 import org.eclipse.paho.client.mqttv3.MqttMessage;
  30 +import org.jetbrains.annotations.NotNull;
23 31 import org.junit.After;
  32 +import org.junit.Assert;
24 33 import org.junit.Before;
25 34 import org.junit.Test;
  35 +import org.thingsboard.server.common.data.DeviceProfileProvisionType;
26 36 import org.thingsboard.server.common.data.TransportPayloadType;
  37 +import org.thingsboard.server.common.data.device.profile.DeviceProfileTransportConfiguration;
  38 +import org.thingsboard.server.common.data.device.profile.MqttDeviceProfileTransportConfiguration;
27 39 import org.thingsboard.server.common.data.device.profile.MqttTopics;
  40 +import org.thingsboard.server.common.data.device.profile.ProtoTransportPayloadConfiguration;
  41 +import org.thingsboard.server.common.data.device.profile.TransportPayloadTypeConfiguration;
28 42 import org.thingsboard.server.gen.transport.TransportApiProtos;
29   -import org.thingsboard.server.gen.transport.TransportProtos;
  43 +
  44 +import java.util.List;
  45 +import java.util.concurrent.CountDownLatch;
  46 +import java.util.concurrent.TimeUnit;
  47 +
  48 +import static org.junit.Assert.assertNotNull;
  49 +import static org.junit.Assert.assertTrue;
  50 +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
30 51
31 52 @Slf4j
32 53 public abstract class AbstractMqttServerSideRpcProtoIntegrationTest extends AbstractMqttServerSideRpcIntegrationTest {
33 54
  55 + private static final String RPC_REQUEST_PROTO_SCHEMA = "syntax =\"proto3\";\n" +
  56 + "package rpc;\n" +
  57 + "\n" +
  58 + "message RpcRequestMsg {\n" +
  59 + " string method = 1;\n" +
  60 + " int32 requestId = 2;\n" +
  61 + " Params params = 3;\n" +
  62 + "\n" +
  63 + " message Params {\n" +
  64 + " string pin = 1;\n" +
  65 + " int32 value = 2;\n" +
  66 + " }\n" +
  67 + "}";
  68 +
34 69 @Before
35 70 public void beforeTest() throws Exception {
36   - processBeforeTest("RPC test device", "RPC test gateway", TransportPayloadType.PROTOBUF, null, null);
  71 + processBeforeTest("RPC test device", "RPC test gateway", TransportPayloadType.PROTOBUF, null, null, null, null, null, RPC_REQUEST_PROTO_SCHEMA, null, null, DeviceProfileProvisionType.DISABLED);
37 72 }
38 73
39 74 @After
... ... @@ -83,14 +118,55 @@ public abstract class AbstractMqttServerSideRpcProtoIntegrationTest extends Abst
83 118 return builder.build();
84 119 }
85 120
  121 + protected void processTwoWayRpcTest() throws Exception {
  122 + MqttAsyncClient client = getMqttAsyncClient(accessToken);
  123 + client.subscribe(MqttTopics.DEVICE_RPC_REQUESTS_SUB_TOPIC, 1);
  124 +
  125 + CountDownLatch latch = new CountDownLatch(1);
  126 + TestMqttCallback callback = new TestMqttCallback(client, latch);
  127 + client.setCallback(callback);
  128 +
  129 + Thread.sleep(1000);
  130 +
  131 + String setGpioRequest = "{\"method\":\"setGpio\",\"params\":{\"pin\": \"26\",\"value\": 1}}";
  132 + String deviceId = savedDevice.getId().getId().toString();
  133 +
  134 + String result = doPostAsync("/api/plugins/rpc/twoway/" + deviceId, setGpioRequest, String.class, status().isOk());
  135 + String expected = "{\"payload\":\"{\\\"value1\\\":\\\"A\\\",\\\"value2\\\":\\\"B\\\"}\"}";
  136 + latch.await(3, TimeUnit.SECONDS);
  137 + Assert.assertEquals(expected, result);
  138 + }
  139 +
86 140 protected MqttMessage processMessageArrived(String requestTopic, MqttMessage mqttMessage) throws MqttException, InvalidProtocolBufferException {
87 141 MqttMessage message = new MqttMessage();
88 142 if (requestTopic.startsWith(MqttTopics.BASE_DEVICE_API_TOPIC)) {
89   - TransportProtos.ToDeviceRpcResponseMsg toDeviceRpcResponseMsg = TransportProtos.ToDeviceRpcResponseMsg.newBuilder()
90   - .setPayload(DEVICE_RESPONSE)
91   - .setRequestId(0)
  143 + ProtoTransportPayloadConfiguration protoTransportPayloadConfiguration = getProtoTransportPayloadConfiguration();
  144 + ProtoFileElement rpcRequestProtoSchemaFile = protoTransportPayloadConfiguration.getTransportProtoSchema(RPC_REQUEST_PROTO_SCHEMA);
  145 + DynamicSchema rpcRequestProtoSchema = protoTransportPayloadConfiguration.getDynamicSchema(rpcRequestProtoSchemaFile, ProtoTransportPayloadConfiguration.RPC_REQUEST_PROTO_SCHEMA);
  146 +
  147 + byte[] requestPayload = mqttMessage.getPayload();
  148 + DynamicMessage.Builder rpcRequestMsg = rpcRequestProtoSchema.newMessageBuilder("RpcRequestMsg");
  149 + Descriptors.Descriptor rpcRequestMsgDescriptor = rpcRequestMsg.getDescriptorForType();
  150 + assertNotNull(rpcRequestMsgDescriptor);
  151 + try {
  152 + DynamicMessage dynamicMessage = DynamicMessage.parseFrom(rpcRequestMsgDescriptor, requestPayload);
  153 + List<Descriptors.FieldDescriptor> fields = rpcRequestMsgDescriptor.getFields();
  154 + for (Descriptors.FieldDescriptor fieldDescriptor: fields) {
  155 + assertTrue(dynamicMessage.hasField(fieldDescriptor));
  156 + }
  157 + ProtoFileElement transportProtoSchemaFile = protoTransportPayloadConfiguration.getTransportProtoSchema(DEVICE_RPC_RESPONSE_PROTO_SCHEMA);
  158 + DynamicSchema rpcResponseProtoSchema = protoTransportPayloadConfiguration.getDynamicSchema(transportProtoSchemaFile, ProtoTransportPayloadConfiguration.RPC_RESPONSE_PROTO_SCHEMA);
  159 +
  160 + DynamicMessage.Builder rpcResponseBuilder = rpcResponseProtoSchema.newMessageBuilder("RpcResponseMsg");
  161 + Descriptors.Descriptor rpcResponseMsgDescriptor = rpcResponseBuilder.getDescriptorForType();
  162 + assertNotNull(rpcResponseMsgDescriptor);
  163 + DynamicMessage rpcResponseMsg = rpcResponseBuilder
  164 + .setField(rpcResponseMsgDescriptor.findFieldByName("payload"), DEVICE_RESPONSE)
92 165 .build();
93   - message.setPayload(toDeviceRpcResponseMsg.toByteArray());
  166 + message.setPayload(rpcResponseMsg.toByteArray());
  167 + } catch (InvalidProtocolBufferException e) {
  168 + log.warn("Command Response Ack Error, Invalid response received: ", e);
  169 + }
94 170 } else {
95 171 TransportApiProtos.GatewayDeviceRpcRequestMsg msg = TransportApiProtos.GatewayDeviceRpcRequestMsg.parseFrom(mqttMessage.getPayload());
96 172 String deviceName = msg.getDeviceName();
... ... @@ -105,6 +181,14 @@ public abstract class AbstractMqttServerSideRpcProtoIntegrationTest extends Abst
105 181 return message;
106 182 }
107 183
  184 + private ProtoTransportPayloadConfiguration getProtoTransportPayloadConfiguration() {
  185 + DeviceProfileTransportConfiguration transportConfiguration = deviceProfile.getProfileData().getTransportConfiguration();
  186 + assertTrue(transportConfiguration instanceof MqttDeviceProfileTransportConfiguration);
  187 + MqttDeviceProfileTransportConfiguration mqttTransportConfiguration = (MqttDeviceProfileTransportConfiguration) transportConfiguration;
  188 + TransportPayloadTypeConfiguration transportPayloadTypeConfiguration = mqttTransportConfiguration.getTransportPayloadTypeConfiguration();
  189 + assertTrue(transportPayloadTypeConfiguration instanceof ProtoTransportPayloadConfiguration);
  190 + return (ProtoTransportPayloadConfiguration) transportPayloadTypeConfiguration;
  191 + }
108 192
109 193
110 194 }
... ...
... ... @@ -119,7 +119,7 @@ public abstract class AbstractMqttTimeseriesProtoIntegrationTest extends Abstrac
119 119 " }\n" +
120 120 " }\n" +
121 121 "}";
122   - super.processBeforeTest("Test Post Telemetry device proto payload", "Test Post Telemetry gateway proto payload", TransportPayloadType.PROTOBUF, POST_DATA_TELEMETRY_TOPIC, null, schemaStr, null, DeviceProfileProvisionType.DISABLED, null, null);
  122 + super.processBeforeTest("Test Post Telemetry device proto payload", "Test Post Telemetry gateway proto payload", TransportPayloadType.PROTOBUF, POST_DATA_TELEMETRY_TOPIC, null, schemaStr, null, null, null, null, null, DeviceProfileProvisionType.DISABLED);
123 123 List<String> expectedKeys = Arrays.asList("key1", "key2", "key3", "key4", "key5");
124 124 DeviceProfileTransportConfiguration transportConfiguration = deviceProfile.getProfileData().getTransportConfiguration();
125 125 assertTrue(transportConfiguration instanceof MqttDeviceProfileTransportConfiguration);
... ... @@ -172,7 +172,7 @@ public abstract class AbstractMqttTimeseriesProtoIntegrationTest extends Abstrac
172 172
173 173 @Test
174 174 public void testPushMqttTelemetryGateway() throws Exception {
175   - super.processBeforeTest("Test Post Telemetry device proto payload", "Test Post Telemetry gateway proto payload", TransportPayloadType.PROTOBUF, null, null, null, null, DeviceProfileProvisionType.DISABLED, null, null);
  175 + super.processBeforeTest("Test Post Telemetry device proto payload", "Test Post Telemetry gateway proto payload", TransportPayloadType.PROTOBUF, null, null, null, null, null, null, null, null, DeviceProfileProvisionType.DISABLED);
176 176 TransportApiProtos.GatewayTelemetryMsg.Builder gatewayTelemetryMsgProtoBuilder = TransportApiProtos.GatewayTelemetryMsg.newBuilder();
177 177 List<String> expectedKeys = Arrays.asList("key1", "key2", "key3", "key4", "key5");
178 178 String deviceName1 = "Device A";
... ... @@ -186,7 +186,7 @@ public abstract class AbstractMqttTimeseriesProtoIntegrationTest extends Abstrac
186 186
187 187 @Test
188 188 public void testGatewayConnect() throws Exception {
189   - super.processBeforeTest("Test Post Telemetry device proto payload", "Test Post Telemetry gateway proto payload", TransportPayloadType.PROTOBUF, POST_DATA_TELEMETRY_TOPIC, null, null, null, DeviceProfileProvisionType.DISABLED, null, null);
  189 + super.processBeforeTest("Test Post Telemetry device proto payload", "Test Post Telemetry gateway proto payload", TransportPayloadType.PROTOBUF, POST_DATA_TELEMETRY_TOPIC, null, null, null, null, null, null, null, DeviceProfileProvisionType.DISABLED);
190 190 String deviceName = "Device A";
191 191 TransportApiProtos.ConnectMsg connectMsgProto = getConnectProto(deviceName);
192 192 MqttAsyncClient client = getMqttAsyncClient(gatewayAccessToken);
... ...
... ... @@ -102,4 +102,6 @@ public interface DeviceService {
102 102 PageData<Device> findDevicesByTenantIdAndEdgeId(TenantId tenantId, EdgeId edgeId, PageLink pageLink);
103 103
104 104 PageData<Device> findDevicesByTenantIdAndEdgeIdAndType(TenantId tenantId, EdgeId edgeId, String type, PageLink pageLink);
  105 +
  106 + long countByTenantId(TenantId tenantId);
105 107 }
... ...
... ... @@ -17,6 +17,7 @@ package org.thingsboard.server.dao.event;
17 17
18 18 import com.google.common.util.concurrent.ListenableFuture;
19 19 import org.thingsboard.server.common.data.Event;
  20 +import org.thingsboard.server.common.data.event.EventFilter;
20 21 import org.thingsboard.server.common.data.id.EntityId;
21 22 import org.thingsboard.server.common.data.id.TenantId;
22 23 import org.thingsboard.server.common.data.page.PageData;
... ... @@ -41,6 +42,8 @@ public interface EventService {
41 42
42 43 List<Event> findLatestEvents(TenantId tenantId, EntityId entityId, String eventType, int limit);
43 44
  45 + PageData<Event> findEventsByFilter(TenantId tenantId, EntityId entityId, EventFilter eventFilter, TimePageLink pageLink);
  46 +
44 47 void removeEvents(TenantId tenantId, EntityId entityId);
45 48
46 49 }
... ...
  1 +/**
  2 + * Copyright © 2016-2021 The Thingsboard Authors
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +package org.thingsboard.server.dao.resource;
  17 +
  18 +import org.thingsboard.server.common.data.ResourceType;
  19 +import org.thingsboard.server.common.data.TbResource;
  20 +import org.thingsboard.server.common.data.TbResourceInfo;
  21 +import org.thingsboard.server.common.data.id.TbResourceId;
  22 +import org.thingsboard.server.common.data.id.TenantId;
  23 +import org.thingsboard.server.common.data.page.PageData;
  24 +import org.thingsboard.server.common.data.page.PageLink;
  25 +
  26 +import java.util.List;
  27 +
  28 +public interface ResourceService {
  29 + TbResource saveResource(TbResource resource);
  30 +
  31 + TbResource getResource(TenantId tenantId, ResourceType resourceType, String resourceId);
  32 +
  33 + TbResource findResourceById(TenantId tenantId, TbResourceId resourceId);
  34 +
  35 + TbResourceInfo findResourceInfoById(TenantId tenantId, TbResourceId resourceId);
  36 +
  37 + PageData<TbResourceInfo> findAllTenantResourcesByTenantId(TenantId tenantId, PageLink pageLink);
  38 +
  39 + PageData<TbResourceInfo> findTenantResourcesByTenantId(TenantId tenantId, PageLink pageLink);
  40 +
  41 + List<TbResource> findTenantResourcesByResourceTypeAndObjectIds(TenantId tenantId, ResourceType lwm2mModel, String[] objectIds);
  42 +
  43 + PageData<TbResource> findTenantResourcesByResourceTypeAndPageLink(TenantId tenantId, ResourceType lwm2mModel, PageLink pageLink);
  44 +
  45 + void deleteResource(TenantId tenantId, TbResourceId resourceId);
  46 +
  47 + void deleteResourcesByTenantId(TenantId tenantId);
  48 +
  49 +
  50 +}
... ...
... ... @@ -43,7 +43,7 @@ public interface RuleChainService {
43 43
44 44 boolean setRootRuleChain(TenantId tenantId, RuleChainId ruleChainId);
45 45
46   - RuleChainMetaData saveRuleChainMetaData(TenantId tenantId, RuleChainMetaData ruleChainMetaData);
  46 + boolean saveRuleChainMetaData(TenantId tenantId, RuleChainMetaData ruleChainMetaData);
47 47
48 48 RuleChainMetaData loadRuleChainMetaData(TenantId tenantId, RuleChainId ruleChainId);
49 49
... ...
... ... @@ -91,10 +91,6 @@
91 91 <groupId>org.apache.commons</groupId>
92 92 <artifactId>commons-lang3</artifactId>
93 93 </dependency>
94   - <dependency>
95   - <groupId>org.eclipse.leshan</groupId>
96   - <artifactId>leshan-core</artifactId>
97   - </dependency>
98 94 </dependencies>
99 95
100 96 <build>
... ...
... ... @@ -19,14 +19,18 @@ import com.fasterxml.jackson.annotation.JsonProperty;
19 19 import org.thingsboard.server.common.data.id.CustomerId;
20 20 import org.thingsboard.server.common.data.id.DashboardId;
21 21 import org.thingsboard.server.common.data.id.TenantId;
  22 +import org.thingsboard.server.common.data.validation.NoXss;
22 23
  24 +import javax.validation.Valid;
23 25 import java.util.HashSet;
24 26 import java.util.Set;
25 27
26 28 public class DashboardInfo extends SearchTextBased<DashboardId> implements HasName, HasTenantId {
27 29
28 30 private TenantId tenantId;
  31 + @NoXss
29 32 private String title;
  33 + @Valid
30 34 private Set<ShortCustomerInfo> assignedCustomers;
31 35
32 36 public DashboardInfo() {
... ...
... ... @@ -19,6 +19,7 @@ import lombok.AllArgsConstructor;
19 19 import lombok.Getter;
20 20 import lombok.Setter;
21 21 import org.thingsboard.server.common.data.id.CustomerId;
  22 +import org.thingsboard.server.common.data.validation.NoXss;
22 23
23 24 /**
24 25 * Created by igor on 2/27/18.
... ... @@ -31,6 +32,7 @@ public class ShortCustomerInfo {
31 32 private CustomerId customerId;
32 33
33 34 @Getter @Setter
  35 + @NoXss
34 36 private String title;
35 37
36 38 @Getter @Setter
... ...
  1 +/**
  2 + * Copyright © 2016-2021 The Thingsboard Authors
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +package org.thingsboard.server.common.data;
  17 +
  18 +public class StringUtils {
  19 +
  20 + public static boolean isEmpty(String source) {
  21 + return source == null || source.isEmpty();
  22 + }
  23 +
  24 + public static boolean isNotEmpty(String source) {
  25 + return source != null && !source.isEmpty();
  26 + }
  27 +}
... ...
... ... @@ -19,6 +19,7 @@ import lombok.Data;
19 19 import lombok.EqualsAndHashCode;
20 20 import lombok.extern.slf4j.Slf4j;
21 21 import org.thingsboard.server.common.data.id.TbResourceId;
  22 +import org.thingsboard.server.common.data.validation.NoXss;
22 23
23 24 @Slf4j
24 25 @Data
... ... @@ -27,6 +28,7 @@ public class TbResource extends TbResourceInfo {
27 28
28 29 private static final long serialVersionUID = 7379609705527272306L;
29 30
  31 + @NoXss
30 32 private String fileName;
31 33
32 34 private String data;
... ...
... ... @@ -20,6 +20,7 @@ import lombok.EqualsAndHashCode;
20 20 import lombok.extern.slf4j.Slf4j;
21 21 import org.thingsboard.server.common.data.id.TbResourceId;
22 22 import org.thingsboard.server.common.data.id.TenantId;
  23 +import org.thingsboard.server.common.data.validation.NoXss;
23 24
24 25 @Slf4j
25 26 @Data
... ... @@ -27,6 +28,7 @@ import org.thingsboard.server.common.data.id.TenantId;
27 28 public class TbResourceInfo extends SearchTextBased<TbResourceId> implements HasTenantId {
28 29
29 30 private TenantId tenantId;
  31 + @NoXss
30 32 private String title;
31 33 private ResourceType resourceType;
32 34 private String resourceKey;
... ...
... ... @@ -19,11 +19,8 @@ import lombok.AllArgsConstructor;
19 19 import lombok.Builder;
20 20 import lombok.Data;
21 21 import org.thingsboard.server.common.data.id.EntityId;
22   -import org.thingsboard.server.common.data.id.TenantId;
23 22 import org.thingsboard.server.common.data.page.TimePageLink;
24 23
25   -import java.util.UUID;
26   -
27 24 /**
28 25 * Created by ashvayka on 11.05.17.
29 26 */
... ... @@ -37,6 +34,5 @@ public class AlarmQuery {
37 34 private AlarmSearchStatus searchStatus;
38 35 private AlarmStatus status;
39 36 private Boolean fetchOriginator;
40   - private UUID idOffset;
41 37
42 38 }
... ...
... ... @@ -25,6 +25,7 @@ import java.util.List;
25 25 public class DeviceProfileData implements Serializable {
26 26
27 27 private DeviceProfileConfiguration configuration;
  28 + @Valid
28 29 private DeviceProfileTransportConfiguration transportConfiguration;
29 30 private DeviceProfileProvisionConfiguration provisionConfiguration;
30 31 @Valid
... ...
... ... @@ -17,11 +17,14 @@ package org.thingsboard.server.common.data.device.profile;
17 17
18 18 import lombok.Data;
19 19 import org.thingsboard.server.common.data.DeviceTransportType;
  20 +import org.thingsboard.server.common.data.validation.NoXss;
20 21
21 22 @Data
22 23 public class MqttDeviceProfileTransportConfiguration implements DeviceProfileTransportConfiguration {
23 24
  25 + @NoXss
24 26 private String deviceTelemetryTopic = MqttTopics.DEVICE_TELEMETRY_TOPIC;
  27 + @NoXss
25 28 private String deviceAttributesTopic = MqttTopics.DEVICE_ATTRIBUTES_TOPIC;
26 29 private TransportPayloadTypeConfiguration transportPayloadTypeConfiguration;
27 30
... ...
... ... @@ -15,7 +15,6 @@
15 15 */
16 16 package org.thingsboard.server.common.data.device.profile;
17 17
18   -import com.fasterxml.jackson.annotation.JsonIgnore;
19 18 import com.github.os72.protobuf.dynamic.DynamicSchema;
20 19 import com.github.os72.protobuf.dynamic.EnumDefinition;
21 20 import com.github.os72.protobuf.dynamic.MessageDefinition;
... ... @@ -46,9 +45,13 @@ public class ProtoTransportPayloadConfiguration implements TransportPayloadTypeC
46 45 public static final Location LOCATION = new Location("", "", -1, -1);
47 46 public static final String ATTRIBUTES_PROTO_SCHEMA = "attributes proto schema";
48 47 public static final String TELEMETRY_PROTO_SCHEMA = "telemetry proto schema";
  48 + public static final String RPC_RESPONSE_PROTO_SCHEMA = "rpc response proto schema";
  49 + public static final String RPC_REQUEST_PROTO_SCHEMA = "rpc request proto schema";
49 50
50 51 private String deviceTelemetryProtoSchema;
51 52 private String deviceAttributesProtoSchema;
  53 + private String deviceRpcRequestProtoSchema;
  54 + private String deviceRpcResponseProtoSchema;
52 55
53 56 @Override
54 57 public TransportPayloadType getTransportPayloadType() {
... ... @@ -63,13 +66,45 @@ public class ProtoTransportPayloadConfiguration implements TransportPayloadTypeC
63 66 return getDescriptor(deviceAttributesProtoSchema, ATTRIBUTES_PROTO_SCHEMA);
64 67 }
65 68
  69 + public Descriptors.Descriptor getRpcResponseDynamicMessageDescriptor(String deviceRpcResponseProtoSchema) {
  70 + return getDescriptor(deviceRpcResponseProtoSchema, RPC_RESPONSE_PROTO_SCHEMA);
  71 + }
  72 +
  73 + public DynamicMessage.Builder getRpcRequestDynamicMessageBuilder(String deviceRpcRequestProtoSchema) {
  74 + return getDynamicMessageBuilder(deviceRpcRequestProtoSchema, RPC_REQUEST_PROTO_SCHEMA);
  75 + }
  76 +
  77 + public String getDeviceRpcResponseProtoSchema() {
  78 + if (!isEmptyStr(deviceRpcResponseProtoSchema)) {
  79 + return deviceRpcResponseProtoSchema;
  80 + } else {
  81 + return "syntax =\"proto3\";\n" +
  82 + "package rpc;\n" +
  83 + "\n" +
  84 + "message RpcResponseMsg {\n" +
  85 + " string payload = 1;\n" +
  86 + "}";
  87 + }
  88 + }
  89 +
  90 + public String getDeviceRpcRequestProtoSchema() {
  91 + if (!isEmptyStr(deviceRpcRequestProtoSchema)) {
  92 + return deviceRpcRequestProtoSchema;
  93 + } else {
  94 + return "syntax =\"proto3\";\n" +
  95 + "package rpc;\n" +
  96 + "\n" +
  97 + "message RpcRequestMsg {\n" +
  98 + " string method = 1;\n" +
  99 + " int32 requestId = 2;\n" +
  100 + " string params = 3;\n" +
  101 + "}";
  102 + }
  103 + }
  104 +
66 105 private Descriptors.Descriptor getDescriptor(String protoSchema, String schemaName) {
67 106 try {
68   - ProtoFileElement protoFileElement = getTransportProtoSchema(protoSchema);
69   - DynamicSchema dynamicSchema = getDynamicSchema(protoFileElement, schemaName);
70   - String lastMsgName = getMessageTypes(protoFileElement.getTypes()).stream()
71   - .map(MessageElement::getName).reduce((previous, last) -> last).get();
72   - DynamicMessage.Builder builder = dynamicSchema.newMessageBuilder(lastMsgName);
  107 + DynamicMessage.Builder builder = getDynamicMessageBuilder(protoSchema, schemaName);
73 108 return builder.getDescriptorForType();
74 109 } catch (Exception e) {
75 110 log.warn("Failed to get Message Descriptor due to {}", e.getMessage());
... ... @@ -77,6 +112,14 @@ public class ProtoTransportPayloadConfiguration implements TransportPayloadTypeC
77 112 }
78 113 }
79 114
  115 + public DynamicMessage.Builder getDynamicMessageBuilder(String protoSchema, String schemaName) {
  116 + ProtoFileElement protoFileElement = getTransportProtoSchema(protoSchema);
  117 + DynamicSchema dynamicSchema = getDynamicSchema(protoFileElement, schemaName);
  118 + String lastMsgName = getMessageTypes(protoFileElement.getTypes()).stream()
  119 + .map(MessageElement::getName).reduce((previous, last) -> last).get();
  120 + return dynamicSchema.newMessageBuilder(lastMsgName);
  121 + }
  122 +
80 123 public DynamicSchema getDynamicSchema(ProtoFileElement protoFileElement, String schemaName) {
81 124 DynamicSchema.Builder schemaBuilder = DynamicSchema.newBuilder();
82 125 schemaBuilder.setName(schemaName);
... ...
  1 +/**
  2 + * Copyright © 2016-2021 The Thingsboard Authors
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +package org.thingsboard.server.common.data.event;
  17 +
  18 +import lombok.Data;
  19 +import org.thingsboard.server.common.data.StringUtils;
  20 +
  21 +@Data
  22 +public abstract class DebugEvent implements EventFilter {
  23 +
  24 + private String msgDirectionType;
  25 + private String server;
  26 + private String dataSearch;
  27 + private String metadataSearch;
  28 + private String entityName;
  29 + private String relationType;
  30 + private String entityId;
  31 + private String msgType;
  32 + private boolean isError;
  33 + private String error;
  34 +
  35 + public void setIsError(boolean isError) {
  36 + this.isError = isError;
  37 + }
  38 +
  39 + @Override
  40 + public boolean hasFilterForJsonBody() {
  41 + return !StringUtils.isEmpty(msgDirectionType) || !StringUtils.isEmpty(server) || !StringUtils.isEmpty(dataSearch) || !StringUtils.isEmpty(metadataSearch)
  42 + || !StringUtils.isEmpty(entityName) || !StringUtils.isEmpty(relationType) || !StringUtils.isEmpty(entityId) || !StringUtils.isEmpty(msgType) || !StringUtils.isEmpty(error) || isError;
  43 + }
  44 +
  45 +}
... ...
  1 +/**
  2 + * Copyright © 2016-2021 The Thingsboard Authors
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +package org.thingsboard.server.common.data.event;
  17 +
  18 +public class DebugRuleChainEventFilter extends DebugEvent {
  19 + @Override
  20 + public EventType getEventType() {
  21 + return EventType.DEBUG_RULE_CHAIN;
  22 + }
  23 +}
... ...
  1 +/**
  2 + * Copyright © 2016-2021 The Thingsboard Authors
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +package org.thingsboard.server.common.data.event;
  17 +
  18 +public class DebugRuleNodeEventFilter extends DebugEvent {
  19 + @Override
  20 + public EventType getEventType() {
  21 + return EventType.DEBUG_RULE_NODE;
  22 + }
  23 +}
... ...
  1 +/**
  2 + * Copyright © 2016-2021 The Thingsboard Authors
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +package org.thingsboard.server.common.data.event;
  17 +
  18 +import lombok.Data;
  19 +import org.thingsboard.server.common.data.StringUtils;
  20 +
  21 +@Data
  22 +public class ErrorEventFilter implements EventFilter {
  23 + private String server;
  24 + private String method;
  25 + private String error;
  26 +
  27 + @Override
  28 + public EventType getEventType() {
  29 + return EventType.ERROR;
  30 + }
  31 +
  32 + @Override
  33 + public boolean hasFilterForJsonBody() {
  34 + return !StringUtils.isEmpty(server) || !StringUtils.isEmpty(method) || !StringUtils.isEmpty(error);
  35 + }
  36 +}
... ...
  1 +/**
  2 + * Copyright © 2016-2021 The Thingsboard Authors
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +package org.thingsboard.server.common.data.event;
  17 +
  18 +import com.fasterxml.jackson.annotation.JsonIgnore;
  19 +import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
  20 +import com.fasterxml.jackson.annotation.JsonSubTypes;
  21 +import com.fasterxml.jackson.annotation.JsonTypeInfo;
  22 +
  23 +@JsonTypeInfo(
  24 + use = JsonTypeInfo.Id.NAME,
  25 + include = JsonTypeInfo.As.PROPERTY,
  26 + property = "eventType")
  27 +@JsonSubTypes({
  28 + @JsonSubTypes.Type(value = DebugRuleNodeEventFilter.class, name = "DEBUG_RULE_NODE"),
  29 + @JsonSubTypes.Type(value = DebugRuleChainEventFilter.class, name = "DEBUG_RULE_CHAIN"),
  30 + @JsonSubTypes.Type(value = ErrorEventFilter.class, name = "ERROR"),
  31 + @JsonSubTypes.Type(value = LifeCycleEventFilter.class, name = "LC_EVENT"),
  32 + @JsonSubTypes.Type(value = StatisticsEventFilter.class, name = "STATS")
  33 +})
  34 +public interface EventFilter {
  35 + @JsonIgnore
  36 + EventType getEventType();
  37 +
  38 + boolean hasFilterForJsonBody();
  39 +
  40 +}
... ...
common/data/src/main/java/org/thingsboard/server/common/data/event/EventType.java renamed from ui-ngx/src/app/shared/components/time/quick-time-interval.component.scss
... ... @@ -13,7 +13,8 @@
13 13 * See the License for the specific language governing permissions and
14 14 * limitations under the License.
15 15 */
  16 +package org.thingsboard.server.common.data.event;
16 17
17   -:host {
18   - min-width: 364px;
19   -}
  18 +public enum EventType {
  19 + ERROR, LC_EVENT, STATS, DEBUG_RULE_NODE, DEBUG_RULE_CHAIN
  20 +}
\ No newline at end of file
... ...
  1 +/**
  2 + * Copyright © 2016-2021 The Thingsboard Authors
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +package org.thingsboard.server.common.data.event;
  17 +
  18 +import lombok.Data;
  19 +import org.thingsboard.server.common.data.StringUtils;
  20 +
  21 +@Data
  22 +public class LifeCycleEventFilter implements EventFilter {
  23 + private String server;
  24 + private String event;
  25 + private String status;
  26 + private String error;
  27 +
  28 + @Override
  29 + public EventType getEventType() {
  30 + return EventType.LC_EVENT;
  31 + }
  32 +
  33 + @Override
  34 + public boolean hasFilterForJsonBody() {
  35 + return !StringUtils.isEmpty(server) || !StringUtils.isEmpty(event) || !StringUtils.isEmpty(status) || !StringUtils.isEmpty(error);
  36 + }
  37 +}
... ...
  1 +/**
  2 + * Copyright © 2016-2021 The Thingsboard Authors
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +package org.thingsboard.server.common.data.event;
  17 +
  18 +import lombok.Data;
  19 +import org.thingsboard.server.common.data.StringUtils;
  20 +
  21 +@Data
  22 +public class StatisticsEventFilter implements EventFilter {
  23 + private String server;
  24 + private Integer messagesProcessed;
  25 + private Integer errorsOccurred;
  26 +
  27 + @Override
  28 + public EventType getEventType() {
  29 + return EventType.STATS;
  30 + }
  31 +
  32 + @Override
  33 + public boolean hasFilterForJsonBody() {
  34 + return !StringUtils.isEmpty(server) || (messagesProcessed != null && messagesProcessed > 0) || (errorsOccurred != null && errorsOccurred > 0);
  35 + }
  36 +}
... ...
... ... @@ -15,10 +15,16 @@
15 15 */
16 16 package org.thingsboard.server.common.data.tenant.profile;
17 17
  18 +import lombok.AllArgsConstructor;
  19 +import lombok.Builder;
18 20 import lombok.Data;
  21 +import lombok.NoArgsConstructor;
19 22 import org.thingsboard.server.common.data.ApiUsageRecordKey;
20 23 import org.thingsboard.server.common.data.TenantProfileType;
21 24
  25 +@AllArgsConstructor
  26 +@NoArgsConstructor
  27 +@Builder
22 28 @Data
23 29 public class DefaultTenantProfileConfiguration implements TenantProfileConfiguration {
24 30
... ...
... ... @@ -20,6 +20,7 @@ import org.thingsboard.server.common.data.BaseData;
20 20 import org.thingsboard.server.common.data.HasTenantId;
21 21 import org.thingsboard.server.common.data.id.TenantId;
22 22 import org.thingsboard.server.common.data.id.WidgetTypeId;
  23 +import org.thingsboard.server.common.data.validation.NoXss;
23 24
24 25 @Data
25 26 public class BaseWidgetType extends BaseData<WidgetTypeId> implements HasTenantId {
... ... @@ -27,8 +28,11 @@ public class BaseWidgetType extends BaseData<WidgetTypeId> implements HasTenantI
27 28 private static final long serialVersionUID = 8388684344603660756L;
28 29
29 30 private TenantId tenantId;
  31 + @NoXss
30 32 private String bundleAlias;
  33 + @NoXss
31 34 private String alias;
  35 + @NoXss
32 36 private String name;
33 37
34 38 public BaseWidgetType() {
... ...
... ... @@ -15,14 +15,15 @@
15 15 */
16 16 package org.thingsboard.server.common.data.widget;
17 17
18   -import com.fasterxml.jackson.databind.JsonNode;
19 18 import lombok.Data;
20 19 import org.thingsboard.server.common.data.id.WidgetTypeId;
  20 +import org.thingsboard.server.common.data.validation.NoXss;
21 21
22 22 @Data
23 23 public class WidgetTypeDetails extends WidgetType {
24 24
25 25 private String image;
  26 + @NoXss
26 27 private String description;
27 28
28 29 public WidgetTypeDetails() {
... ...
... ... @@ -17,12 +17,15 @@ package org.thingsboard.server.common.data.widget;
17 17
18 18 import lombok.Data;
19 19 import org.thingsboard.server.common.data.id.WidgetTypeId;
  20 +import org.thingsboard.server.common.data.validation.NoXss;
20 21
21 22 @Data
22 23 public class WidgetTypeInfo extends BaseWidgetType {
23 24
24 25 private String image;
  26 + @NoXss
25 27 private String description;
  28 + @NoXss
26 29 private String widgetType;
27 30
28 31 public WidgetTypeInfo() {
... ...
... ... @@ -19,6 +19,7 @@ import org.thingsboard.server.common.data.HasTenantId;
19 19 import org.thingsboard.server.common.data.SearchTextBased;
20 20 import org.thingsboard.server.common.data.id.TenantId;
21 21 import org.thingsboard.server.common.data.id.WidgetsBundleId;
  22 +import org.thingsboard.server.common.data.validation.NoXss;
22 23
23 24 import java.util.Arrays;
24 25
... ... @@ -27,9 +28,12 @@ public class WidgetsBundle extends SearchTextBased<WidgetsBundleId> implements H
27 28 private static final long serialVersionUID = -7627368878362410489L;
28 29
29 30 private TenantId tenantId;
  31 + @NoXss
30 32 private String alias;
  33 + @NoXss
31 34 private String title;
32 35 private String image;
  36 + @NoXss
33 37 private String description;
34 38
35 39 public WidgetsBundle() {
... ...
... ... @@ -113,6 +113,10 @@
113 113 <artifactId>protobuf-java</artifactId>
114 114 </dependency>
115 115 <dependency>
  116 + <groupId>com.google.protobuf</groupId>
  117 + <artifactId>protobuf-java-util</artifactId>
  118 + </dependency>
  119 + <dependency>
116 120 <groupId>org.apache.curator</groupId>
117 121 <artifactId>curator-recipes</artifactId>
118 122 </dependency>
... ...
... ... @@ -21,22 +21,28 @@ import org.thingsboard.server.common.msg.queue.TopicPartitionInfo;
21 21 import org.thingsboard.server.queue.TbQueueConsumer;
22 22 import org.thingsboard.server.queue.TbQueueMsg;
23 23
  24 +import javax.annotation.Nonnull;
24 25 import java.io.IOException;
25 26 import java.util.ArrayList;
26 27 import java.util.Collections;
27 28 import java.util.List;
  29 +import java.util.Queue;
28 30 import java.util.Set;
29   -import java.util.concurrent.locks.Lock;
  31 +import java.util.concurrent.ConcurrentLinkedQueue;
  32 +import java.util.concurrent.TimeUnit;
30 33 import java.util.concurrent.locks.ReentrantLock;
31 34 import java.util.stream.Collectors;
32 35
  36 +import static java.util.Collections.emptyList;
  37 +
33 38 @Slf4j
34 39 public abstract class AbstractTbQueueConsumerTemplate<R, T extends TbQueueMsg> implements TbQueueConsumer<T> {
35 40
36 41 private volatile boolean subscribed;
37 42 protected volatile boolean stopped = false;
38 43 protected volatile Set<TopicPartitionInfo> partitions;
39   - protected final Lock consumerLock = new ReentrantLock();
  44 + protected final ReentrantLock consumerLock = new ReentrantLock(); //NonfairSync
  45 + final Queue<Set<TopicPartitionInfo>> subscribeQueue = new ConcurrentLinkedQueue<>();
40 46
41 47 @Getter
42 48 private final String topic;
... ... @@ -47,84 +53,101 @@ public abstract class AbstractTbQueueConsumerTemplate<R, T extends TbQueueMsg> i
47 53
48 54 @Override
49 55 public void subscribe() {
50   - consumerLock.lock();
51   - try {
52   - partitions = Collections.singleton(new TopicPartitionInfo(topic, null, null, true));
53   - subscribed = false;
54   - } finally {
55   - consumerLock.unlock();
  56 + log.info("enqueue topic subscribe {} ", topic);
  57 + if (stopped) {
  58 + log.error("trying subscribe, but consumer stopped for topic {}", topic);
  59 + return;
56 60 }
  61 + subscribeQueue.add(Collections.singleton(new TopicPartitionInfo(topic, null, null, true)));
57 62 }
58 63
59 64 @Override
60 65 public void subscribe(Set<TopicPartitionInfo> partitions) {
  66 + log.info("enqueue topics subscribe {} ", partitions);
  67 + if (stopped) {
  68 + log.error("trying subscribe, but consumer stopped for topic {}", topic);
  69 + return;
  70 + }
  71 + subscribeQueue.add(partitions);
  72 + }
  73 +
  74 + @Override
  75 + public List<T> poll(long durationInMillis) {
  76 + List<R> records;
  77 + long startNanos = System.nanoTime();
  78 + if (stopped) {
  79 + return errorAndReturnEmpty();
  80 + }
  81 + if (!subscribed && partitions == null && subscribeQueue.isEmpty()) {
  82 + return sleepAndReturnEmpty(startNanos, durationInMillis);
  83 + }
  84 +
  85 + if (consumerLock.isLocked()) {
  86 + log.error("poll. consumerLock is locked. will wait with no timeout. it looks like a race conditions or deadlock", new RuntimeException("stacktrace"));
  87 + }
  88 +
61 89 consumerLock.lock();
62 90 try {
63   - this.partitions = partitions;
64   - subscribed = false;
  91 + while (!subscribeQueue.isEmpty()) {
  92 + subscribed = false;
  93 + partitions = subscribeQueue.poll();
  94 + }
  95 + if (!subscribed) {
  96 + List<String> topicNames = partitions.stream().map(TopicPartitionInfo::getFullTopicName).collect(Collectors.toList());
  97 + doSubscribe(topicNames);
  98 + subscribed = true;
  99 + }
  100 + records = partitions.isEmpty() ? emptyList() : doPoll(durationInMillis);
65 101 } finally {
66 102 consumerLock.unlock();
67 103 }
  104 +
  105 + if (records.isEmpty()) { return sleepAndReturnEmpty(startNanos, durationInMillis); }
  106 +
  107 + return decodeRecords(records);
68 108 }
69 109
70   - @Override
71   - public List<T> poll(long durationInMillis) {
72   - if (!subscribed && partitions == null) {
73   - try {
74   - Thread.sleep(durationInMillis);
75   - } catch (InterruptedException e) {
76   - log.debug("Failed to await subscription", e);
77   - }
78   - } else {
79   - long pollStartTs = System.currentTimeMillis();
80   - consumerLock.lock();
  110 + @Nonnull
  111 + List<T> decodeRecords(@Nonnull List<R> records) {
  112 + List<T> result = new ArrayList<>(records.size());
  113 + records.forEach(record -> {
81 114 try {
82   - if (!subscribed) {
83   - List<String> topicNames = partitions.stream().map(TopicPartitionInfo::getFullTopicName).collect(Collectors.toList());
84   - doSubscribe(topicNames);
85   - subscribed = true;
  115 + if (record != null) {
  116 + result.add(decode(record));
86 117 }
  118 + } catch (IOException e) {
  119 + log.error("Failed decode record: [{}]", record);
  120 + throw new RuntimeException("Failed to decode record: ", e);
  121 + }
  122 + });
  123 + return result;
  124 + }
87 125
88   - List<R> records;
89   - if (partitions.isEmpty()) {
90   - records = Collections.emptyList();
91   - } else {
92   - records = doPoll(durationInMillis);
93   - }
94   - if (!records.isEmpty()) {
95   - List<T> result = new ArrayList<>(records.size());
96   - records.forEach(record -> {
97   - try {
98   - if (record != null) {
99   - result.add(decode(record));
100   - }
101   - } catch (IOException e) {
102   - log.error("Failed decode record: [{}]", record);
103   - throw new RuntimeException("Failed to decode record: ", e);
104   - }
105   - });
106   - return result;
107   - } else {
108   - long pollDuration = System.currentTimeMillis() - pollStartTs;
109   - if (pollDuration < durationInMillis) {
110   - try {
111   - Thread.sleep(durationInMillis - pollDuration);
112   - } catch (InterruptedException e) {
113   - if (!stopped) {
114   - log.error("Failed to wait.", e);
115   - }
116   - }
117   - }
  126 + List<T> errorAndReturnEmpty() {
  127 + log.error("poll invoked but consumer stopped for topic" + topic, new RuntimeException("stacktrace"));
  128 + return emptyList();
  129 + }
  130 +
  131 + List<T> sleepAndReturnEmpty(final long startNanos, final long durationInMillis) {
  132 + long durationNanos = TimeUnit.MILLISECONDS.toNanos(durationInMillis);
  133 + long spentNanos = System.nanoTime() - startNanos;
  134 + if (spentNanos < durationNanos) {
  135 + try {
  136 + Thread.sleep(Math.max(TimeUnit.NANOSECONDS.toMillis(durationNanos - spentNanos), 1));
  137 + } catch (InterruptedException e) {
  138 + if (!stopped) {
  139 + log.error("Failed to wait", e);
118 140 }
119   - } finally {
120   - consumerLock.unlock();
121 141 }
122 142 }
123   - return Collections.emptyList();
  143 + return emptyList();
124 144 }
125 145
126 146 @Override
127 147 public void commit() {
  148 + if (consumerLock.isLocked()) {
  149 + log.error("commit. consumerLock is locked. will wait with no timeout. it looks like a race conditions or deadlock", new RuntimeException("stacktrace"));
  150 + }
128 151 consumerLock.lock();
129 152 try {
130 153 doCommit();
... ... @@ -135,6 +158,7 @@ public abstract class AbstractTbQueueConsumerTemplate<R, T extends TbQueueMsg> i
135 158
136 159 @Override
137 160 public void unsubscribe() {
  161 + log.info("unsubscribe topic and stop consumer {}", getTopic());
138 162 stopped = true;
139 163 consumerLock.lock();
140 164 try {
... ...
... ... @@ -128,9 +128,10 @@ public class ZkDiscoveryService implements DiscoveryService, PathChildrenCacheLi
128 128 log.debug("Ignoring application ready event, ZK client is not started, ZK client state [{}]", client.getState());
129 129 return;
130 130 }
  131 + log.info("Going to publish current server...");
131 132 publishCurrentServer();
132   - TransportProtos.ServiceInfo currentService = serviceInfoProvider.getServiceInfo();
133   - partitionService.recalculatePartitions(currentService, getOtherServers());
  133 + log.info("Going to recalculate partitions...");
  134 + recalculatePartitions();
134 135 }
135 136
136 137 public synchronized void publishCurrentServer() {
... ... @@ -285,11 +286,19 @@ public class ZkDiscoveryService implements DiscoveryService, PathChildrenCacheLi
285 286 case CHILD_ADDED:
286 287 case CHILD_UPDATED:
287 288 case CHILD_REMOVED:
288   - TransportProtos.ServiceInfo currentService = serviceInfoProvider.getServiceInfo();
289   - partitionService.recalculatePartitions(currentService, getOtherServers());
  289 + recalculatePartitions();
290 290 break;
291 291 default:
292 292 break;
293 293 }
294 294 }
  295 +
  296 + /**
  297 + * A single entry point to recalculate partitions
  298 + * Synchronized to ensure that other servers info is up to date
  299 + * */
  300 + synchronized void recalculatePartitions() {
  301 + partitionService.recalculatePartitions(serviceInfoProvider.getServiceInfo(), getOtherServers());
  302 + }
  303 +
295 304 }
... ...
... ... @@ -72,8 +72,10 @@ public class TbKafkaConsumerTemplate<T extends TbQueueMsg> extends AbstractTbQue
72 72 protected void doSubscribe(List<String> topicNames) {
73 73 if (!topicNames.isEmpty()) {
74 74 topicNames.forEach(admin::createTopicIfNotExists);
  75 + log.info("subscribe topics {}", topicNames);
75 76 consumer.subscribe(topicNames);
76 77 } else {
  78 + log.info("unsubscribe due to empty topic list");
77 79 consumer.unsubscribe();
78 80 }
79 81 }
... ... @@ -102,6 +104,7 @@ public class TbKafkaConsumerTemplate<T extends TbQueueMsg> extends AbstractTbQue
102 104
103 105 @Override
104 106 protected void doUnsubscribe() {
  107 + log.info("unsubscribe topic and close consumer for topic {}", getTopic());
105 108 if (consumer != null) {
106 109 consumer.unsubscribe();
107 110 consumer.close();
... ...
... ... @@ -17,6 +17,7 @@ package org.thingsboard.server.transport.coap;
17 17
18 18 import com.google.gson.JsonParseException;
19 19 import com.google.protobuf.Descriptors;
  20 +import com.google.protobuf.DynamicMessage;
20 21 import lombok.Data;
21 22 import lombok.extern.slf4j.Slf4j;
22 23 import org.eclipse.californium.core.coap.CoAP;
... ... @@ -261,7 +262,8 @@ public class CoapTransportResource extends AbstractCoapTransportResource {
261 262 TransportProtos.SessionInfoProto currentAttrSession = tokenToSessionIdMap.get(getTokenFromRequest(request));
262 263 if (currentAttrSession == null) {
263 264 attributeSubscriptions.add(sessionId);
264   - registerAsyncCoapSession(exchange, sessionInfo, coapTransportAdaptor, getTokenFromRequest(request));
  265 + registerAsyncCoapSession(exchange, sessionInfo, coapTransportAdaptor,
  266 + transportConfigurationContainer.getRpcRequestDynamicMessageBuilder(), getTokenFromRequest(request));
265 267 transportService.process(sessionInfo,
266 268 TransportProtos.SubscribeToAttributeUpdatesMsg.getDefaultInstance(), new CoapNoOpCallback(exchange));
267 269 }
... ... @@ -281,7 +283,8 @@ public class CoapTransportResource extends AbstractCoapTransportResource {
281 283 TransportProtos.SessionInfoProto currentRpcSession = tokenToSessionIdMap.get(getTokenFromRequest(request));
282 284 if (currentRpcSession == null) {
283 285 rpcSubscriptions.add(sessionId);
284   - registerAsyncCoapSession(exchange, sessionInfo, coapTransportAdaptor, getTokenFromRequest(request));
  286 + registerAsyncCoapSession(exchange, sessionInfo, coapTransportAdaptor,
  287 + transportConfigurationContainer.getRpcRequestDynamicMessageBuilder(), getTokenFromRequest(request));
285 288 transportService.process(sessionInfo,
286 289 TransportProtos.SubscribeToRPCMsg.getDefaultInstance(),
287 290 new CoapNoOpCallback(exchange));
... ... @@ -303,17 +306,19 @@ public class CoapTransportResource extends AbstractCoapTransportResource {
303 306 break;
304 307 case TO_DEVICE_RPC_RESPONSE:
305 308 transportService.process(sessionInfo,
306   - coapTransportAdaptor.convertToDeviceRpcResponse(sessionId, request),
  309 + coapTransportAdaptor.convertToDeviceRpcResponse(sessionId, request, transportConfigurationContainer.getRpcResponseMsgDescriptor()),
307 310 new CoapOkCallback(exchange, CoAP.ResponseCode.CREATED, CoAP.ResponseCode.INTERNAL_SERVER_ERROR));
308 311 break;
309 312 case TO_SERVER_RPC_REQUEST:
310   - transportService.registerSyncSession(sessionInfo, getCoapSessionListener(exchange, coapTransportAdaptor), timeout);
  313 + transportService.registerSyncSession(sessionInfo, getCoapSessionListener(exchange, coapTransportAdaptor,
  314 + transportConfigurationContainer.getRpcRequestDynamicMessageBuilder()), timeout);
311 315 transportService.process(sessionInfo,
312 316 coapTransportAdaptor.convertToServerRpcRequest(sessionId, request),
313 317 new CoapNoOpCallback(exchange));
314 318 break;
315 319 case GET_ATTRIBUTES_REQUEST:
316   - transportService.registerSyncSession(sessionInfo, getCoapSessionListener(exchange, coapTransportAdaptor), timeout);
  320 + transportService.registerSyncSession(sessionInfo, getCoapSessionListener(exchange, coapTransportAdaptor,
  321 + transportConfigurationContainer.getRpcRequestDynamicMessageBuilder()), timeout);
317 322 transportService.process(sessionInfo,
318 323 coapTransportAdaptor.convertToGetAttributes(sessionId, request),
319 324 new CoapNoOpCallback(exchange));
... ... @@ -330,14 +335,14 @@ public class CoapTransportResource extends AbstractCoapTransportResource {
330 335 return tokenToSessionIdMap.remove(token);
331 336 }
332 337
333   - private void registerAsyncCoapSession(CoapExchange exchange, TransportProtos.SessionInfoProto sessionInfo, CoapTransportAdaptor coapTransportAdaptor, String token) {
  338 + private void registerAsyncCoapSession(CoapExchange exchange, TransportProtos.SessionInfoProto sessionInfo, CoapTransportAdaptor coapTransportAdaptor, DynamicMessage.Builder rpcRequestDynamicMessageBuilder, String token) {
334 339 tokenToSessionIdMap.putIfAbsent(token, sessionInfo);
335   - transportService.registerAsyncSession(sessionInfo, getCoapSessionListener(exchange, coapTransportAdaptor));
  340 + transportService.registerAsyncSession(sessionInfo, getCoapSessionListener(exchange, coapTransportAdaptor, rpcRequestDynamicMessageBuilder));
336 341 transportService.process(sessionInfo, getSessionEventMsg(TransportProtos.SessionEvent.OPEN), null);
337 342 }
338 343
339   - private CoapSessionListener getCoapSessionListener(CoapExchange exchange, CoapTransportAdaptor coapTransportAdaptor) {
340   - return new CoapSessionListener(exchange, coapTransportAdaptor);
  344 + private CoapSessionListener getCoapSessionListener(CoapExchange exchange, CoapTransportAdaptor coapTransportAdaptor, DynamicMessage.Builder rpcRequestDynamicMessageBuilder) {
  345 + return new CoapSessionListener(exchange, coapTransportAdaptor, rpcRequestDynamicMessageBuilder);
341 346 }
342 347
343 348 private String getTokenFromRequest(Request request) {
... ... @@ -423,10 +428,12 @@ public class CoapTransportResource extends AbstractCoapTransportResource {
423 428
424 429 private final CoapExchange exchange;
425 430 private final CoapTransportAdaptor coapTransportAdaptor;
  431 + private final DynamicMessage.Builder rpcRequestDynamicMessageBuilder;
426 432
427   - CoapSessionListener(CoapExchange exchange, CoapTransportAdaptor coapTransportAdaptor) {
  433 + CoapSessionListener(CoapExchange exchange, CoapTransportAdaptor coapTransportAdaptor, DynamicMessage.Builder rpcRequestDynamicMessageBuilder) {
428 434 this.exchange = exchange;
429 435 this.coapTransportAdaptor = coapTransportAdaptor;
  436 + this.rpcRequestDynamicMessageBuilder = rpcRequestDynamicMessageBuilder;
430 437 }
431 438
432 439 @Override
... ... @@ -457,7 +464,7 @@ public class CoapTransportResource extends AbstractCoapTransportResource {
457 464 @Override
458 465 public void onToDeviceRpcRequest(TransportProtos.ToDeviceRpcRequestMsg msg) {
459 466 try {
460   - exchange.respond(coapTransportAdaptor.convertToPublish(isConRequest(), msg));
  467 + exchange.respond(coapTransportAdaptor.convertToPublish(isConRequest(), msg, rpcRequestDynamicMessageBuilder));
461 468 } catch (AdaptorException e) {
462 469 log.trace("Failed to reply due to error", e);
463 470 exchange.respond(CoAP.ResponseCode.INTERNAL_SERVER_ERROR);
... ... @@ -545,9 +552,14 @@ public class CoapTransportResource extends AbstractCoapTransportResource {
545 552 (ProtoTransportPayloadConfiguration) transportPayloadTypeConfiguration;
546 553 String deviceTelemetryProtoSchema = protoTransportPayloadConfiguration.getDeviceTelemetryProtoSchema();
547 554 String deviceAttributesProtoSchema = protoTransportPayloadConfiguration.getDeviceAttributesProtoSchema();
  555 + String deviceRpcRequestProtoSchema = protoTransportPayloadConfiguration.getDeviceRpcRequestProtoSchema();
  556 + String deviceRpcResponseProtoSchema = protoTransportPayloadConfiguration.getDeviceRpcResponseProtoSchema();
548 557 return new TransportConfigurationContainer(false,
549 558 protoTransportPayloadConfiguration.getTelemetryDynamicMessageDescriptor(deviceTelemetryProtoSchema),
550   - protoTransportPayloadConfiguration.getAttributesDynamicMessageDescriptor(deviceAttributesProtoSchema));
  559 + protoTransportPayloadConfiguration.getAttributesDynamicMessageDescriptor(deviceAttributesProtoSchema),
  560 + protoTransportPayloadConfiguration.getRpcResponseDynamicMessageDescriptor(deviceRpcResponseProtoSchema),
  561 + protoTransportPayloadConfiguration.getRpcRequestDynamicMessageBuilder(deviceRpcRequestProtoSchema)
  562 + );
551 563 }
552 564 } else {
553 565 throw new AdaptorException("Invalid CoapDeviceTypeConfiguration type: " + coapDeviceTypeConfiguration.getClass().getSimpleName() + "!");
... ... @@ -567,11 +579,15 @@ public class CoapTransportResource extends AbstractCoapTransportResource {
567 579 private boolean jsonPayload;
568 580 private Descriptors.Descriptor telemetryMsgDescriptor;
569 581 private Descriptors.Descriptor attributesMsgDescriptor;
  582 + private Descriptors.Descriptor rpcResponseMsgDescriptor;
  583 + private DynamicMessage.Builder rpcRequestDynamicMessageBuilder;
570 584
571   - public TransportConfigurationContainer(boolean jsonPayload, Descriptors.Descriptor telemetryMsgDescriptor, Descriptors.Descriptor attributesMsgDescriptor) {
  585 + public TransportConfigurationContainer(boolean jsonPayload, Descriptors.Descriptor telemetryMsgDescriptor, Descriptors.Descriptor attributesMsgDescriptor, Descriptors.Descriptor rpcResponseMsgDescriptor, DynamicMessage.Builder rpcRequestDynamicMessageBuilder) {
572 586 this.jsonPayload = jsonPayload;
573 587 this.telemetryMsgDescriptor = telemetryMsgDescriptor;
574 588 this.attributesMsgDescriptor = attributesMsgDescriptor;
  589 + this.rpcResponseMsgDescriptor = rpcResponseMsgDescriptor;
  590 + this.rpcRequestDynamicMessageBuilder = rpcRequestDynamicMessageBuilder;
575 591 }
576 592
577 593 public TransportConfigurationContainer(boolean jsonPayload) {
... ...
... ... @@ -16,6 +16,7 @@
16 16 package org.thingsboard.server.transport.coap.adaptors;
17 17
18 18 import com.google.protobuf.Descriptors;
  19 +import com.google.protobuf.DynamicMessage;
19 20 import org.eclipse.californium.core.coap.Request;
20 21 import org.eclipse.californium.core.coap.Response;
21 22 import org.thingsboard.server.common.transport.adaptor.AdaptorException;
... ... @@ -32,7 +33,7 @@ public interface CoapTransportAdaptor {
32 33
33 34 TransportProtos.GetAttributeRequestMsg convertToGetAttributes(UUID sessionId, Request inbound) throws AdaptorException;
34 35
35   - TransportProtos.ToDeviceRpcResponseMsg convertToDeviceRpcResponse(UUID sessionId, Request inbound) throws AdaptorException;
  36 + TransportProtos.ToDeviceRpcResponseMsg convertToDeviceRpcResponse(UUID sessionId, Request inbound, Descriptors.Descriptor rpcResponseMsgDescriptor) throws AdaptorException;
36 37
37 38 TransportProtos.ToServerRpcRequestMsg convertToServerRpcRequest(UUID sessionId, Request inbound) throws AdaptorException;
38 39
... ... @@ -42,7 +43,7 @@ public interface CoapTransportAdaptor {
42 43
43 44 Response convertToPublish(boolean isConfirmable, TransportProtos.AttributeUpdateNotificationMsg notificationMsg) throws AdaptorException;
44 45
45   - Response convertToPublish(boolean isConfirmable, TransportProtos.ToDeviceRpcRequestMsg rpcRequest) throws AdaptorException;
  46 + Response convertToPublish(boolean isConfirmable, TransportProtos.ToDeviceRpcRequestMsg rpcRequest, DynamicMessage.Builder rpcRequestDynamicMessageBuilder) throws AdaptorException;
46 47
47 48 Response convertToPublish(TransportProtos.ToServerRpcResponseMsg msg) throws AdaptorException;
48 49
... ...
... ... @@ -20,6 +20,7 @@ import com.google.gson.JsonObject;
20 20 import com.google.gson.JsonParser;
21 21 import com.google.gson.JsonSyntaxException;
22 22 import com.google.protobuf.Descriptors;
  23 +import com.google.protobuf.DynamicMessage;
23 24 import lombok.extern.slf4j.Slf4j;
24 25 import org.eclipse.californium.core.coap.CoAP;
25 26 import org.eclipse.californium.core.coap.Request;
... ... @@ -64,7 +65,7 @@ public class JsonCoapAdaptor implements CoapTransportAdaptor {
64 65 }
65 66
66 67 @Override
67   - public TransportProtos.ToDeviceRpcResponseMsg convertToDeviceRpcResponse(UUID sessionId, Request inbound) throws AdaptorException {
  68 + public TransportProtos.ToDeviceRpcResponseMsg convertToDeviceRpcResponse(UUID sessionId, Request inbound, Descriptors.Descriptor rpcResponseMsgDescriptor) throws AdaptorException {
68 69 Optional<Integer> requestId = CoapTransportResource.getRequestId(inbound);
69 70 String payload = validatePayload(sessionId, inbound, false);
70 71 JsonObject response = new JsonParser().parse(payload).getAsJsonObject();
... ... @@ -95,7 +96,7 @@ public class JsonCoapAdaptor implements CoapTransportAdaptor {
95 96 }
96 97
97 98 @Override
98   - public Response convertToPublish(boolean isConfirmable, TransportProtos.ToDeviceRpcRequestMsg msg) throws AdaptorException {
  99 + public Response convertToPublish(boolean isConfirmable, TransportProtos.ToDeviceRpcRequestMsg msg, DynamicMessage.Builder rpcRequestDynamicMessageBuilder) throws AdaptorException {
99 100 return getObserveNotification(isConfirmable, JsonConverter.toJson(msg, true));
100 101 }
101 102
... ...
... ... @@ -15,6 +15,7 @@
15 15 */
16 16 package org.thingsboard.server.transport.coap.adaptors;
17 17
  18 +import com.google.gson.JsonElement;
18 19 import com.google.gson.JsonParser;
19 20 import com.google.protobuf.Descriptors;
20 21 import com.google.protobuf.DynamicMessage;
... ... @@ -63,16 +64,16 @@ public class ProtoCoapAdaptor implements CoapTransportAdaptor {
63 64 }
64 65
65 66 @Override
66   - public TransportProtos.ToDeviceRpcResponseMsg convertToDeviceRpcResponse(UUID sessionId, Request inbound) throws AdaptorException {
  67 + public TransportProtos.ToDeviceRpcResponseMsg convertToDeviceRpcResponse(UUID sessionId, Request inbound, Descriptors.Descriptor rpcResponseMsgDescriptor) throws AdaptorException {
67 68 Optional<Integer> requestId = CoapTransportResource.getRequestId(inbound);
68 69 if (requestId.isEmpty()) {
69 70 throw new AdaptorException("Request id is missing!");
70 71 } else {
71 72 try {
72   - String payload = TransportProtos.ToDeviceRpcResponseMsg.parseFrom(inbound.getPayload()).getPayload();
73   - return TransportProtos.ToDeviceRpcResponseMsg.newBuilder().setRequestId(requestId.get())
74   - .setPayload(payload).build();
75   - } catch (InvalidProtocolBufferException e) {
  73 + JsonElement response = new JsonParser().parse(dynamicMsgToJson(inbound.getPayload(), rpcResponseMsgDescriptor));
  74 + return TransportProtos.ToDeviceRpcResponseMsg.newBuilder().setRequestId(requestId.orElseThrow(() -> new AdaptorException("Request id is missing!")))
  75 + .setPayload(response.toString()).build();
  76 + } catch (Exception e) {
76 77 throw new AdaptorException(e);
77 78 }
78 79 }
... ... @@ -112,8 +113,8 @@ public class ProtoCoapAdaptor implements CoapTransportAdaptor {
112 113 }
113 114
114 115 @Override
115   - public Response convertToPublish(boolean isConfirmable, TransportProtos.ToDeviceRpcRequestMsg msg) throws AdaptorException {
116   - return getObserveNotification(isConfirmable, msg.toByteArray());
  116 + public Response convertToPublish(boolean isConfirmable, TransportProtos.ToDeviceRpcRequestMsg rpcRequest, DynamicMessage.Builder rpcRequestDynamicMessageBuilder) throws AdaptorException {
  117 + return getObserveNotification(isConfirmable, ProtoConverter.convertToRpcRequest(rpcRequest, rpcRequestDynamicMessageBuilder));
117 118 }
118 119
119 120 @Override
... ...
... ... @@ -35,12 +35,11 @@ import org.thingsboard.server.transport.lwm2m.secure.LwM2mCredentialsSecurityInf
35 35 import org.thingsboard.server.transport.lwm2m.secure.ReadResultSecurityStore;
36 36 import org.thingsboard.server.transport.lwm2m.server.LwM2mSessionMsgListener;
37 37 import org.thingsboard.server.transport.lwm2m.server.LwM2mTransportContextServer;
38   -import org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler;
39 38 import org.thingsboard.server.transport.lwm2m.utils.TypeServer;
40 39
41 40 import java.io.IOException;
42 41 import java.security.GeneralSecurityException;
43   -import java.util.Arrays;
  42 +import java.util.Collections;
44 43 import java.util.List;
45 44 import java.util.UUID;
46 45
... ... @@ -70,8 +69,7 @@ public class LwM2MBootstrapSecurityStore implements BootstrapSecurityStore {
70 69
71 70 @Override
72 71 public List<SecurityInfo> getAllByEndpoint(String endPoint) {
73   - String endPointKey = endPoint;
74   - ReadResultSecurityStore store = lwM2MCredentialsSecurityInfoValidator.createAndValidateCredentialsSecurityInfo(endPointKey, TypeServer.BOOTSTRAP);
  72 + ReadResultSecurityStore store = lwM2MCredentialsSecurityInfoValidator.createAndValidateCredentialsSecurityInfo(endPoint, TypeServer.BOOTSTRAP);
75 73 if (store.getBootstrapJsonCredential() != null && store.getSecurityMode() < LwM2MSecurityMode.DEFAULT_MODE.code) {
76 74 /** add value to store from BootstrapJson */
77 75 this.setBootstrapConfigScurityInfo(store);
... ... @@ -87,7 +85,7 @@ public class LwM2MBootstrapSecurityStore implements BootstrapSecurityStore {
87 85 } catch (InvalidConfigurationException e) {
88 86 log.error("", e);
89 87 }
90   - return store.getSecurityInfo() == null ? null : Arrays.asList(store.getSecurityInfo());
  88 + return store.getSecurityInfo() == null ? null : Collections.singletonList(store.getSecurityInfo());
91 89 }
92 90 }
93 91 return null;
... ... @@ -166,13 +164,13 @@ public class LwM2MBootstrapSecurityStore implements BootstrapSecurityStore {
166 164 lwM2MBootstrapConfig.bootstrapServer = new LwM2MServerBootstrap(lwM2MBootstrapConfig.bootstrapServer, profileServerBootstrap);
167 165 lwM2MBootstrapConfig.lwm2mServer = new LwM2MServerBootstrap(lwM2MBootstrapConfig.lwm2mServer, profileLwm2mServer);
168 166 String logMsg = String.format("%s: getParametersBootstrap: %s Access connect client with bootstrap server.", LOG_LW2M_INFO, store.getEndPoint());
169   - context.sendParametersOnThingsboard(context.getTelemetryMsgObject(logMsg), LwM2mTransportHandler.DEVICE_TELEMETRY_TOPIC, sessionInfo);
  167 + context.sendParametersOnThingsboardTelemetry(context.getKvLogyToThingsboard(logMsg), sessionInfo);
170 168 return lwM2MBootstrapConfig;
171 169 } else {
172 170 log.error(" [{}] Different values SecurityMode between of client and profile.", store.getEndPoint());
173 171 log.error("{} getParametersBootstrap: [{}] Different values SecurityMode between of client and profile.", LOG_LW2M_ERROR, store.getEndPoint());
174 172 String logMsg = String.format("%s: getParametersBootstrap: %s Different values SecurityMode between of client and profile.", LOG_LW2M_ERROR, store.getEndPoint());
175   - context.sendParametersOnThingsboard(context.getTelemetryMsgObject(logMsg), LwM2mTransportHandler.DEVICE_TELEMETRY_TOPIC, sessionInfo);
  173 + context.sendParametersOnThingsboardTelemetry(context.getKvLogyToThingsboard(logMsg), sessionInfo);
176 174 return null;
177 175 }
178 176 }
... ...
... ... @@ -23,5 +23,5 @@ public class LwM2MBootstrapServers {
23 23 private Integer lifetime = 300;
24 24 private Integer defaultMinPeriod = 1;
25 25 private boolean notifIfDisabled = true;
26   - private String binding = "U";
  26 + private String binding = "UQ";
27 27 }
... ...
common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mQueuedRequest.java renamed from dao/src/test/java/org/thingsboard/server/dao/service/sql/TbResourceServiceSqlTest.java
... ... @@ -13,11 +13,8 @@
13 13 * See the License for the specific language governing permissions and
14 14 * limitations under the License.
15 15 */
16   -package org.thingsboard.server.dao.service.sql;
  16 +package org.thingsboard.server.transport.lwm2m.server;
17 17
18   -import org.thingsboard.server.dao.service.BaseTbResourceServiceTest;
19   -import org.thingsboard.server.dao.service.DaoSqlTest;
20   -
21   -@DaoSqlTest
22   -public class TbResourceServiceSqlTest extends BaseTbResourceServiceTest {
  18 +public interface LwM2mQueuedRequest {
  19 + void send();
23 20 }
... ...
... ... @@ -26,7 +26,7 @@ import org.eclipse.leshan.server.registration.RegistrationUpdate;
26 26
27 27 import java.util.Collection;
28 28
29   -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.convertToIdVerFromObjectId;
  29 +import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.convertPathFromObjectIdToIdVer;
30 30
31 31 @Slf4j
32 32 public class LwM2mServerListener {
... ... @@ -92,7 +92,7 @@ public class LwM2mServerListener {
92 92 public void onResponse(Observation observation, Registration registration, ObserveResponse response) {
93 93 if (registration != null) {
94 94 try {
95   - service.onObservationResponse(registration, convertToIdVerFromObjectId(observation.getPath().toString(), registration), response);
  95 + service.onObservationResponse(registration, convertPathFromObjectIdToIdVer(observation.getPath().toString(), registration), response);
96 96 } catch (Exception e) {
97 97 log.error("[{}] onResponse", e.toString());
98 98
... ... @@ -107,7 +107,7 @@ public class LwM2mServerListener {
107 107
108 108 @Override
109 109 public void newObservation(Observation observation, Registration registration) {
110   -// log.info("Received newObservation from [{}] endpoint [{}] ", observation.getPath(), registration.getEndpoint());
  110 + log.info("Received newObservation from [{}] endpoint [{}] ", observation.getPath(), registration.getEndpoint());
111 111 }
112 112 };
113 113
... ...
... ... @@ -18,6 +18,7 @@ package org.thingsboard.server.transport.lwm2m.server;
18 18 import io.netty.util.concurrent.Future;
19 19 import io.netty.util.concurrent.GenericFutureListener;
20 20 import lombok.extern.slf4j.Slf4j;
  21 +import org.jetbrains.annotations.NotNull;
21 22 import org.thingsboard.server.common.data.Device;
22 23 import org.thingsboard.server.common.data.DeviceProfile;
23 24 import org.thingsboard.server.common.data.ResourceType;
... ... @@ -74,12 +75,12 @@ public class LwM2mSessionMsgListener implements GenericFutureListener<Future<? s
74 75
75 76 @Override
76 77 public void onToDeviceRpcRequest(ToDeviceRpcRequestMsg toDeviceRequest) {
77   - log.info("[{}] toDeviceRpcRequest", toDeviceRequest);
  78 + this.service.onToDeviceRpcRequest(toDeviceRequest);
78 79 }
79 80
80 81 @Override
81 82 public void onToServerRpcResponse(ToServerRpcResponseMsg toServerResponse) {
82   - log.info("[{}] toServerRpcResponse", toServerResponse);
  83 + this.service.onToServerRpcResponse(toServerResponse);
83 84 }
84 85
85 86 @Override
... ... @@ -87,13 +88,15 @@ public class LwM2mSessionMsgListener implements GenericFutureListener<Future<? s
87 88 log.info("[{}] operationComplete", future);
88 89 }
89 90
90   - public void onResourceUpdate(Optional<TransportProtos.ResourceUpdateMsg> resourceUpdateMsgOpt) {
  91 + @Override
  92 + public void onResourceUpdate(@NotNull Optional<TransportProtos.ResourceUpdateMsg> resourceUpdateMsgOpt) {
91 93 if (ResourceType.LWM2M_MODEL.name().equals(resourceUpdateMsgOpt.get().getResourceType())) {
92 94 this.service.onResourceUpdate(resourceUpdateMsgOpt);
93 95 }
94 96 }
95 97
96   - public void onResourceDelete(Optional<TransportProtos.ResourceDeleteMsg> resourceDeleteMsgOpt) {
  98 + @Override
  99 + public void onResourceDelete(@NotNull Optional<TransportProtos.ResourceDeleteMsg> resourceDeleteMsgOpt) {
97 100 if (ResourceType.LWM2M_MODEL.name().equals(resourceDeleteMsgOpt.get().getResourceType())) {
98 101 this.service.onResourceDelete(resourceDeleteMsgOpt);
99 102 }
... ...
... ... @@ -30,31 +30,33 @@ package org.thingsboard.server.transport.lwm2m.server;
30 30 * limitations under the License.
31 31 */
32 32
33   -import com.google.gson.JsonElement;
34   -import com.google.gson.JsonObject;
35 33 import lombok.Getter;
36 34 import lombok.extern.slf4j.Slf4j;
37 35 import org.eclipse.leshan.core.model.DDFFileParser;
38 36 import org.eclipse.leshan.core.model.DefaultDDFFileValidator;
39 37 import org.eclipse.leshan.core.model.InvalidDDFFileException;
40 38 import org.eclipse.leshan.core.model.ObjectModel;
  39 +import org.eclipse.leshan.core.model.ResourceModel;
  40 +import org.eclipse.leshan.core.node.codec.CodecException;
41 41 import org.springframework.stereotype.Component;
42 42 import org.thingsboard.server.common.transport.TransportContext;
43 43 import org.thingsboard.server.common.transport.TransportResourceCache;
44 44 import org.thingsboard.server.common.transport.TransportService;
45 45 import org.thingsboard.server.common.transport.TransportServiceCallback;
46   -import org.thingsboard.server.common.transport.adaptor.AdaptorException;
47 46 import org.thingsboard.server.common.transport.lwm2m.LwM2MTransportConfigServer;
  47 +import org.thingsboard.server.gen.transport.TransportProtos;
48 48 import org.thingsboard.server.gen.transport.TransportProtos.PostAttributeMsg;
49 49 import org.thingsboard.server.gen.transport.TransportProtos.PostTelemetryMsg;
50 50 import org.thingsboard.server.gen.transport.TransportProtos.SessionInfoProto;
51   -import org.thingsboard.server.gen.transport.TransportProtos.ValidateDeviceCredentialsResponseMsg;
52 51 import org.thingsboard.server.queue.util.TbLwM2mTransportComponent;
53 52 import org.thingsboard.server.transport.lwm2m.server.adaptors.LwM2MJsonAdaptor;
54 53
55 54 import java.io.ByteArrayInputStream;
56 55 import java.io.IOException;
  56 +import java.util.ArrayList;
  57 +import java.util.List;
57 58
  59 +import static org.thingsboard.server.gen.transport.TransportProtos.KeyValueType.BOOLEAN_V;
58 60 import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.LOG_LW2M_TELEMETRY;
59 61
60 62 @Slf4j
... ... @@ -91,7 +93,7 @@ public class LwM2mTransportContextServer extends TransportContext {
91 93 /**
92 94 * send to Thingsboard Attribute || Telemetry
93 95 *
94   - * @param msg - JsonObject: [{name: value}]
  96 + * @param msg - JsonObject: [{name: value}]
95 97 * @return - dummy
96 98 */
97 99 private <T> TransportServiceCallback<Void> getPubAckCallbackSendAttrTelemetry(final T msg) {
... ... @@ -108,33 +110,29 @@ public class LwM2mTransportContextServer extends TransportContext {
108 110 };
109 111 }
110 112
111   - public void sendParametersOnThingsboard(JsonElement msg, String topicName, SessionInfoProto sessionInfo) {
112   - try {
113   - if (topicName.equals(LwM2mTransportHandler.DEVICE_ATTRIBUTES_TOPIC)) {
114   - PostAttributeMsg postAttributeMsg = adaptor.convertToPostAttributes(msg);
115   - TransportServiceCallback call = this.getPubAckCallbackSendAttrTelemetry(postAttributeMsg);
116   - transportService.process(sessionInfo, postAttributeMsg, this.getPubAckCallbackSendAttrTelemetry(call));
117   - } else if (topicName.equals(LwM2mTransportHandler.DEVICE_TELEMETRY_TOPIC)) {
118   - PostTelemetryMsg postTelemetryMsg = adaptor.convertToPostTelemetry(msg);
119   - TransportServiceCallback call = this.getPubAckCallbackSendAttrTelemetry(postTelemetryMsg);
120   - transportService.process(sessionInfo, postTelemetryMsg, this.getPubAckCallbackSendAttrTelemetry(call));
121   - }
122   - } catch (AdaptorException e) {
123   - log.error("[{}] Failed to process publish msg [{}]", topicName, e);
124   - log.info("[{}] Closing current session due to invalid publish", topicName);
125   - }
  113 + public void sendParametersOnThingsboardAttribute(List<TransportProtos.KeyValueProto> result, SessionInfoProto sessionInfo) {
  114 + PostAttributeMsg.Builder request = PostAttributeMsg.newBuilder();
  115 + request.addAllKv(result);
  116 + PostAttributeMsg postAttributeMsg = request.build();
  117 + TransportServiceCallback call = this.getPubAckCallbackSendAttrTelemetry(postAttributeMsg);
  118 + transportService.process(sessionInfo, postAttributeMsg, this.getPubAckCallbackSendAttrTelemetry(call));
126 119 }
127 120
128   - public JsonObject getTelemetryMsgObject(String logMsg) {
129   - JsonObject telemetries = new JsonObject();
130   - telemetries.addProperty(LOG_LW2M_TELEMETRY, logMsg);
131   - return telemetries;
  121 + public void sendParametersOnThingsboardTelemetry(List<TransportProtos.KeyValueProto> result, SessionInfoProto sessionInfo) {
  122 + PostTelemetryMsg.Builder request = PostTelemetryMsg.newBuilder();
  123 + TransportProtos.TsKvListProto.Builder builder = TransportProtos.TsKvListProto.newBuilder();
  124 + builder.setTs(System.currentTimeMillis());
  125 + builder.addAllKv(result);
  126 + request.addTsKvList(builder.build());
  127 + PostTelemetryMsg postTelemetryMsg = request.build();
  128 + TransportServiceCallback call = this.getPubAckCallbackSendAttrTelemetry(postTelemetryMsg);
  129 + transportService.process(sessionInfo, postTelemetryMsg, this.getPubAckCallbackSendAttrTelemetry(call));
132 130 }
133 131
134 132 /**
135 133 * @return - sessionInfo after access connect client
136 134 */
137   - public SessionInfoProto getValidateSessionInfo(ValidateDeviceCredentialsResponseMsg msg, long mostSignificantBits, long leastSignificantBits) {
  135 + public SessionInfoProto getValidateSessionInfo(TransportProtos.ValidateDeviceCredentialsResponseMsg msg, long mostSignificantBits, long leastSignificantBits) {
138 136 return SessionInfoProto.newBuilder()
139 137 .setNodeId(this.getNodeId())
140 138 .setSessionIdMSB(mostSignificantBits)
... ... @@ -159,4 +157,90 @@ public class LwM2mTransportContextServer extends TransportContext {
159 157 return null;
160 158 }
161 159 }
  160 +
  161 + /**
  162 + *
  163 + * @param logMsg - info about Logs
  164 + * @return- KeyValueProto for telemetry (Logs)
  165 + */
  166 + public List <TransportProtos.KeyValueProto> getKvLogyToThingsboard(String logMsg) {
  167 + List <TransportProtos.KeyValueProto> result = new ArrayList<>();
  168 + result.add(TransportProtos.KeyValueProto.newBuilder()
  169 + .setKey(LOG_LW2M_TELEMETRY)
  170 + .setType(TransportProtos.KeyValueType.STRING_V)
  171 + .setStringV(logMsg).build());
  172 + return result;
  173 + }
  174 +
  175 + /**
  176 + * @return - KeyValueProto for attribute/telemetry (change value)
  177 + * @throws CodecException -
  178 + */
  179 +
  180 + public TransportProtos.KeyValueProto getKvAttrTelemetryToThingsboard(ResourceModel.Type resourceType, String resourceName, Object value, boolean isMultiInstances) {
  181 + TransportProtos.KeyValueProto.Builder kvProto = TransportProtos.KeyValueProto.newBuilder().setKey(resourceName);
  182 + if (isMultiInstances) {
  183 + kvProto.setType(TransportProtos.KeyValueType.JSON_V)
  184 + .setJsonV((String) value);
  185 + }
  186 + else {
  187 + switch (resourceType) {
  188 + case BOOLEAN:
  189 + kvProto.setType(BOOLEAN_V).setBoolV((Boolean) value).build();
  190 + break;
  191 + case STRING:
  192 + case TIME:
  193 + case OPAQUE:
  194 + case OBJLNK:
  195 + kvProto.setType(TransportProtos.KeyValueType.STRING_V).setStringV((String) value);
  196 + break;
  197 + case INTEGER:
  198 + kvProto.setType(TransportProtos.KeyValueType.LONG_V).setLongV((Long) value);
  199 + break;
  200 + case FLOAT:
  201 + kvProto.setType(TransportProtos.KeyValueType.DOUBLE_V).setDoubleV((Double) value);
  202 + }
  203 + }
  204 + return kvProto.build();
  205 + }
  206 +
  207 + /**
  208 + *
  209 + * @param currentType -
  210 + * @param resourcePath -
  211 + * @return
  212 + */
  213 + public ResourceModel.Type getResourceModelTypeEqualsKvProtoValueType(ResourceModel.Type currentType, String resourcePath) {
  214 + switch (currentType) {
  215 + case BOOLEAN:
  216 + return ResourceModel.Type.BOOLEAN;
  217 + case STRING:
  218 + case TIME:
  219 + case OPAQUE:
  220 + case OBJLNK:
  221 + return ResourceModel.Type.STRING;
  222 + case INTEGER:
  223 + return ResourceModel.Type.INTEGER;
  224 + case FLOAT:
  225 + return ResourceModel.Type.FLOAT;
  226 + default:
  227 + }
  228 + throw new CodecException("Invalid ResourceModel_Type for resource %s, got %s", resourcePath, currentType);
  229 + }
  230 +
  231 + public Object getValueFromKvProto (TransportProtos.KeyValueProto kv) {
  232 + switch (kv.getType()) {
  233 + case BOOLEAN_V:
  234 + return kv.getBoolV();
  235 + case LONG_V:
  236 + return kv.getLongV();
  237 + case DOUBLE_V:
  238 + return kv.getDoubleV();
  239 + case STRING_V:
  240 + return kv.getStringV();
  241 + case JSON_V:
  242 + return kv.getJsonV();
  243 + }
  244 + return null;
  245 + }
162 246 }
... ...