Commit 0045f00613ac04e27f25ee7c986c7c9b9b17a921
Committed by
GitHub
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); | ... | ... |
application/src/main/java/org/thingsboard/server/service/install/DefaultSystemDataLoaderService.java
... | ... | @@ -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 | +} | ... | ... |
common/data/src/main/java/org/thingsboard/server/common/data/event/DebugRuleChainEventFilter.java
0 → 100644
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 | +} | ... | ... |
common/data/src/main/java/org/thingsboard/server/common/data/event/DebugRuleNodeEventFilter.java
0 → 100644
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 | ... | ... |
common/data/src/main/java/org/thingsboard/server/common/data/event/LifeCycleEventFilter.java
0 → 100644
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 | +} | ... | ... |
common/data/src/main/java/org/thingsboard/server/common/data/event/StatisticsEventFilter.java
0 → 100644
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(); | ... | ... |
common/transport/coap/src/main/java/org/thingsboard/server/transport/coap/CoapTransportResource.java
... | ... | @@ -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 | } | ... | ... |
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 | } | ... | ... |