Commit 201476f912e317ce7d7c466c0bffec72189611bb
Committed by
Andrew Shvayka
1 parent
3420eeb9
lwm2m: add objectKeyId to back and front profile
Showing
26 changed files
with
458 additions
and
140 deletions
@@ -27,11 +27,14 @@ import org.thingsboard.server.common.data.Resource; | @@ -27,11 +27,14 @@ import org.thingsboard.server.common.data.Resource; | ||
27 | import org.thingsboard.server.common.data.ResourceType; | 27 | import org.thingsboard.server.common.data.ResourceType; |
28 | import org.thingsboard.server.common.data.exception.ThingsboardException; | 28 | import org.thingsboard.server.common.data.exception.ThingsboardException; |
29 | import org.thingsboard.server.common.data.id.TenantId; | 29 | import org.thingsboard.server.common.data.id.TenantId; |
30 | +import org.thingsboard.server.common.data.lwm2m.LwM2mObject; | ||
30 | import org.thingsboard.server.common.data.page.PageData; | 31 | import org.thingsboard.server.common.data.page.PageData; |
31 | import org.thingsboard.server.common.data.page.PageLink; | 32 | import org.thingsboard.server.common.data.page.PageLink; |
32 | import org.thingsboard.server.dao.resource.ResourceService; | 33 | import org.thingsboard.server.dao.resource.ResourceService; |
33 | import org.thingsboard.server.queue.util.TbCoreComponent; | 34 | import org.thingsboard.server.queue.util.TbCoreComponent; |
34 | 35 | ||
36 | +import java.util.List; | ||
37 | + | ||
35 | @Slf4j | 38 | @Slf4j |
36 | @RestController | 39 | @RestController |
37 | @TbCoreComponent | 40 | @TbCoreComponent |
@@ -59,21 +62,55 @@ public class ResourceController extends BaseController { | @@ -59,21 +62,55 @@ public class ResourceController extends BaseController { | ||
59 | } | 62 | } |
60 | 63 | ||
61 | @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')") | 64 | @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')") |
62 | - @RequestMapping(value = "/resource", method = RequestMethod.GET) | 65 | + @RequestMapping(value = "/resource/page", method = RequestMethod.GET) |
63 | @ResponseBody | 66 | @ResponseBody |
64 | public PageData<Resource> getResources(@RequestParam(required = false) boolean system, | 67 | public PageData<Resource> getResources(@RequestParam(required = false) boolean system, |
65 | @RequestParam int pageSize, | 68 | @RequestParam int pageSize, |
66 | @RequestParam int page, | 69 | @RequestParam int page, |
70 | + @RequestParam(required = false) String textSearch, | ||
67 | @RequestParam(required = false) String sortProperty, | 71 | @RequestParam(required = false) String sortProperty, |
68 | @RequestParam(required = false) String sortOrder) throws ThingsboardException { | 72 | @RequestParam(required = false) String sortOrder) throws ThingsboardException { |
69 | try { | 73 | try { |
70 | - PageLink pageLink = createPageLink(pageSize, page, null, sortProperty, sortOrder); | 74 | +// int[] objectIds; |
75 | +// ResourceType resourceType | ||
76 | + PageLink pageLink = createPageLink(pageSize, page, textSearch, sortProperty, sortOrder); | ||
71 | return checkNotNull(resourceService.findResourcesByTenantId(system ? TenantId.SYS_TENANT_ID : getTenantId(), pageLink)); | 77 | return checkNotNull(resourceService.findResourcesByTenantId(system ? TenantId.SYS_TENANT_ID : getTenantId(), pageLink)); |
72 | } catch (Exception e) { | 78 | } catch (Exception e) { |
73 | throw handleException(e); | 79 | throw handleException(e); |
74 | } | 80 | } |
75 | } | 81 | } |
76 | 82 | ||
83 | + @PreAuthorize("hasAnyAuthority('TENANT_ADMIN')") | ||
84 | + @RequestMapping(value = "/resource/lwm2m/page", method = RequestMethod.GET) | ||
85 | + @ResponseBody | ||
86 | + public List<LwM2mObject> getLwm2mListObjectsPage(@RequestParam int pageSize, | ||
87 | + @RequestParam int page, | ||
88 | + @RequestParam(required = false) String textSearch, | ||
89 | + @RequestParam(required = false) String sortProperty, | ||
90 | + @RequestParam(required = false) String sortOrder) throws ThingsboardException { | ||
91 | + try { | ||
92 | + PageLink pageLink = new PageLink(pageSize, page, textSearch); | ||
93 | + return checkNotNull(resourceService.findLwM2mObjectPage(getTenantId(), sortProperty, sortOrder, pageLink)); | ||
94 | + } catch (Exception e) { | ||
95 | + throw handleException(e); | ||
96 | + } | ||
97 | + } | ||
98 | + | ||
99 | + @PreAuthorize("hasAnyAuthority('TENANT_ADMIN')") | ||
100 | + @RequestMapping(value = "/resource/lwm2m", method = RequestMethod.GET) | ||
101 | + @ResponseBody | ||
102 | + public List<LwM2mObject> getLwm2mListObjects(@RequestParam String sortOrder, | ||
103 | + @RequestParam String sortProperty, | ||
104 | + @RequestParam(required = false) String[] objectIds, | ||
105 | + @RequestParam(required = false) String searchText) | ||
106 | + throws ThingsboardException { | ||
107 | + try { | ||
108 | + return checkNotNull(resourceService.findLwM2mObject(getTenantId(), sortOrder, sortProperty, objectIds, searchText)); | ||
109 | + } catch (Exception e) { | ||
110 | + throw handleException(e); | ||
111 | + } | ||
112 | + } | ||
113 | + | ||
77 | @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')") | 114 | @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')") |
78 | @RequestMapping(value = "/resource/{resourceType}/{resourceId}", method = RequestMethod.DELETE) | 115 | @RequestMapping(value = "/resource/{resourceType}/{resourceId}", method = RequestMethod.DELETE) |
79 | @ResponseBody | 116 | @ResponseBody |
@@ -37,6 +37,7 @@ import org.thingsboard.server.common.data.rule.RuleChainMetaData; | @@ -37,6 +37,7 @@ import org.thingsboard.server.common.data.rule.RuleChainMetaData; | ||
37 | import org.thingsboard.server.common.data.widget.WidgetType; | 37 | import org.thingsboard.server.common.data.widget.WidgetType; |
38 | import org.thingsboard.server.common.data.widget.WidgetsBundle; | 38 | import org.thingsboard.server.common.data.widget.WidgetsBundle; |
39 | import org.thingsboard.server.dao.dashboard.DashboardService; | 39 | import org.thingsboard.server.dao.dashboard.DashboardService; |
40 | +import org.thingsboard.server.dao.exception.DataValidationException; | ||
40 | import org.thingsboard.server.dao.oauth2.OAuth2ConfigTemplateService; | 41 | import org.thingsboard.server.dao.oauth2.OAuth2ConfigTemplateService; |
41 | import org.thingsboard.server.dao.resource.ResourceService; | 42 | import org.thingsboard.server.dao.resource.ResourceService; |
42 | import org.thingsboard.server.dao.rule.RuleChainService; | 43 | import org.thingsboard.server.dao.rule.RuleChainService; |
@@ -202,7 +203,6 @@ public class InstallScripts { | @@ -202,7 +203,6 @@ public class InstallScripts { | ||
202 | } | 203 | } |
203 | 204 | ||
204 | public void loadSystemLwm2mResources() throws Exception { | 205 | public void loadSystemLwm2mResources() throws Exception { |
205 | -// Path modelsDir = Paths.get("/home/nick/Igor_project/thingsboard_ce_3_2_docker/thingsboard/common/transport/lwm2m/src/main/resources/models/"); | ||
206 | Path modelsDir = Paths.get(getDataDir(), MODELS_DIR); | 206 | Path modelsDir = Paths.get(getDataDir(), MODELS_DIR); |
207 | if (Files.isDirectory(modelsDir)) { | 207 | if (Files.isDirectory(modelsDir)) { |
208 | try (DirectoryStream<Path> dirStream = Files.newDirectoryStream(modelsDir, path -> path.toString().endsWith(XML_EXT))) { | 208 | try (DirectoryStream<Path> dirStream = Files.newDirectoryStream(modelsDir, path -> path.toString().endsWith(XML_EXT))) { |
@@ -210,18 +210,16 @@ public class InstallScripts { | @@ -210,18 +210,16 @@ public class InstallScripts { | ||
210 | path -> { | 210 | path -> { |
211 | try { | 211 | try { |
212 | byte[] fileBytes = Files.readAllBytes(path); | 212 | byte[] fileBytes = Files.readAllBytes(path); |
213 | - String key = getObjectModelLwm2mValid(fileBytes, path.getFileName().toString(), new DefaultDDFFileValidator()); | ||
214 | - if (key != null) { | ||
215 | - Resource resource = new Resource(); | ||
216 | - resource.setTenantId(TenantId.SYS_TENANT_ID); | ||
217 | - resource.setResourceType(ResourceType.LWM2M_MODEL); | ||
218 | - resource.setResourceId(key); | ||
219 | - resource.setValue(Base64.getEncoder().encodeToString(fileBytes)); | ||
220 | - resourceService.saveResource(resource); | ||
221 | - } | 213 | + String source = new String(fileBytes); |
214 | + Resource resource = new Resource(); | ||
215 | + resource.setTenantId(TenantId.SYS_TENANT_ID); | ||
216 | + resource.setResourceType(ResourceType.LWM2M_MODEL); | ||
217 | + resource.setResourceId(getValueByTeg(source, "ObjectID") + "_" + getValueByTeg(source, "ObjectVersion")); | ||
218 | + resource.setTextSearch(resource.getResourceId() + ":" + getValueByTeg(source, "Name")); | ||
219 | + resource.setValue(Base64.getEncoder().encodeToString(fileBytes)); | ||
220 | + resourceService.saveResource(resource); | ||
222 | } catch (Exception e) { | 221 | } catch (Exception e) { |
223 | - log.error("Unable to load lwm2m model [{}]", path.toString()); | ||
224 | - throw new RuntimeException("Unable to load lwm2m model", e); | 222 | + throw new DataValidationException(String.format("Could not parse the XML of objectModel with name %s", path.toString())); |
225 | } | 223 | } |
226 | } | 224 | } |
227 | ); | 225 | ); |
@@ -234,6 +232,7 @@ public class InstallScripts { | @@ -234,6 +232,7 @@ public class InstallScripts { | ||
234 | resource.setTenantId(TenantId.SYS_TENANT_ID); | 232 | resource.setTenantId(TenantId.SYS_TENANT_ID); |
235 | resource.setResourceType(ResourceType.JKS); | 233 | resource.setResourceType(ResourceType.JKS); |
236 | resource.setResourceId(jksPath.getFileName().toString()); | 234 | resource.setResourceId(jksPath.getFileName().toString()); |
235 | + resource.setTextSearch(jksPath.getFileName().toString()); | ||
237 | resource.setValue(Base64.getEncoder().encodeToString(Files.readAllBytes(jksPath))); | 236 | resource.setValue(Base64.getEncoder().encodeToString(Files.readAllBytes(jksPath))); |
238 | resourceService.saveResource(resource); | 237 | resourceService.saveResource(resource); |
239 | } catch (Exception e) { | 238 | } catch (Exception e) { |
@@ -242,11 +241,18 @@ public class InstallScripts { | @@ -242,11 +241,18 @@ public class InstallScripts { | ||
242 | } | 241 | } |
243 | } | 242 | } |
244 | 243 | ||
245 | - private String getObjectModelLwm2mValid(byte[] xmlByte, String streamName, DefaultDDFFileValidator ddfValidator) { | 244 | + private String getValueByTeg(String source, String tagHtml) { |
245 | + int lenTag = ("<" + tagHtml + ">").length(); | ||
246 | + int indStart = source.indexOf("<" + tagHtml + ">"); | ||
247 | + int indEnd = source.indexOf("</" + tagHtml + ">"); | ||
248 | + return (indStart > 0 && indEnd > 0) ? source.substring(indStart + lenTag, indEnd) : null; | ||
249 | + | ||
250 | + } | ||
251 | + | ||
252 | + private ObjectModel getObjectModelLwm2mValid(byte[] xmlByte, String streamName, DefaultDDFFileValidator ddfValidator) { | ||
246 | try { | 253 | try { |
247 | DDFFileParser ddfFileParser = new DDFFileParser(ddfValidator); | 254 | DDFFileParser ddfFileParser = new DDFFileParser(ddfValidator); |
248 | - ObjectModel objectModel = ddfFileParser.parseEx(new ByteArrayInputStream(xmlByte), streamName).get(0); | ||
249 | - return objectModel.id + "##" + objectModel.getVersion(); | 255 | + return ddfFileParser.parseEx(new ByteArrayInputStream(xmlByte), streamName).get(0); |
250 | } catch (IOException | InvalidDDFFileException e) { | 256 | } catch (IOException | InvalidDDFFileException e) { |
251 | log.error("Could not parse the XML file [{}]", streamName, e); | 257 | log.error("Could not parse the XML file [{}]", streamName, e); |
252 | return null; | 258 | return null; |
@@ -442,6 +442,7 @@ public class SqlDatabaseUpgradeService implements DatabaseEntitiesUpgradeService | @@ -442,6 +442,7 @@ public class SqlDatabaseUpgradeService implements DatabaseEntitiesUpgradeService | ||
442 | " tenant_id uuid NOT NULL," + | 442 | " tenant_id uuid NOT NULL," + |
443 | " resource_type varchar(32) NOT NULL," + | 443 | " resource_type varchar(32) NOT NULL," + |
444 | " resource_id varchar(255) NOT NULL," + | 444 | " resource_id varchar(255) NOT NULL," + |
445 | + " text_search varchar(255)," + | ||
445 | " resource_value varchar," + | 446 | " resource_value varchar," + |
446 | " CONSTRAINT resource_unq_key UNIQUE (tenant_id, resource_type, resource_id)" + | 447 | " CONSTRAINT resource_unq_key UNIQUE (tenant_id, resource_type, resource_id)" + |
447 | " );"); | 448 | " );"); |
@@ -18,6 +18,7 @@ package org.thingsboard.server.dao.resource; | @@ -18,6 +18,7 @@ package org.thingsboard.server.dao.resource; | ||
18 | import org.thingsboard.server.common.data.Resource; | 18 | import org.thingsboard.server.common.data.Resource; |
19 | import org.thingsboard.server.common.data.ResourceType; | 19 | import org.thingsboard.server.common.data.ResourceType; |
20 | import org.thingsboard.server.common.data.id.TenantId; | 20 | import org.thingsboard.server.common.data.id.TenantId; |
21 | +import org.thingsboard.server.common.data.lwm2m.LwM2mObject; | ||
21 | import org.thingsboard.server.common.data.page.PageData; | 22 | import org.thingsboard.server.common.data.page.PageData; |
22 | import org.thingsboard.server.common.data.page.PageLink; | 23 | import org.thingsboard.server.common.data.page.PageLink; |
23 | 24 | ||
@@ -31,7 +32,18 @@ public interface ResourceService { | @@ -31,7 +32,18 @@ public interface ResourceService { | ||
31 | 32 | ||
32 | PageData<Resource> findResourcesByTenantId(TenantId tenantId, PageLink pageLink); | 33 | PageData<Resource> findResourcesByTenantId(TenantId tenantId, PageLink pageLink); |
33 | 34 | ||
34 | - List<Resource> findResourcesByTenantIdResourceType(TenantId tenantId, ResourceType resourceType); | 35 | + List<LwM2mObject> findLwM2mObject(TenantId tenantId, |
36 | + String sortOrder, | ||
37 | + String sortProperty, | ||
38 | + String[] objectIds, | ||
39 | + String searchText); | ||
40 | + | ||
41 | + List<LwM2mObject> findLwM2mObjectPage(TenantId tenantId, | ||
42 | + String sortProperty, | ||
43 | + String sortOrder, | ||
44 | + PageLink pageLink); | ||
45 | + | ||
46 | + List<Resource> findAllByTenantIdAndResourceType(TenantId tenantId, ResourceType resourceType); | ||
35 | 47 | ||
36 | void deleteResource(TenantId tenantId, ResourceType resourceType, String resourceId); | 48 | void deleteResource(TenantId tenantId, ResourceType resourceType, String resourceId); |
37 | 49 |
@@ -79,6 +79,10 @@ | @@ -79,6 +79,10 @@ | ||
79 | <groupId>org.thingsboard</groupId> | 79 | <groupId>org.thingsboard</groupId> |
80 | <artifactId>protobuf-dynamic</artifactId> | 80 | <artifactId>protobuf-dynamic</artifactId> |
81 | </dependency> | 81 | </dependency> |
82 | + <dependency> | ||
83 | + <groupId>org.eclipse.leshan</groupId> | ||
84 | + <artifactId>leshan-core</artifactId> | ||
85 | + </dependency> | ||
82 | </dependencies> | 86 | </dependencies> |
83 | 87 | ||
84 | <build> | 88 | <build> |
@@ -16,10 +16,24 @@ | @@ -16,10 +16,24 @@ | ||
16 | package org.thingsboard.server.common.data; | 16 | package org.thingsboard.server.common.data; |
17 | 17 | ||
18 | import lombok.Data; | 18 | import lombok.Data; |
19 | +import lombok.extern.slf4j.Slf4j; | ||
20 | +import org.eclipse.leshan.core.model.DDFFileParser; | ||
21 | +import org.eclipse.leshan.core.model.DefaultDDFFileValidator; | ||
22 | +import org.eclipse.leshan.core.model.InvalidDDFFileException; | ||
23 | +import org.eclipse.leshan.core.model.ObjectModel; | ||
19 | import org.thingsboard.server.common.data.id.TenantId; | 24 | import org.thingsboard.server.common.data.id.TenantId; |
25 | +import org.thingsboard.server.common.data.lwm2m.LwM2mInstance; | ||
26 | +import org.thingsboard.server.common.data.lwm2m.LwM2mObject; | ||
27 | +import org.thingsboard.server.common.data.lwm2m.LwM2mResource; | ||
20 | 28 | ||
29 | +import java.io.ByteArrayInputStream; | ||
30 | +import java.io.IOException; | ||
21 | import java.io.Serializable; | 31 | import java.io.Serializable; |
32 | +import java.util.ArrayList; | ||
33 | +import java.util.Base64; | ||
34 | +import java.util.List; | ||
22 | 35 | ||
36 | +@Slf4j | ||
23 | @Data | 37 | @Data |
24 | public class Resource implements HasTenantId, Serializable { | 38 | public class Resource implements HasTenantId, Serializable { |
25 | 39 | ||
@@ -28,14 +42,51 @@ public class Resource implements HasTenantId, Serializable { | @@ -28,14 +42,51 @@ public class Resource implements HasTenantId, Serializable { | ||
28 | private TenantId tenantId; | 42 | private TenantId tenantId; |
29 | private ResourceType resourceType; | 43 | private ResourceType resourceType; |
30 | private String resourceId; | 44 | private String resourceId; |
45 | + private String textSearch; | ||
31 | private String value; | 46 | private String value; |
32 | 47 | ||
33 | @Override | 48 | @Override |
34 | public String toString() { | 49 | public String toString() { |
35 | - return "Resource{" + | ||
36 | - "tenantId=" + tenantId + | ||
37 | - ", resourceType=" + resourceType + | ||
38 | - ", resourceId='" + resourceId + '\'' + | ||
39 | - '}'; | 50 | + final StringBuilder res = new StringBuilder("Resource{"); |
51 | + res.append("tenantId=").append(tenantId); | ||
52 | + res.append(", resourceType='").append(resourceType).append('\''); | ||
53 | + res.append(", resourceId='").append(resourceId).append('\''); | ||
54 | + res.append(", textSearch='").append(textSearch).append('\''); | ||
55 | + res.append('}'); | ||
56 | + return res.toString(); | ||
57 | + } | ||
58 | + | ||
59 | + public LwM2mObject toLwM2mObject () { | ||
60 | + try { | ||
61 | + DDFFileParser ddfFileParser = new DDFFileParser(new DefaultDDFFileValidator()); | ||
62 | + List<ObjectModel> objectModels = ddfFileParser.parseEx(new ByteArrayInputStream(Base64.getDecoder().decode(this.value)), this.textSearch); | ||
63 | + if (objectModels.size() == 0) { | ||
64 | + return null; | ||
65 | + } | ||
66 | + else { | ||
67 | + ObjectModel obj = objectModels.get(0); | ||
68 | + LwM2mObject lwM2mObject = new LwM2mObject(); | ||
69 | + lwM2mObject.setId(obj.id); | ||
70 | + lwM2mObject.setKeyId(this.resourceId); | ||
71 | + lwM2mObject.setName(obj.name); | ||
72 | + lwM2mObject.setMultiple(obj.multiple); | ||
73 | + lwM2mObject.setMandatory(obj.mandatory); | ||
74 | + LwM2mInstance instance = new LwM2mInstance(); | ||
75 | + instance.setId(0); | ||
76 | + List<LwM2mResource> resources = new ArrayList<>(); | ||
77 | + obj.resources.forEach((k, v) -> { | ||
78 | + if (!v.operations.isExecutable()) { | ||
79 | + LwM2mResource resource = new LwM2mResource(k, v.name, false, false, false); | ||
80 | + resources.add(resource); | ||
81 | + } | ||
82 | + }); | ||
83 | + instance.setResources(resources.stream().toArray(LwM2mResource[]::new)); | ||
84 | + lwM2mObject.setInstances(new LwM2mInstance[]{instance}); | ||
85 | + return lwM2mObject; | ||
86 | + } | ||
87 | + } catch (IOException | InvalidDDFFileException e) { | ||
88 | + log.error("Could not parse the XML of objectModel with name [{}]", this.textSearch, e); | ||
89 | + return null; | ||
90 | + } | ||
40 | } | 91 | } |
41 | } | 92 | } |
@@ -20,6 +20,7 @@ import lombok.Data; | @@ -20,6 +20,7 @@ import lombok.Data; | ||
20 | @Data | 20 | @Data |
21 | public class LwM2mObject { | 21 | public class LwM2mObject { |
22 | int id; | 22 | int id; |
23 | + String keyId; | ||
23 | String name; | 24 | String name; |
24 | boolean multiple; | 25 | boolean multiple; |
25 | boolean mandatory; | 26 | boolean mandatory; |
@@ -214,6 +214,10 @@ | @@ -214,6 +214,10 @@ | ||
214 | <groupId>org.elasticsearch.client</groupId> | 214 | <groupId>org.elasticsearch.client</groupId> |
215 | <artifactId>rest</artifactId> | 215 | <artifactId>rest</artifactId> |
216 | </dependency> | 216 | </dependency> |
217 | + <dependency> | ||
218 | + <groupId>org.eclipse.leshan</groupId> | ||
219 | + <artifactId>leshan-core</artifactId> | ||
220 | + </dependency> | ||
217 | </dependencies> | 221 | </dependencies> |
218 | <build> | 222 | <build> |
219 | <plugins> | 223 | <plugins> |
@@ -460,8 +460,10 @@ public class ModelConstants { | @@ -460,8 +460,10 @@ public class ModelConstants { | ||
460 | public static final String RESOURCE_TENANT_ID_COLUMN = TENANT_ID_COLUMN; | 460 | public static final String RESOURCE_TENANT_ID_COLUMN = TENANT_ID_COLUMN; |
461 | public static final String RESOURCE_TYPE_COLUMN = "resource_type"; | 461 | public static final String RESOURCE_TYPE_COLUMN = "resource_type"; |
462 | public static final String RESOURCE_ID_COLUMN = "resource_id"; | 462 | public static final String RESOURCE_ID_COLUMN = "resource_id"; |
463 | + public static final String TEXT_SEARCH_COLUMN = "text_search"; | ||
463 | public static final String RESOURCE_VALUE_COLUMN = "resource_value"; | 464 | public static final String RESOURCE_VALUE_COLUMN = "resource_value"; |
464 | 465 | ||
466 | + | ||
465 | /** | 467 | /** |
466 | * Cassandra attributes and timeseries constants. | 468 | * Cassandra attributes and timeseries constants. |
467 | */ | 469 | */ |
@@ -33,6 +33,7 @@ import static org.thingsboard.server.dao.model.ModelConstants.RESOURCE_TABLE_NAM | @@ -33,6 +33,7 @@ import static org.thingsboard.server.dao.model.ModelConstants.RESOURCE_TABLE_NAM | ||
33 | import static org.thingsboard.server.dao.model.ModelConstants.RESOURCE_TENANT_ID_COLUMN; | 33 | import static org.thingsboard.server.dao.model.ModelConstants.RESOURCE_TENANT_ID_COLUMN; |
34 | import static org.thingsboard.server.dao.model.ModelConstants.RESOURCE_TYPE_COLUMN; | 34 | import static org.thingsboard.server.dao.model.ModelConstants.RESOURCE_TYPE_COLUMN; |
35 | import static org.thingsboard.server.dao.model.ModelConstants.RESOURCE_VALUE_COLUMN; | 35 | import static org.thingsboard.server.dao.model.ModelConstants.RESOURCE_VALUE_COLUMN; |
36 | +import static org.thingsboard.server.dao.model.ModelConstants.TEXT_SEARCH_COLUMN; | ||
36 | 37 | ||
37 | @Data | 38 | @Data |
38 | @Entity | 39 | @Entity |
@@ -52,6 +53,9 @@ public class ResourceEntity implements ToData<Resource> { | @@ -52,6 +53,9 @@ public class ResourceEntity implements ToData<Resource> { | ||
52 | @Column(name = RESOURCE_ID_COLUMN) | 53 | @Column(name = RESOURCE_ID_COLUMN) |
53 | private String resourceId; | 54 | private String resourceId; |
54 | 55 | ||
56 | + @Column(name = TEXT_SEARCH_COLUMN) | ||
57 | + private String textSearch; | ||
58 | + | ||
55 | @Column(name = RESOURCE_VALUE_COLUMN) | 59 | @Column(name = RESOURCE_VALUE_COLUMN) |
56 | private String value; | 60 | private String value; |
57 | 61 | ||
@@ -62,6 +66,7 @@ public class ResourceEntity implements ToData<Resource> { | @@ -62,6 +66,7 @@ public class ResourceEntity implements ToData<Resource> { | ||
62 | this.tenantId = resource.getTenantId().getId(); | 66 | this.tenantId = resource.getTenantId().getId(); |
63 | this.resourceType = resource.getResourceType().name(); | 67 | this.resourceType = resource.getResourceType().name(); |
64 | this.resourceId = resource.getResourceId(); | 68 | this.resourceId = resource.getResourceId(); |
69 | + this.textSearch = resource.getTextSearch(); | ||
65 | this.value = resource.getValue(); | 70 | this.value = resource.getValue(); |
66 | } | 71 | } |
67 | 72 | ||
@@ -71,6 +76,7 @@ public class ResourceEntity implements ToData<Resource> { | @@ -71,6 +76,7 @@ public class ResourceEntity implements ToData<Resource> { | ||
71 | resource.setTenantId(new TenantId(tenantId)); | 76 | resource.setTenantId(new TenantId(tenantId)); |
72 | resource.setResourceType(ResourceType.valueOf(resourceType)); | 77 | resource.setResourceType(ResourceType.valueOf(resourceType)); |
73 | resource.setResourceId(resourceId); | 78 | resource.setResourceId(resourceId); |
79 | + resource.setTextSearch(textSearch); | ||
74 | resource.setValue(value); | 80 | resource.setValue(value); |
75 | return resource; | 81 | return resource; |
76 | } | 82 | } |
@@ -16,15 +16,28 @@ | @@ -16,15 +16,28 @@ | ||
16 | package org.thingsboard.server.dao.resource; | 16 | package org.thingsboard.server.dao.resource; |
17 | 17 | ||
18 | import lombok.extern.slf4j.Slf4j; | 18 | import lombok.extern.slf4j.Slf4j; |
19 | +import org.eclipse.leshan.core.model.DDFFileParser; | ||
20 | +import org.eclipse.leshan.core.model.DefaultDDFFileValidator; | ||
21 | +import org.eclipse.leshan.core.model.InvalidDDFFileException; | ||
22 | +import org.eclipse.leshan.core.model.ObjectModel; | ||
19 | import org.springframework.stereotype.Service; | 23 | import org.springframework.stereotype.Service; |
20 | import org.thingsboard.server.common.data.Resource; | 24 | import org.thingsboard.server.common.data.Resource; |
21 | import org.thingsboard.server.common.data.ResourceType; | 25 | import org.thingsboard.server.common.data.ResourceType; |
22 | import org.thingsboard.server.common.data.id.TenantId; | 26 | import org.thingsboard.server.common.data.id.TenantId; |
27 | +import org.thingsboard.server.common.data.lwm2m.LwM2mInstance; | ||
28 | +import org.thingsboard.server.common.data.lwm2m.LwM2mObject; | ||
29 | +import org.thingsboard.server.common.data.lwm2m.LwM2mResource; | ||
23 | import org.thingsboard.server.common.data.page.PageData; | 30 | import org.thingsboard.server.common.data.page.PageData; |
24 | import org.thingsboard.server.common.data.page.PageLink; | 31 | import org.thingsboard.server.common.data.page.PageLink; |
25 | import org.thingsboard.server.dao.exception.DataValidationException; | 32 | import org.thingsboard.server.dao.exception.DataValidationException; |
26 | 33 | ||
34 | +import java.io.ByteArrayInputStream; | ||
35 | +import java.io.IOException; | ||
36 | +import java.util.ArrayList; | ||
37 | +import java.util.Base64; | ||
38 | +import java.util.Comparator; | ||
27 | import java.util.List; | 39 | import java.util.List; |
40 | +import java.util.stream.Collectors; | ||
28 | 41 | ||
29 | import static org.thingsboard.server.dao.device.DeviceServiceImpl.INCORRECT_TENANT_ID; | 42 | import static org.thingsboard.server.dao.device.DeviceServiceImpl.INCORRECT_TENANT_ID; |
30 | import static org.thingsboard.server.dao.service.Validator.validateId; | 43 | import static org.thingsboard.server.dao.service.Validator.validateId; |
@@ -69,10 +82,35 @@ public class BaseResourceService implements ResourceService { | @@ -69,10 +82,35 @@ public class BaseResourceService implements ResourceService { | ||
69 | 82 | ||
70 | 83 | ||
71 | @Override | 84 | @Override |
72 | - public List<Resource> findResourcesByTenantIdResourceType(TenantId tenantId, ResourceType resourceType) { | 85 | + public List<Resource> findAllByTenantIdAndResourceType(TenantId tenantId, ResourceType resourceType) { |
73 | log.trace("Executing findByTenantId [{}]", tenantId); | 86 | log.trace("Executing findByTenantId [{}]", tenantId); |
74 | validateId(tenantId, INCORRECT_TENANT_ID + tenantId); | 87 | validateId(tenantId, INCORRECT_TENANT_ID + tenantId); |
75 | - return resourceDao.findAllByTenantIdResourceType(tenantId, resourceType); | 88 | + return resourceDao.findAllByTenantIdAndResourceType(tenantId, resourceType); |
89 | + } | ||
90 | + | ||
91 | + @Override | ||
92 | + public List<LwM2mObject> findLwM2mObjectPage(TenantId tenantId, String sortProperty, String sortOrder, PageLink pageLink) { | ||
93 | + log.trace("Executing findByTenantId [{}]", tenantId); | ||
94 | + validateId(tenantId, INCORRECT_TENANT_ID + tenantId); | ||
95 | + PageData<Resource> resourcePageData = resourceDao.findResourcesByTenantIdAndResourceType( | ||
96 | + tenantId, | ||
97 | + ResourceType.LWM2M_MODEL, pageLink); | ||
98 | + List<LwM2mObject> lwM2mObjects = resourcePageData.getData().stream().map(this::toLwM2mObject).collect(Collectors.toList()); | ||
99 | + return lwM2mObjects.size() > 1 ? this.sortList (lwM2mObjects, sortProperty, sortOrder) : lwM2mObjects; | ||
100 | + } | ||
101 | + | ||
102 | + @Override | ||
103 | + public List<LwM2mObject> findLwM2mObject(TenantId tenantId, String sortOrder, | ||
104 | + String sortProperty, | ||
105 | + String[] objectIds, | ||
106 | + String searchText) { | ||
107 | + log.trace("Executing findByTenantId [{}]", tenantId); | ||
108 | + validateId(tenantId, INCORRECT_TENANT_ID + tenantId); | ||
109 | + List<Resource> resources = resourceDao.findResourcesByTenantIdAndResourceType(tenantId, ResourceType.LWM2M_MODEL, | ||
110 | + objectIds, | ||
111 | + searchText); | ||
112 | + List<LwM2mObject> lwM2mObjects = resources.stream().map(this::toLwM2mObject).collect(Collectors.toList()); | ||
113 | + return lwM2mObjects.size() > 1 ? this.sortList (lwM2mObjects, sortProperty, sortOrder) : lwM2mObjects; | ||
76 | } | 114 | } |
77 | 115 | ||
78 | @Override | 116 | @Override |
@@ -86,11 +124,13 @@ public class BaseResourceService implements ResourceService { | @@ -86,11 +124,13 @@ public class BaseResourceService implements ResourceService { | ||
86 | if (resource == null) { | 124 | if (resource == null) { |
87 | throw new DataValidationException("Resource should be specified!"); | 125 | throw new DataValidationException("Resource should be specified!"); |
88 | } | 126 | } |
89 | - | ||
90 | if (resource.getValue() == null) { | 127 | if (resource.getValue() == null) { |
91 | throw new DataValidationException("Resource value should be specified!"); | 128 | throw new DataValidationException("Resource value should be specified!"); |
92 | } | 129 | } |
93 | validate(resource.getTenantId(), resource.getResourceType(), resource.getResourceId()); | 130 | validate(resource.getTenantId(), resource.getResourceType(), resource.getResourceId()); |
131 | + if (resource.getResourceType().equals(ResourceType.LWM2M_MODEL) && resource.toLwM2mObject() == null) { | ||
132 | + throw new DataValidationException(String.format("Could not parse the XML of objectModel with name %s", resource.getTextSearch())); | ||
133 | + } | ||
94 | } | 134 | } |
95 | 135 | ||
96 | protected void validate(TenantId tenantId, ResourceType resourceType, String resourceId) { | 136 | protected void validate(TenantId tenantId, ResourceType resourceType, String resourceId) { |
@@ -103,4 +143,61 @@ public class BaseResourceService implements ResourceService { | @@ -103,4 +143,61 @@ public class BaseResourceService implements ResourceService { | ||
103 | validateId(tenantId, "Incorrect tenantId "); | 143 | validateId(tenantId, "Incorrect tenantId "); |
104 | } | 144 | } |
105 | 145 | ||
146 | + private LwM2mObject toLwM2mObject(Resource resource) { | ||
147 | + try { | ||
148 | + DDFFileParser ddfFileParser = new DDFFileParser(new DefaultDDFFileValidator()); | ||
149 | + List<ObjectModel> objectModels = | ||
150 | + ddfFileParser.parseEx(new ByteArrayInputStream(Base64.getDecoder().decode(resource.getValue())), resource.getTextSearch()); | ||
151 | + if (objectModels.size() == 0) { | ||
152 | + return null; | ||
153 | + } else { | ||
154 | + ObjectModel obj = objectModels.get(0); | ||
155 | + LwM2mObject lwM2mObject = new LwM2mObject(); | ||
156 | + lwM2mObject.setId(obj.id); | ||
157 | + lwM2mObject.setKeyId(resource.getResourceId()); | ||
158 | + lwM2mObject.setName(obj.name); | ||
159 | + lwM2mObject.setMultiple(obj.multiple); | ||
160 | + lwM2mObject.setMandatory(obj.mandatory); | ||
161 | + LwM2mInstance instance = new LwM2mInstance(); | ||
162 | + instance.setId(0); | ||
163 | + List<LwM2mResource> resources = new ArrayList<>(); | ||
164 | + obj.resources.forEach((k, v) -> { | ||
165 | + if (!v.operations.isExecutable()) { | ||
166 | + LwM2mResource lwM2mResource = new LwM2mResource(k, v.name, false, false, false); | ||
167 | + resources.add(lwM2mResource); | ||
168 | + } | ||
169 | + }); | ||
170 | + instance.setResources(resources.stream().toArray(LwM2mResource[]::new)); | ||
171 | + lwM2mObject.setInstances(new LwM2mInstance[]{instance}); | ||
172 | + return lwM2mObject; | ||
173 | + } | ||
174 | + } catch (IOException | InvalidDDFFileException e) { | ||
175 | + log.error("Could not parse the XML of objectModel with name [{}]", resource.getTextSearch(), e); | ||
176 | + return null; | ||
177 | + } | ||
178 | + } | ||
179 | + | ||
180 | + private List<LwM2mObject> sortList (List<LwM2mObject> lwM2mObjects, String sortProperty, String sortOrder) { | ||
181 | + switch (sortProperty) { | ||
182 | + case "name": | ||
183 | + switch (sortOrder) { | ||
184 | + case "ASC": | ||
185 | + lwM2mObjects.sort((o1, o2) -> o1.getName().compareTo(o2.getName())); | ||
186 | + break; | ||
187 | + case "DESC": | ||
188 | + lwM2mObjects.stream().sorted(Comparator.comparing(LwM2mObject::getName).reversed()); | ||
189 | + break; | ||
190 | + } | ||
191 | + case "id": | ||
192 | + switch (sortOrder) { | ||
193 | + case "ASC": | ||
194 | + lwM2mObjects.sort((o1, o2) -> Long.compare(o1.getId(), o2.getId())); | ||
195 | + break; | ||
196 | + case "DESC": | ||
197 | + lwM2mObjects.sort((o1, o2) -> Long.compare(o2.getId(), o1.getId())); | ||
198 | + } | ||
199 | + } | ||
200 | + return lwM2mObjects; | ||
201 | + } | ||
202 | + | ||
106 | } | 203 | } |
@@ -33,8 +33,15 @@ public interface ResourceDao { | @@ -33,8 +33,15 @@ public interface ResourceDao { | ||
33 | 33 | ||
34 | PageData<Resource> findAllByTenantId(TenantId tenantId, PageLink pageLink); | 34 | PageData<Resource> findAllByTenantId(TenantId tenantId, PageLink pageLink); |
35 | 35 | ||
36 | + PageData<Resource> findResourcesByTenantIdAndResourceType(TenantId tenantId, | ||
37 | + ResourceType resourceType, | ||
38 | + PageLink pageLink); | ||
36 | 39 | ||
37 | - List<Resource> findAllByTenantIdResourceType(TenantId tenantId, ResourceType resourceType); | 40 | + List<Resource> findAllByTenantIdAndResourceType(TenantId tenantId, ResourceType resourceType); |
38 | 41 | ||
42 | + List<Resource> findResourcesByTenantIdAndResourceType(TenantId tenantId, | ||
43 | + ResourceType resourceType, | ||
44 | + String[] objectIds, | ||
45 | + String searchText); | ||
39 | void removeAllByTenantId(TenantId tenantId); | 46 | void removeAllByTenantId(TenantId tenantId); |
40 | } | 47 | } |
@@ -29,6 +29,7 @@ import org.thingsboard.server.dao.model.sql.ResourceEntity; | @@ -29,6 +29,7 @@ import org.thingsboard.server.dao.model.sql.ResourceEntity; | ||
29 | import org.thingsboard.server.dao.resource.ResourceDao; | 29 | import org.thingsboard.server.dao.resource.ResourceDao; |
30 | 30 | ||
31 | import java.util.List; | 31 | import java.util.List; |
32 | +import java.util.Objects; | ||
32 | 33 | ||
33 | @Slf4j | 34 | @Slf4j |
34 | @Component | 35 | @Component |
@@ -73,11 +74,40 @@ public class ResourceDaoImpl implements ResourceDao { | @@ -73,11 +74,40 @@ public class ResourceDaoImpl implements ResourceDao { | ||
73 | } | 74 | } |
74 | 75 | ||
75 | @Override | 76 | @Override |
76 | - public List<Resource> findAllByTenantIdResourceType(TenantId tenantId, ResourceType resourceType) { | 77 | + public List<Resource> findAllByTenantIdAndResourceType(TenantId tenantId, ResourceType resourceType) { |
77 | return DaoUtil.convertDataList(resourceRepository.findAllByTenantIdAndResourceType(tenantId.getId(), resourceType.name())); | 78 | return DaoUtil.convertDataList(resourceRepository.findAllByTenantIdAndResourceType(tenantId.getId(), resourceType.name())); |
78 | } | 79 | } |
79 | 80 | ||
80 | @Override | 81 | @Override |
82 | + public PageData<Resource> findResourcesByTenantIdAndResourceType(TenantId tenantId, | ||
83 | + ResourceType resourceType, | ||
84 | + PageLink pageLink) { | ||
85 | + return DaoUtil.toPageData(resourceRepository.findResourcesPage( | ||
86 | + tenantId.getId(), | ||
87 | + TenantId.SYS_TENANT_ID.getId(), | ||
88 | + resourceType.name(), | ||
89 | + Objects.toString(pageLink.getTextSearch(), ""), | ||
90 | + DaoUtil.toPageable(pageLink) | ||
91 | + )); | ||
92 | + } | ||
93 | + | ||
94 | + @Override | ||
95 | + public List<Resource> findResourcesByTenantIdAndResourceType(TenantId tenantId, ResourceType resourceType, | ||
96 | + String[] objectIds, | ||
97 | + String searchText) { | ||
98 | + return objectIds == null ? | ||
99 | + DaoUtil.convertDataList(resourceRepository.findResources( | ||
100 | + tenantId.getId(), | ||
101 | + TenantId.SYS_TENANT_ID.getId(), | ||
102 | + resourceType.name(), | ||
103 | + Objects.toString(searchText, ""))) : | ||
104 | + DaoUtil.convertDataList(resourceRepository.findResourcesByIds( | ||
105 | + tenantId.getId(), | ||
106 | + TenantId.SYS_TENANT_ID.getId(), | ||
107 | + resourceType.name(), objectIds)); | ||
108 | + } | ||
109 | + | ||
110 | + @Override | ||
81 | public void removeAllByTenantId(TenantId tenantId) { | 111 | public void removeAllByTenantId(TenantId tenantId) { |
82 | resourceRepository.removeAllByTenantId(tenantId.getId()); | 112 | resourceRepository.removeAllByTenantId(tenantId.getId()); |
83 | } | 113 | } |
@@ -17,7 +17,9 @@ package org.thingsboard.server.dao.sql.resource; | @@ -17,7 +17,9 @@ package org.thingsboard.server.dao.sql.resource; | ||
17 | 17 | ||
18 | import org.springframework.data.domain.Page; | 18 | import org.springframework.data.domain.Page; |
19 | import org.springframework.data.domain.Pageable; | 19 | import org.springframework.data.domain.Pageable; |
20 | +import org.springframework.data.jpa.repository.Query; | ||
20 | import org.springframework.data.repository.CrudRepository; | 21 | import org.springframework.data.repository.CrudRepository; |
22 | +import org.springframework.data.repository.query.Param; | ||
21 | import org.thingsboard.server.dao.model.sql.ResourceCompositeKey; | 23 | import org.thingsboard.server.dao.model.sql.ResourceCompositeKey; |
22 | import org.thingsboard.server.dao.model.sql.ResourceEntity; | 24 | import org.thingsboard.server.dao.model.sql.ResourceEntity; |
23 | 25 | ||
@@ -26,10 +28,57 @@ import java.util.UUID; | @@ -26,10 +28,57 @@ import java.util.UUID; | ||
26 | 28 | ||
27 | public interface ResourceRepository extends CrudRepository<ResourceEntity, ResourceCompositeKey> { | 29 | public interface ResourceRepository extends CrudRepository<ResourceEntity, ResourceCompositeKey> { |
28 | 30 | ||
31 | + | ||
29 | Page<ResourceEntity> findAllByTenantId(UUID tenantId, Pageable pageable); | 32 | Page<ResourceEntity> findAllByTenantId(UUID tenantId, Pageable pageable); |
30 | 33 | ||
34 | + @Query("SELECT tr FROM ResourceEntity tr " + | ||
35 | + "WHERE tr.resourceType = :resourceType " + | ||
36 | + "AND LOWER(tr.textSearch) LIKE LOWER(CONCAT('%', :searchText, '%')) " + | ||
37 | + "AND (tr.tenantId = :tenantId " + | ||
38 | + "OR (tr.tenantId = :systemAdminId " + | ||
39 | + "AND NOT EXISTS " + | ||
40 | + "(SELECT sr FROM ResourceEntity sr " + | ||
41 | + "WHERE sr.tenantId = :tenantId " + | ||
42 | + "AND sr.resourceType = :resourceType " + | ||
43 | + "AND tr.resourceId = sr.resourceId)))") | ||
44 | + Page<ResourceEntity> findResourcesPage( | ||
45 | + @Param("tenantId") UUID tenantId, | ||
46 | + @Param("systemAdminId") UUID sysAdminId, | ||
47 | + @Param("resourceType") String resourceType, | ||
48 | + @Param("searchText") String search, | ||
49 | + Pageable pageable); | ||
31 | 50 | ||
32 | List<ResourceEntity> findAllByTenantIdAndResourceType(UUID tenantId, String resourceType); | 51 | List<ResourceEntity> findAllByTenantIdAndResourceType(UUID tenantId, String resourceType); |
33 | 52 | ||
34 | void removeAllByTenantId(UUID tenantId); | 53 | void removeAllByTenantId(UUID tenantId); |
54 | + | ||
55 | + @Query("SELECT tr FROM ResourceEntity tr " + | ||
56 | + "WHERE tr.resourceType = :resourceType " + | ||
57 | + "AND LOWER(tr.textSearch) LIKE LOWER(CONCAT('%', :searchText, '%')) " + | ||
58 | + "AND (tr.tenantId = :tenantId " + | ||
59 | + "OR (tr.tenantId = :systemAdminId " + | ||
60 | + "AND NOT EXISTS " + | ||
61 | + "(SELECT sr FROM ResourceEntity sr " + | ||
62 | + "WHERE sr.tenantId = :tenantId " + | ||
63 | + "AND sr.resourceType = :resourceType " + | ||
64 | + "AND tr.resourceId = sr.resourceId)))") | ||
65 | + List<ResourceEntity> findResources(@Param("tenantId") UUID tenantId, | ||
66 | + @Param("systemAdminId") UUID sysAdminId, | ||
67 | + @Param("resourceType") String resourceType, | ||
68 | + @Param("searchText") String search); | ||
69 | + | ||
70 | + @Query("SELECT tr FROM ResourceEntity tr " + | ||
71 | + "WHERE tr.resourceType = :resourceType " + | ||
72 | + "AND tr.resourceId in (:resourceIds) " + | ||
73 | + "AND (tr.tenantId = :tenantId " + | ||
74 | + "OR (tr.tenantId = :systemAdminId " + | ||
75 | + "AND NOT EXISTS " + | ||
76 | + "(SELECT sr FROM ResourceEntity sr " + | ||
77 | + "WHERE sr.tenantId = :tenantId " + | ||
78 | + "AND sr.resourceType = :resourceType " + | ||
79 | + "AND tr.resourceId = sr.resourceId)))") | ||
80 | + List<ResourceEntity> findResourcesByIds(@Param("tenantId") UUID tenantId, | ||
81 | + @Param("systemAdminId") UUID sysAdminId, | ||
82 | + @Param("resourceType") String resourceType, | ||
83 | + @Param("resourceIds") String[] objectIds); | ||
35 | } | 84 | } |
@@ -425,6 +425,7 @@ CREATE TABLE IF NOT EXISTS resource ( | @@ -425,6 +425,7 @@ CREATE TABLE IF NOT EXISTS resource ( | ||
425 | tenant_id uuid NOT NULL, | 425 | tenant_id uuid NOT NULL, |
426 | resource_type varchar(32) NOT NULL, | 426 | resource_type varchar(32) NOT NULL, |
427 | resource_id varchar(255) NOT NULL, | 427 | resource_id varchar(255) NOT NULL, |
428 | + text_search varchar(255), | ||
428 | resource_value varchar, | 429 | resource_value varchar, |
429 | CONSTRAINT resource_unq_key UNIQUE (tenant_id, resource_type, resource_id) | 430 | CONSTRAINT resource_unq_key UNIQUE (tenant_id, resource_type, resource_id) |
430 | ); | 431 | ); |
@@ -451,6 +451,7 @@ CREATE TABLE IF NOT EXISTS resource ( | @@ -451,6 +451,7 @@ CREATE TABLE IF NOT EXISTS resource ( | ||
451 | tenant_id uuid NOT NULL, | 451 | tenant_id uuid NOT NULL, |
452 | resource_type varchar(32) NOT NULL, | 452 | resource_type varchar(32) NOT NULL, |
453 | resource_id varchar(255) NOT NULL, | 453 | resource_id varchar(255) NOT NULL, |
454 | + text_search varchar(255), | ||
454 | resource_value varchar, | 455 | resource_value varchar, |
455 | CONSTRAINT resource_unq_key UNIQUE (tenant_id, resource_type, resource_id) | 456 | CONSTRAINT resource_unq_key UNIQUE (tenant_id, resource_type, resource_id) |
456 | ); | 457 | ); |
@@ -14,16 +14,16 @@ | @@ -14,16 +14,16 @@ | ||
14 | /// limitations under the License. | 14 | /// limitations under the License. |
15 | /// | 15 | /// |
16 | 16 | ||
17 | -import { Injectable } from '@angular/core'; | ||
18 | -import { HttpClient } from '@angular/common/http'; | ||
19 | -import { PageLink } from '@shared/models/page/page-link'; | ||
20 | -import { defaultHttpOptionsFromConfig, RequestConfig } from './http-utils'; | ||
21 | -import { Observable } from 'rxjs'; | ||
22 | -import { PageData } from '@shared/models/page/page-data'; | ||
23 | -import { DeviceProfile, DeviceProfileInfo, DeviceTransportType } from '@shared/models/device.models'; | ||
24 | -import { isDefinedAndNotNull, isEmptyStr } from '@core/utils'; | ||
25 | -import { ObjectLwM2M, ServerSecurityConfig } from '@home/components/profile/device/lwm2m/profile-config.models'; | ||
26 | -import { SortOrder } from '@shared/models/page/sort-order'; | 17 | +import {Injectable} from '@angular/core'; |
18 | +import {HttpClient} from '@angular/common/http'; | ||
19 | +import {PageLink} from '@shared/models/page/page-link'; | ||
20 | +import {defaultHttpOptionsFromConfig, RequestConfig} from './http-utils'; | ||
21 | +import {Observable} from 'rxjs'; | ||
22 | +import {PageData} from '@shared/models/page/page-data'; | ||
23 | +import {DeviceProfile, DeviceProfileInfo, DeviceTransportType} from '@shared/models/device.models'; | ||
24 | +import {isDefinedAndNotNull, isEmptyStr} from '@core/utils'; | ||
25 | +import {ObjectLwM2M, ServerSecurityConfig} from '@home/components/profile/device/lwm2m/profile-config.models'; | ||
26 | +import {SortOrder} from '@shared/models/page/sort-order'; | ||
27 | 27 | ||
28 | @Injectable({ | 28 | @Injectable({ |
29 | providedIn: 'root' | 29 | providedIn: 'root' |
@@ -43,9 +43,9 @@ export class DeviceProfileService { | @@ -43,9 +43,9 @@ export class DeviceProfileService { | ||
43 | return this.http.get<DeviceProfile>(`/api/deviceProfile/${deviceProfileId}`, defaultHttpOptionsFromConfig(config)); | 43 | return this.http.get<DeviceProfile>(`/api/deviceProfile/${deviceProfileId}`, defaultHttpOptionsFromConfig(config)); |
44 | } | 44 | } |
45 | 45 | ||
46 | - public getLwm2mObjects(sortOrder: SortOrder, objectIds?: number[], searchText?: string, config?: RequestConfig): | 46 | + public getLwm2mObjects(sortOrder: SortOrder, objectIds?: string[], searchText?: string, config?: RequestConfig): |
47 | Observable<Array<ObjectLwM2M>> { | 47 | Observable<Array<ObjectLwM2M>> { |
48 | - let url = `/api/lwm2m/deviceProfile/?sortProperty=${sortOrder.property}&sortOrder=${sortOrder.direction}`; | 48 | + let url = `/api/resource/lwm2m/?sortProperty=${sortOrder.property}&sortOrder=${sortOrder.direction}`; |
49 | if (isDefinedAndNotNull(objectIds) && objectIds.length > 0) { | 49 | if (isDefinedAndNotNull(objectIds) && objectIds.length > 0) { |
50 | url += `&objectIds=${objectIds}`; | 50 | url += `&objectIds=${objectIds}`; |
51 | } | 51 | } |
@@ -63,9 +63,9 @@ export class DeviceProfileService { | @@ -63,9 +63,9 @@ export class DeviceProfileService { | ||
63 | ); | 63 | ); |
64 | } | 64 | } |
65 | 65 | ||
66 | - public getLwm2mObjectsPage(pageLink: PageLink, config?: RequestConfig): Observable<PageData<ObjectLwM2M>> { | ||
67 | - return this.http.get<PageData<ObjectLwM2M>>( | ||
68 | - `/api/lwm2m/deviceProfile/objects${pageLink.toQuery()}`, | 66 | + public getLwm2mObjectsPage(pageLink: PageLink, config?: RequestConfig): Observable<Array<ObjectLwM2M>> { |
67 | + return this.http.get<Array<ObjectLwM2M>>( | ||
68 | + `/api/resource/lwm2m/page${pageLink.toQuery()}`, | ||
69 | defaultHttpOptionsFromConfig(config) | 69 | defaultHttpOptionsFromConfig(config) |
70 | ); | 70 | ); |
71 | } | 71 | } |
@@ -172,7 +172,7 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro | @@ -172,7 +172,7 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro | ||
172 | 172 | ||
173 | private updateObserveAttrTelemetryObjectFormGroup = (objectsList: ObjectLwM2M[]): void => { | 173 | private updateObserveAttrTelemetryObjectFormGroup = (objectsList: ObjectLwM2M[]): void => { |
174 | this.lwm2mDeviceProfileFormGroup.patchValue({ | 174 | this.lwm2mDeviceProfileFormGroup.patchValue({ |
175 | - observeAttrTelemetry: this.getObserveAttrTelemetryObjects(objectsList) | 175 | + observeAttrTelemetry: deepClone(this.getObserveAttrTelemetryObjects(objectsList)) |
176 | }, | 176 | }, |
177 | {emitEvent: false}); | 177 | {emitEvent: false}); |
178 | } | 178 | } |
@@ -195,32 +195,32 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro | @@ -195,32 +195,32 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro | ||
195 | } | 195 | } |
196 | } | 196 | } |
197 | 197 | ||
198 | - private getObserveAttrTelemetryObjects = (listObject: ObjectLwM2M[]): object => { | ||
199 | - const clientObserveAttrTelemetry = listObject; | ||
200 | - if (this.configurationValue.observeAttr) { | 198 | + private getObserveAttrTelemetryObjects = (objectList: ObjectLwM2M[]): object => { |
199 | + const objectLwM2MS = deepClone(objectList); | ||
200 | + if (this.configurationValue.observeAttr && objectLwM2MS.length > 0) { | ||
201 | const observeArray = this.configurationValue.observeAttr.observe; | 201 | const observeArray = this.configurationValue.observeAttr.observe; |
202 | const attributeArray = this.configurationValue.observeAttr.attribute; | 202 | const attributeArray = this.configurationValue.observeAttr.attribute; |
203 | const telemetryArray = this.configurationValue.observeAttr.telemetry; | 203 | const telemetryArray = this.configurationValue.observeAttr.telemetry; |
204 | let keyNameJson = this.configurationValue.observeAttr.keyName; | 204 | let keyNameJson = this.configurationValue.observeAttr.keyName; |
205 | if (this.includesNotZeroInstance(attributeArray, telemetryArray)) { | 205 | if (this.includesNotZeroInstance(attributeArray, telemetryArray)) { |
206 | - this.addInstances(attributeArray, telemetryArray, clientObserveAttrTelemetry); | 206 | + this.addInstances(attributeArray, telemetryArray, objectLwM2MS); |
207 | } | 207 | } |
208 | if (isDefinedAndNotNull(observeArray)) { | 208 | if (isDefinedAndNotNull(observeArray)) { |
209 | - this.updateObserveAttrTelemetryObjects(observeArray, clientObserveAttrTelemetry, OBSERVE); | 209 | + this.updateObserveAttrTelemetryObjects(observeArray, objectLwM2MS, OBSERVE); |
210 | } | 210 | } |
211 | if (isDefinedAndNotNull(attributeArray)) { | 211 | if (isDefinedAndNotNull(attributeArray)) { |
212 | - this.updateObserveAttrTelemetryObjects(attributeArray, clientObserveAttrTelemetry, ATTRIBUTE); | 212 | + this.updateObserveAttrTelemetryObjects(attributeArray, objectLwM2MS, ATTRIBUTE); |
213 | } | 213 | } |
214 | if (isDefinedAndNotNull(telemetryArray)) { | 214 | if (isDefinedAndNotNull(telemetryArray)) { |
215 | - this.updateObserveAttrTelemetryObjects(telemetryArray, clientObserveAttrTelemetry, TELEMETRY); | 215 | + this.updateObserveAttrTelemetryObjects(telemetryArray, objectLwM2MS, TELEMETRY); |
216 | } | 216 | } |
217 | if (isDefinedAndNotNull(keyNameJson)) { | 217 | if (isDefinedAndNotNull(keyNameJson)) { |
218 | this.configurationValue.observeAttr.keyName = this.validateKeyNameObjects(keyNameJson, attributeArray, telemetryArray); | 218 | this.configurationValue.observeAttr.keyName = this.validateKeyNameObjects(keyNameJson, attributeArray, telemetryArray); |
219 | this.upDateJsonAllConfig(); | 219 | this.upDateJsonAllConfig(); |
220 | - this.updateKeyNameObjects(clientObserveAttrTelemetry); | 220 | + this.updateKeyNameObjects(objectLwM2MS); |
221 | } | 221 | } |
222 | } | 222 | } |
223 | - return {clientLwM2M: clientObserveAttrTelemetry}; | 223 | + return {clientLwM2M: objectLwM2MS}; |
224 | } | 224 | } |
225 | 225 | ||
226 | private includesNotZeroInstance = (attribute: string[], telemetry: string[]): boolean => { | 226 | private includesNotZeroInstance = (attribute: string[], telemetry: string[]): boolean => { |
@@ -235,35 +235,39 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro | @@ -235,35 +235,39 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro | ||
235 | .sort(this.sortPath); | 235 | .sort(this.sortPath); |
236 | 236 | ||
237 | new Set(instancesPath).forEach(path => { | 237 | new Set(instancesPath).forEach(path => { |
238 | - const pathParameter = Array.from(path.split('/'), Number); | ||
239 | - const objectLwM2M = clientObserveAttrTelemetry.find(x => x.id === pathParameter[0]); | 238 | + const pathParameter = Array.from(path.split('/'), String); |
239 | + const objectLwM2M = clientObserveAttrTelemetry.find(x => x.keyId === pathParameter[0]); | ||
240 | if (objectLwM2M) { | 240 | if (objectLwM2M) { |
241 | const instance = deepClone(objectLwM2M.instances[0]); | 241 | const instance = deepClone(objectLwM2M.instances[0]); |
242 | - instance.id = pathParameter[1]; | 242 | + instance.id = +pathParameter[1]; |
243 | objectLwM2M.instances.push(instance); | 243 | objectLwM2M.instances.push(instance); |
244 | } | 244 | } |
245 | }); | 245 | }); |
246 | } | 246 | } |
247 | 247 | ||
248 | - private updateObserveAttrTelemetryObjects = (parameters: string[], clientObserveAttrTelemetry: ObjectLwM2M[], | 248 | + private updateObserveAttrTelemetryObjects = (parameters: string[], objectLwM2MS: ObjectLwM2M[], |
249 | nameParameter: string): void => { | 249 | nameParameter: string): void => { |
250 | parameters.forEach(parameter => { | 250 | parameters.forEach(parameter => { |
251 | - const [objectId, instanceId, resourceId] = Array.from(parameter.substring(1).split('/'), Number); | ||
252 | - clientObserveAttrTelemetry.find(objectLwm2m => objectLwm2m.id === objectId) | ||
253 | - .instances.find(itrInstance => itrInstance.id === instanceId) | ||
254 | - .resources.find(resource => resource.id === resourceId) | ||
255 | - [nameParameter] = true; | 251 | + const [objectKeyId, instanceId, resourceId] = Array.from(parameter.substring(1).split('/'), String); |
252 | + const objectLwM2M = objectLwM2MS.find(objectLwm2m => objectLwm2m.keyId === objectKeyId); | ||
253 | + if (objectLwM2M) { | ||
254 | + objectLwM2M.instances.find(itrInstance => itrInstance.id === +instanceId) | ||
255 | + .resources.find(resource => resource.id === +resourceId) | ||
256 | + [nameParameter] = true; | ||
257 | + } | ||
256 | }); | 258 | }); |
259 | + | ||
257 | } | 260 | } |
258 | 261 | ||
259 | private updateKeyNameObjects = (clientObserveAttrTelemetry: ObjectLwM2M[]): void => { | 262 | private updateKeyNameObjects = (clientObserveAttrTelemetry: ObjectLwM2M[]): void => { |
260 | Object.keys(this.configurationValue.observeAttr.keyName).forEach(key => { | 263 | Object.keys(this.configurationValue.observeAttr.keyName).forEach(key => { |
261 | - const [objectId, instanceId, resourceId] = Array.from(key.substring(1).split('/'), Number); | ||
262 | - clientObserveAttrTelemetry.find(objectLwm2m => objectLwm2m.id === objectId) | ||
263 | - .instances.find(instance => instance.id === instanceId) | ||
264 | - .resources.find(resource => resource.id === resourceId) | 264 | + const [objectKeyId, instanceId, resourceId] = Array.from(key.substring(1).split('/'), String); |
265 | + const objectLwM2M = clientObserveAttrTelemetry.find(objectLwm2m => objectLwm2m.keyId === objectKeyId) | ||
266 | + if (objectLwM2M) { | ||
267 | + objectLwM2M.instances.find(instance => instance.id === +instanceId) | ||
268 | + .resources.find(resource => resource.id === +resourceId) | ||
265 | .keyName = this.configurationValue.observeAttr.keyName[key]; | 269 | .keyName = this.configurationValue.observeAttr.keyName[key]; |
266 | - }); | 270 | + }}); |
267 | } | 271 | } |
268 | 272 | ||
269 | private validateKeyNameObjects = (nameJson: JsonObject, attributeArray: JsonArray, telemetryArray: JsonArray): {} => { | 273 | private validateKeyNameObjects = (nameJson: JsonObject, attributeArray: JsonArray, telemetryArray: JsonArray): {} => { |
@@ -290,7 +294,7 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro | @@ -290,7 +294,7 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro | ||
290 | if (instance.hasOwnProperty(RESOURCES) && Array.isArray(instance.resources)) { | 294 | if (instance.hasOwnProperty(RESOURCES) && Array.isArray(instance.resources)) { |
291 | instance.resources.forEach(resource => { | 295 | instance.resources.forEach(resource => { |
292 | if (resource.attribute || resource.telemetry) { | 296 | if (resource.attribute || resource.telemetry) { |
293 | - let pathRes = `/${obj.id}/${instance.id}/${resource.id}`; | 297 | + let pathRes = `/${obj.keyId}/${instance.id}/${resource.id}`; |
294 | if (resource.observe) { | 298 | if (resource.observe) { |
295 | observeArray.push(pathRes); | 299 | observeArray.push(pathRes); |
296 | } | 300 | } |
@@ -345,22 +349,22 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro | @@ -345,22 +349,22 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro | ||
345 | }); | 349 | }); |
346 | } | 350 | } |
347 | 351 | ||
348 | - private getObjectsFromJsonAllConfig = (): number[] => { | ||
349 | - const objectsIds = new Set<number>(); | 352 | + private getObjectsFromJsonAllConfig = (): string[] => { |
353 | + const objectsIds = new Set<string>(); | ||
350 | if (this.configurationValue.observeAttr) { | 354 | if (this.configurationValue.observeAttr) { |
351 | if (this.configurationValue.observeAttr.observe) { | 355 | if (this.configurationValue.observeAttr.observe) { |
352 | this.configurationValue.observeAttr.observe.forEach(obj => { | 356 | this.configurationValue.observeAttr.observe.forEach(obj => { |
353 | - objectsIds.add(Array.from(obj.substring(1).split('/'), Number)[0]); | 357 | + objectsIds.add(Array.from(obj.substring(1).split('/'), String)[0]); |
354 | }); | 358 | }); |
355 | } | 359 | } |
356 | if (this.configurationValue.observeAttr.attribute) { | 360 | if (this.configurationValue.observeAttr.attribute) { |
357 | this.configurationValue.observeAttr.attribute.forEach(obj => { | 361 | this.configurationValue.observeAttr.attribute.forEach(obj => { |
358 | - objectsIds.add(Array.from(obj.substring(1).split('/'), Number)[0]); | 362 | + objectsIds.add(Array.from(obj.substring(1).split('/'), String)[0]); |
359 | }); | 363 | }); |
360 | } | 364 | } |
361 | if (this.configurationValue.observeAttr.telemetry) { | 365 | if (this.configurationValue.observeAttr.telemetry) { |
362 | this.configurationValue.observeAttr.telemetry.forEach(obj => { | 366 | this.configurationValue.observeAttr.telemetry.forEach(obj => { |
363 | - objectsIds.add(Array.from(obj.substring(1).split('/'), Number)[0]); | 367 | + objectsIds.add(Array.from(obj.substring(1).split('/'), String)[0]); |
364 | }); | 368 | }); |
365 | } | 369 | } |
366 | } | 370 | } |
@@ -379,21 +383,21 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro | @@ -379,21 +383,21 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro | ||
379 | 383 | ||
380 | removeObjectsList = (value: ObjectLwM2M): void => { | 384 | removeObjectsList = (value: ObjectLwM2M): void => { |
381 | const objectsOld = this.lwm2mDeviceProfileFormGroup.get(OBSERVE_ATTR_TELEMETRY).value.clientLwM2M; | 385 | const objectsOld = this.lwm2mDeviceProfileFormGroup.get(OBSERVE_ATTR_TELEMETRY).value.clientLwM2M; |
382 | - const isIdIndex = (element) => element.id === value.id; | 386 | + const isIdIndex = (element) => element.keyId === value.keyId; |
383 | const index = objectsOld.findIndex(isIdIndex); | 387 | const index = objectsOld.findIndex(isIdIndex); |
384 | if (index >= 0) { | 388 | if (index >= 0) { |
385 | objectsOld.splice(index, 1); | 389 | objectsOld.splice(index, 1); |
386 | } | 390 | } |
387 | - this.removeObserveAttrTelemetryFromJson(OBSERVE, value.id); | ||
388 | - this.removeObserveAttrTelemetryFromJson(TELEMETRY, value.id); | ||
389 | - this.removeObserveAttrTelemetryFromJson(ATTRIBUTE, value.id); | ||
390 | - this.removeKeyNameFromJson(value.id); | 391 | + this.removeObserveAttrTelemetryFromJson(OBSERVE, value.keyId); |
392 | + this.removeObserveAttrTelemetryFromJson(TELEMETRY, value.keyId); | ||
393 | + this.removeObserveAttrTelemetryFromJson(ATTRIBUTE, value.keyId); | ||
394 | + this.removeKeyNameFromJson(value.keyId); | ||
391 | this.updateObserveAttrTelemetryObjectFormGroup(objectsOld); | 395 | this.updateObserveAttrTelemetryObjectFormGroup(objectsOld); |
392 | this.upDateJsonAllConfig(); | 396 | this.upDateJsonAllConfig(); |
393 | } | 397 | } |
394 | 398 | ||
395 | - private removeObserveAttrTelemetryFromJson = (observeAttrTel: string, id: number): void => { | ||
396 | - const isIdIndex = (element) => element.startsWith(`/${id}`); | 399 | + private removeObserveAttrTelemetryFromJson = (observeAttrTel: string, keyId: string): void => { |
400 | + const isIdIndex = (element) => element.startsWith(`/${keyId}`); | ||
397 | let index = this.configurationValue.observeAttr[observeAttrTel].findIndex(isIdIndex); | 401 | let index = this.configurationValue.observeAttr[observeAttrTel].findIndex(isIdIndex); |
398 | while (index >= 0) { | 402 | while (index >= 0) { |
399 | this.configurationValue.observeAttr[observeAttrTel].splice(index, 1); | 403 | this.configurationValue.observeAttr[observeAttrTel].splice(index, 1); |
@@ -401,10 +405,10 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro | @@ -401,10 +405,10 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro | ||
401 | } | 405 | } |
402 | } | 406 | } |
403 | 407 | ||
404 | - private removeKeyNameFromJson = (id: number): void => { | 408 | + private removeKeyNameFromJson = (keyId: string): void => { |
405 | const keyNameJson = this.configurationValue.observeAttr.keyName; | 409 | const keyNameJson = this.configurationValue.observeAttr.keyName; |
406 | Object.keys(keyNameJson).forEach(key => { | 410 | Object.keys(keyNameJson).forEach(key => { |
407 | - if (key.startsWith(`/${id}`)) { | 411 | + if (key.startsWith(`/${keyId}`)) { |
408 | delete keyNameJson[key]; | 412 | delete keyNameJson[key]; |
409 | } | 413 | } |
410 | }); | 414 | }); |
@@ -14,12 +14,11 @@ | @@ -14,12 +14,11 @@ | ||
14 | /// limitations under the License. | 14 | /// limitations under the License. |
15 | /// | 15 | /// |
16 | 16 | ||
17 | -import { Component, forwardRef, } from '@angular/core'; | ||
18 | -import { ControlValueAccessor, FormBuilder, FormGroup, NG_VALUE_ACCESSOR, Validators } from '@angular/forms'; | ||
19 | -import { Store } from '@ngrx/store'; | ||
20 | -import { AppState } from '@core/core.state'; | ||
21 | -import { INSTANCES_ID_VALUE_MAX, INSTANCES_ID_VALUE_MIN, KEY_REGEXP_NUMBER } from './profile-config.models'; | ||
22 | -import { DeviceProfileService } from '@core/http/device-profile.service'; | 17 | +import {Component, forwardRef,} from '@angular/core'; |
18 | +import {ControlValueAccessor, FormBuilder, FormGroup, NG_VALUE_ACCESSOR, Validators} from '@angular/forms'; | ||
19 | +import {Store} from '@ngrx/store'; | ||
20 | +import {AppState} from '@core/core.state'; | ||
21 | +import {INSTANCES_ID_VALUE_MAX, INSTANCES_ID_VALUE_MIN, KEY_REGEXP_NUMBER} from './profile-config.models'; | ||
23 | 22 | ||
24 | @Component({ | 23 | @Component({ |
25 | selector: 'tb-profile-lwm2m-object-add-instances-list', | 24 | selector: 'tb-profile-lwm2m-object-add-instances-list', |
@@ -43,7 +42,6 @@ export class Lwm2mObjectAddInstancesListComponent implements ControlValueAccesso | @@ -43,7 +42,6 @@ export class Lwm2mObjectAddInstancesListComponent implements ControlValueAccesso | ||
43 | private propagateChange = (v: any) => { }; | 42 | private propagateChange = (v: any) => { }; |
44 | 43 | ||
45 | constructor(private store: Store<AppState>, | 44 | constructor(private store: Store<AppState>, |
46 | - private deviceProfileService: DeviceProfileService, | ||
47 | private fb: FormBuilder) { | 45 | private fb: FormBuilder) { |
48 | this.instancesListFormGroup = this.fb.group({ | 46 | this.instancesListFormGroup = this.fb.group({ |
49 | instanceIdInput: [null, [ | 47 | instanceIdInput: [null, [ |
@@ -17,7 +17,7 @@ | @@ -17,7 +17,7 @@ | ||
17 | --> | 17 | --> |
18 | <form [formGroup]="instancesFormGroup" (ngSubmit)="add()" style="min-width: 400px;"> | 18 | <form [formGroup]="instancesFormGroup" (ngSubmit)="add()" style="min-width: 400px;"> |
19 | <mat-toolbar fxLayout="row" color="primary"> | 19 | <mat-toolbar fxLayout="row" color="primary"> |
20 | - <b><i>{{data.objectName}}</i></b> (object [<b>{{data.objectId}}</b>]) | 20 | + <b><i>{{data.objectName}}</i></b> (object [<b>{{data.objectKeyId}}</b>]) |
21 | <span fxFlex></span> | 21 | <span fxFlex></span> |
22 | <button mat-button mat-icon-button | 22 | <button mat-button mat-icon-button |
23 | (click)="cancel()" | 23 | (click)="cancel()" |
@@ -14,18 +14,18 @@ | @@ -14,18 +14,18 @@ | ||
14 | /// limitations under the License. | 14 | /// limitations under the License. |
15 | /// | 15 | /// |
16 | 16 | ||
17 | -import { Component, Inject, OnInit } from '@angular/core'; | ||
18 | -import { DialogComponent } from '@shared/components/dialog.component'; | ||
19 | -import { FormBuilder, FormGroup } from '@angular/forms'; | ||
20 | -import { Store } from '@ngrx/store'; | ||
21 | -import { AppState } from '@core/core.state'; | ||
22 | -import { Router } from '@angular/router'; | ||
23 | -import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog'; | 17 | +import {Component, Inject, OnInit} from '@angular/core'; |
18 | +import {DialogComponent} from '@shared/components/dialog.component'; | ||
19 | +import {FormBuilder, FormGroup} from '@angular/forms'; | ||
20 | +import {Store} from '@ngrx/store'; | ||
21 | +import {AppState} from '@core/core.state'; | ||
22 | +import {Router} from '@angular/router'; | ||
23 | +import {MAT_DIALOG_DATA, MatDialogRef} from '@angular/material/dialog'; | ||
24 | 24 | ||
25 | export interface Lwm2mObjectAddInstancesData { | 25 | export interface Lwm2mObjectAddInstancesData { |
26 | instancesIds: Set<number>; | 26 | instancesIds: Set<number>; |
27 | objectName?: string; | 27 | objectName?: string; |
28 | - objectId?: number; | 28 | + objectKeyId?: string; |
29 | } | 29 | } |
30 | 30 | ||
31 | @Component({ | 31 | @Component({ |
@@ -40,7 +40,7 @@ | @@ -40,7 +40,7 @@ | ||
40 | class="tb-autocomplete" | 40 | class="tb-autocomplete" |
41 | [displayWith]="displayObjectLwm2mFn"> | 41 | [displayWith]="displayObjectLwm2mFn"> |
42 | <mat-option *ngFor="let objectLwm2m of filteredObjectsList | async" [value]="objectLwm2m"> | 42 | <mat-option *ngFor="let objectLwm2m of filteredObjectsList | async" [value]="objectLwm2m"> |
43 | - <span [innerHTML]="objectLwm2m.id + ': ' + objectLwm2m.name | highlight:searchText"></span> | 43 | + <span [innerHTML]="objectLwm2m.keyId + ': ' + objectLwm2m.name | highlight:searchText"></span> |
44 | </mat-option> | 44 | </mat-option> |
45 | <mat-option *ngIf="!(filteredObjectsList | async)?.length" [value]="null"> | 45 | <mat-option *ngIf="!(filteredObjectsList | async)?.length" [value]="null"> |
46 | <span> | 46 | <span> |
@@ -14,17 +14,18 @@ | @@ -14,17 +14,18 @@ | ||
14 | /// limitations under the License. | 14 | /// limitations under the License. |
15 | /// | 15 | /// |
16 | 16 | ||
17 | -import { Component, ElementRef, EventEmitter, forwardRef, Input, OnInit, Output, ViewChild } from '@angular/core'; | ||
18 | -import { ControlValueAccessor, FormBuilder, FormGroup, NG_VALUE_ACCESSOR, Validators } from '@angular/forms'; | ||
19 | -import { coerceBooleanProperty } from '@angular/cdk/coercion'; | ||
20 | -import { Store } from '@ngrx/store'; | ||
21 | -import { AppState } from '@core/core.state'; | ||
22 | -import { Observable } from 'rxjs'; | ||
23 | -import { filter, map, mergeMap, publishReplay, refCount, tap } from 'rxjs/operators'; | ||
24 | -import { ModelValue, ObjectLwM2M } from './profile-config.models'; | ||
25 | -import { DeviceProfileService } from '@core/http/device-profile.service'; | ||
26 | -import { Direction } from '@shared/models/page/sort-order'; | ||
27 | -import { isDefined, isDefinedAndNotNull, isEmptyStr, isString } from '@core/utils'; | 17 | +import {Component, ElementRef, EventEmitter, forwardRef, Input, OnInit, Output, ViewChild} from '@angular/core'; |
18 | +import {ControlValueAccessor, FormBuilder, FormGroup, NG_VALUE_ACCESSOR, Validators} from '@angular/forms'; | ||
19 | +import {coerceBooleanProperty} from '@angular/cdk/coercion'; | ||
20 | +import {Store} from '@ngrx/store'; | ||
21 | +import {AppState} from '@core/core.state'; | ||
22 | +import {Observable} from 'rxjs'; | ||
23 | +import {filter, map, mergeMap, publishReplay, refCount, tap} from 'rxjs/operators'; | ||
24 | +import {ModelValue, ObjectLwM2M, PAGE_SIZE_LIMIT} from './profile-config.models'; | ||
25 | +import {DeviceProfileService} from '@core/http/device-profile.service'; | ||
26 | +import {Direction} from '@shared/models/page/sort-order'; | ||
27 | +import {isDefined, isDefinedAndNotNull, isString} from '@core/utils'; | ||
28 | +import {PageLink} from "@shared/models/page/page-link"; | ||
28 | 29 | ||
29 | @Component({ | 30 | @Component({ |
30 | selector: 'tb-profile-lwm2m-object-list', | 31 | selector: 'tb-profile-lwm2m-object-list', |
@@ -41,7 +42,7 @@ export class Lwm2mObjectListComponent implements ControlValueAccessor, OnInit, V | @@ -41,7 +42,7 @@ export class Lwm2mObjectListComponent implements ControlValueAccessor, OnInit, V | ||
41 | private requiredValue: boolean; | 42 | private requiredValue: boolean; |
42 | private dirty = false; | 43 | private dirty = false; |
43 | private lw2mModels: Observable<Array<ObjectLwM2M>>; | 44 | private lw2mModels: Observable<Array<ObjectLwM2M>>; |
44 | - private modelValue: Array<number> = []; | 45 | + private modelValue: Array<string> = []; |
45 | 46 | ||
46 | lwm2mListFormGroup: FormGroup; | 47 | lwm2mListFormGroup: FormGroup; |
47 | objectsList: Array<ObjectLwM2M> = []; | 48 | objectsList: Array<ObjectLwM2M> = []; |
@@ -134,8 +135,8 @@ export class Lwm2mObjectListComponent implements ControlValueAccessor, OnInit, V | @@ -134,8 +135,8 @@ export class Lwm2mObjectListComponent implements ControlValueAccessor, OnInit, V | ||
134 | } | 135 | } |
135 | 136 | ||
136 | private add(object: ObjectLwM2M): void { | 137 | private add(object: ObjectLwM2M): void { |
137 | - if (isDefinedAndNotNull(this.modelValue) && this.modelValue.indexOf(object.id) === -1) { | ||
138 | - this.modelValue.push(object.id); | 138 | + if (isDefinedAndNotNull(this.modelValue) && this.modelValue.indexOf(object.keyId) === -1) { |
139 | + this.modelValue.push(object.keyId); | ||
139 | this.objectsList.push(object); | 140 | this.objectsList.push(object); |
140 | this.lwm2mListFormGroup.get('objectsList').setValue(this.objectsList); | 141 | this.lwm2mListFormGroup.get('objectsList').setValue(this.objectsList); |
141 | this.addList.next(this.objectsList); | 142 | this.addList.next(this.objectsList); |
@@ -148,7 +149,7 @@ export class Lwm2mObjectListComponent implements ControlValueAccessor, OnInit, V | @@ -148,7 +149,7 @@ export class Lwm2mObjectListComponent implements ControlValueAccessor, OnInit, V | ||
148 | if (index >= 0) { | 149 | if (index >= 0) { |
149 | this.objectsList.splice(index, 1); | 150 | this.objectsList.splice(index, 1); |
150 | this.lwm2mListFormGroup.get('objectsList').setValue(this.objectsList); | 151 | this.lwm2mListFormGroup.get('objectsList').setValue(this.objectsList); |
151 | - index = this.modelValue.indexOf(object.id); | 152 | + index = this.modelValue.indexOf(object.keyId); |
152 | this.modelValue.splice(index, 1); | 153 | this.modelValue.splice(index, 1); |
153 | this.removeList.next(object); | 154 | this.removeList.next(object); |
154 | this.clear(); | 155 | this.clear(); |
@@ -159,25 +160,29 @@ export class Lwm2mObjectListComponent implements ControlValueAccessor, OnInit, V | @@ -159,25 +160,29 @@ export class Lwm2mObjectListComponent implements ControlValueAccessor, OnInit, V | ||
159 | return object ? object.name : undefined; | 160 | return object ? object.name : undefined; |
160 | } | 161 | } |
161 | 162 | ||
162 | - private fetchListObjects = (searchText?: string): Observable<Array<ObjectLwM2M>> => { | 163 | + private fetchListObjects = (searchText?: string): Observable<Array<ObjectLwM2M>> => { |
163 | this.searchText = searchText; | 164 | this.searchText = searchText; |
164 | - const filters = {names: [], ids: []}; | ||
165 | - if (isDefinedAndNotNull(searchText) && !isEmptyStr(searchText)) { | ||
166 | - const ids = searchText.match(/\d+/g); | ||
167 | - filters.ids = ids !== null ? ids.map(Number) : filters.ids; | ||
168 | - filters.names = searchText.trim().toUpperCase().split(' '); | ||
169 | - } | ||
170 | - const predicate = objectLwM2M => filters.names.find(word => objectLwM2M.name.toUpperCase().includes(word)) | ||
171 | - || filters.ids.includes(objectLwM2M.id); | ||
172 | - return this.getLwM2mModels().pipe( | ||
173 | - map(objectLwM2Ms => searchText ? objectLwM2Ms.filter(predicate) : objectLwM2Ms) | ||
174 | - ); | 165 | + return this.getLwM2mModelsPage().pipe( |
166 | + map(objectLwM2Ms => objectLwM2Ms) | ||
167 | + ); | ||
168 | + } | ||
169 | + | ||
170 | + private getLwM2mModelsPage(): Observable<Array<ObjectLwM2M>> { | ||
171 | + const pageLink = new PageLink(PAGE_SIZE_LIMIT, 0, this.searchText, { | ||
172 | + property: 'id', | ||
173 | + direction: Direction.ASC | ||
174 | + }); | ||
175 | + this.lw2mModels = this.deviceProfileService.getLwm2mObjectsPage(pageLink).pipe( | ||
176 | + publishReplay(1), | ||
177 | + refCount() | ||
178 | + ); | ||
179 | + return this.lw2mModels; | ||
175 | } | 180 | } |
176 | 181 | ||
177 | private getLwM2mModels(): Observable<Array<ObjectLwM2M>> { | 182 | private getLwM2mModels(): Observable<Array<ObjectLwM2M>> { |
178 | if (!this.lw2mModels) { | 183 | if (!this.lw2mModels) { |
179 | const sortOrder = { | 184 | const sortOrder = { |
180 | - property: 'name', | 185 | + property: 'id', |
181 | direction: Direction.ASC | 186 | direction: Direction.ASC |
182 | }; | 187 | }; |
183 | this.lw2mModels = this.deviceProfileService.getLwm2mObjects(sortOrder).pipe( | 188 | this.lw2mModels = this.deviceProfileService.getLwm2mObjects(sortOrder).pipe( |
@@ -22,7 +22,7 @@ | @@ -22,7 +22,7 @@ | ||
22 | [formGroupName]="i"> | 22 | [formGroupName]="i"> |
23 | <mat-expansion-panel-header> | 23 | <mat-expansion-panel-header> |
24 | <mat-panel-title fxLayoutAlign="start center"> | 24 | <mat-panel-title fxLayoutAlign="start center"> |
25 | - <b><i>{{ objectLwM2M.get('name').value}}</i></b> <id: {{ objectLwM2M.get('id').value}}> | 25 | + <b><i>{{ objectLwM2M.get('name').value}}</i></b> <id: {{ objectLwM2M.get('keyId').value}}> |
26 | </mat-panel-title> | 26 | </mat-panel-title> |
27 | <mat-panel-description fxLayoutAlign="end center" *ngIf="!disabled"> | 27 | <mat-panel-description fxLayoutAlign="end center" *ngIf="!disabled"> |
28 | <button type="button" | 28 | <button type="button" |
@@ -15,7 +15,7 @@ | @@ -15,7 +15,7 @@ | ||
15 | /// | 15 | /// |
16 | 16 | ||
17 | 17 | ||
18 | -import { Component, forwardRef, Input } from '@angular/core'; | 18 | +import {Component, forwardRef, Input} from '@angular/core'; |
19 | import { | 19 | import { |
20 | AbstractControl, | 20 | AbstractControl, |
21 | ControlValueAccessor, | 21 | ControlValueAccessor, |
@@ -25,13 +25,13 @@ import { | @@ -25,13 +25,13 @@ import { | ||
25 | NG_VALUE_ACCESSOR, | 25 | NG_VALUE_ACCESSOR, |
26 | Validators | 26 | Validators |
27 | } from '@angular/forms'; | 27 | } from '@angular/forms'; |
28 | -import { Store } from '@ngrx/store'; | ||
29 | -import { AppState } from '@core/core.state'; | ||
30 | -import { coerceBooleanProperty } from '@angular/cdk/coercion'; | ||
31 | -import { CLIENT_LWM2M, Instance, INSTANCES, ObjectLwM2M, ResourceLwM2M, RESOURCES } from './profile-config.models'; | ||
32 | -import { deepClone, isDefinedAndNotNull, isEqual, isUndefined } from '@core/utils'; | ||
33 | -import { MatDialog } from '@angular/material/dialog'; | ||
34 | -import { TranslateService } from '@ngx-translate/core'; | 28 | +import {Store} from '@ngrx/store'; |
29 | +import {AppState} from '@core/core.state'; | ||
30 | +import {coerceBooleanProperty} from '@angular/cdk/coercion'; | ||
31 | +import {CLIENT_LWM2M, Instance, INSTANCES, ObjectLwM2M, ResourceLwM2M, RESOURCES} from './profile-config.models'; | ||
32 | +import {deepClone, isDefinedAndNotNull, isEqual, isUndefined} from '@core/utils'; | ||
33 | +import {MatDialog} from '@angular/material/dialog'; | ||
34 | +import {TranslateService} from '@ngx-translate/core'; | ||
35 | import { | 35 | import { |
36 | Lwm2mObjectAddInstancesComponent, | 36 | Lwm2mObjectAddInstancesComponent, |
37 | Lwm2mObjectAddInstancesData | 37 | Lwm2mObjectAddInstancesData |
@@ -139,7 +139,7 @@ export class Lwm2mObserveAttrTelemetryComponent implements ControlValueAccessor | @@ -139,7 +139,7 @@ export class Lwm2mObserveAttrTelemetryComponent implements ControlValueAccessor | ||
139 | private createObjectsLwM2M = (objectsLwM2M: ObjectLwM2M[]): FormArray => { | 139 | private createObjectsLwM2M = (objectsLwM2M: ObjectLwM2M[]): FormArray => { |
140 | return this.fb.array(objectsLwM2M.map((objectLwM2M) => { | 140 | return this.fb.array(objectsLwM2M.map((objectLwM2M) => { |
141 | return this.fb.group({ | 141 | return this.fb.group({ |
142 | - id: objectLwM2M.id, | 142 | + keyId: objectLwM2M.keyId, |
143 | name: objectLwM2M.name, | 143 | name: objectLwM2M.name, |
144 | multiple: objectLwM2M.multiple, | 144 | multiple: objectLwM2M.multiple, |
145 | mandatory: objectLwM2M.mandatory, | 145 | mandatory: objectLwM2M.mandatory, |
@@ -228,7 +228,7 @@ export class Lwm2mObserveAttrTelemetryComponent implements ControlValueAccessor | @@ -228,7 +228,7 @@ export class Lwm2mObserveAttrTelemetryComponent implements ControlValueAccessor | ||
228 | data: { | 228 | data: { |
229 | instancesIds: this.instancesToSetId(object.instances), | 229 | instancesIds: this.instancesToSetId(object.instances), |
230 | objectName: object.name, | 230 | objectName: object.name, |
231 | - objectId: object.id | 231 | + objectKeyId: object.keyId |
232 | } | 232 | } |
233 | }).afterClosed().subscribe( | 233 | }).afterClosed().subscribe( |
234 | (res: Lwm2mObjectAddInstancesData | undefined) => { | 234 | (res: Lwm2mObjectAddInstancesData | undefined) => { |
@@ -241,7 +241,7 @@ export class Lwm2mObserveAttrTelemetryComponent implements ControlValueAccessor | @@ -241,7 +241,7 @@ export class Lwm2mObserveAttrTelemetryComponent implements ControlValueAccessor | ||
241 | 241 | ||
242 | private updateInstancesIds = (data: Lwm2mObjectAddInstancesData): void => { | 242 | private updateInstancesIds = (data: Lwm2mObjectAddInstancesData): void => { |
243 | const objectLwM2MFormGroup = (this.observeAttrTelemetryFormGroup.get(CLIENT_LWM2M) as FormArray).controls | 243 | const objectLwM2MFormGroup = (this.observeAttrTelemetryFormGroup.get(CLIENT_LWM2M) as FormArray).controls |
244 | - .find(e => e.value.id === data.objectId) as FormGroup; | 244 | + .find(e => e.value.keyId === data.objectKeyId) as FormGroup; |
245 | const instancesArray = objectLwM2MFormGroup.value.instances as Instance []; | 245 | const instancesArray = objectLwM2MFormGroup.value.instances as Instance []; |
246 | const instancesFormArray = objectLwM2MFormGroup.get(INSTANCES) as FormArray; | 246 | const instancesFormArray = objectLwM2MFormGroup.get(INSTANCES) as FormArray; |
247 | const instance0 = deepClone(instancesFormArray.at(0).value as Instance); | 247 | const instance0 = deepClone(instancesFormArray.at(0).value as Instance); |
@@ -14,6 +14,7 @@ | @@ -14,6 +14,7 @@ | ||
14 | /// limitations under the License. | 14 | /// limitations under the License. |
15 | /// | 15 | /// |
16 | 16 | ||
17 | +export const PAGE_SIZE_LIMIT = 50; | ||
17 | export const INSTANCES = 'instances'; | 18 | export const INSTANCES = 'instances'; |
18 | export const RESOURCES = 'resources'; | 19 | export const RESOURCES = 'resources'; |
19 | export const CLIENT_LWM2M = 'clientLwM2M'; | 20 | export const CLIENT_LWM2M = 'clientLwM2M'; |
@@ -58,7 +59,7 @@ export const SECURITY_CONFIG_MODE_NAMES = new Map<SECURITY_CONFIG_MODE, string>( | @@ -58,7 +59,7 @@ export const SECURITY_CONFIG_MODE_NAMES = new Map<SECURITY_CONFIG_MODE, string>( | ||
58 | ); | 59 | ); |
59 | 60 | ||
60 | export interface ModelValue { | 61 | export interface ModelValue { |
61 | - objectIds: number[] | null, | 62 | + objectIds: string[] | null, |
62 | objectsList: ObjectLwM2M[] | 63 | objectsList: ObjectLwM2M[] |
63 | } | 64 | } |
64 | 65 | ||
@@ -190,6 +191,7 @@ export interface Instance { | @@ -190,6 +191,7 @@ export interface Instance { | ||
190 | */ | 191 | */ |
191 | export interface ObjectLwM2M { | 192 | export interface ObjectLwM2M { |
192 | id: number; | 193 | id: number; |
194 | + keyId: string; | ||
193 | name: string; | 195 | name: string; |
194 | multiple?: boolean; | 196 | multiple?: boolean; |
195 | mandatory?: boolean; | 197 | mandatory?: boolean; |