Commit af57637dc5ec4490b0c6c68701ec829dd9e4d488
1 parent
8369429f
lwm2m: notification in transport, add, update, del models
Showing
14 changed files
with
186 additions
and
98 deletions
common/data/src/main/java/org/thingsboard/server/common/data/lwm2m/LwM2mResourceObserve.java
renamed from
common/data/src/main/java/org/thingsboard/server/common/data/lwm2m/LwM2mResource.java
... | ... | @@ -22,7 +22,7 @@ import java.util.stream.Stream; |
22 | 22 | |
23 | 23 | @Data |
24 | 24 | @AllArgsConstructor |
25 | -public class LwM2mResource { | |
25 | +public class LwM2mResourceObserve { | |
26 | 26 | int id; |
27 | 27 | String name; |
28 | 28 | boolean observe; |
... | ... | @@ -30,7 +30,7 @@ public class LwM2mResource { |
30 | 30 | boolean telemetry; |
31 | 31 | String keyName; |
32 | 32 | |
33 | - public LwM2mResource(int id, String name, boolean observe, boolean attribute, boolean telemetry) { | |
33 | + public LwM2mResourceObserve(int id, String name, boolean observe, boolean attribute, boolean telemetry) { | |
34 | 34 | this.id = id; |
35 | 35 | this.name = name; |
36 | 36 | this.observe = observe; | ... | ... |
... | ... | @@ -20,10 +20,11 @@ import io.netty.util.concurrent.GenericFutureListener; |
20 | 20 | import lombok.extern.slf4j.Slf4j; |
21 | 21 | import org.thingsboard.server.common.data.Device; |
22 | 22 | import org.thingsboard.server.common.data.DeviceProfile; |
23 | +import org.thingsboard.server.common.data.ResourceType; | |
23 | 24 | import org.thingsboard.server.common.transport.SessionMsgListener; |
24 | 25 | import org.thingsboard.server.gen.transport.TransportProtos; |
25 | -import org.thingsboard.server.gen.transport.TransportProtos.GetAttributeResponseMsg; | |
26 | 26 | import org.thingsboard.server.gen.transport.TransportProtos.AttributeUpdateNotificationMsg; |
27 | +import org.thingsboard.server.gen.transport.TransportProtos.GetAttributeResponseMsg; | |
27 | 28 | import org.thingsboard.server.gen.transport.TransportProtos.SessionCloseNotificationProto; |
28 | 29 | import org.thingsboard.server.gen.transport.TransportProtos.ToDeviceRpcRequestMsg; |
29 | 30 | import org.thingsboard.server.gen.transport.TransportProtos.ToServerRpcResponseMsg; |
... | ... | @@ -85,4 +86,16 @@ public class LwM2mSessionMsgListener implements GenericFutureListener<Future<? s |
85 | 86 | public void operationComplete(Future<? super Void> future) throws Exception { |
86 | 87 | log.info("[{}] operationComplete", future); |
87 | 88 | } |
89 | + | |
90 | + public void onResourceUpdate(Optional<TransportProtos.ResourceUpdateMsg> resourceUpdateMsgOpt) { | |
91 | + if (ResourceType.LWM2M_MODEL.name().equals(resourceUpdateMsgOpt.get().getResourceType())) { | |
92 | + this.service.onResourceUpdate(resourceUpdateMsgOpt); | |
93 | + } | |
94 | + } | |
95 | + | |
96 | + public void onResourceDelete(Optional<TransportProtos.ResourceDeleteMsg> resourceDeleteMsgOpt) { | |
97 | + if (ResourceType.LWM2M_MODEL.name().equals(resourceDeleteMsgOpt.get().getResourceType())) { | |
98 | + this.service.onResourceDelete(resourceDeleteMsgOpt); | |
99 | + } | |
100 | + } | |
88 | 101 | } | ... | ... |
... | ... | @@ -83,7 +83,7 @@ public class LwM2mTransportRequest { |
83 | 83 | |
84 | 84 | private LwM2mValueConverterImpl converter; |
85 | 85 | |
86 | - private final LwM2mTransportContextServer context; | |
86 | + private final LwM2mTransportContextServer lwM2mTransportContextServer; | |
87 | 87 | |
88 | 88 | private final LwM2mClientContext lwM2mClientContext; |
89 | 89 | |
... | ... | @@ -91,8 +91,8 @@ public class LwM2mTransportRequest { |
91 | 91 | |
92 | 92 | private final LwM2mTransportServiceImpl serviceImpl; |
93 | 93 | |
94 | - public LwM2mTransportRequest(LwM2mTransportContextServer context, LwM2mClientContext lwM2mClientContext, LeshanServer leshanServer, LwM2mTransportServiceImpl serviceImpl) { | |
95 | - this.context = context; | |
94 | + public LwM2mTransportRequest(LwM2mTransportContextServer lwM2mTransportContextServer, LwM2mClientContext lwM2mClientContext, LeshanServer leshanServer, LwM2mTransportServiceImpl serviceImpl) { | |
95 | + this.lwM2mTransportContextServer = lwM2mTransportContextServer; | |
96 | 96 | this.lwM2mClientContext = lwM2mClientContext; |
97 | 97 | this.leshanServer = leshanServer; |
98 | 98 | this.serviceImpl = serviceImpl; |
... | ... | @@ -101,7 +101,7 @@ public class LwM2mTransportRequest { |
101 | 101 | @PostConstruct |
102 | 102 | public void init() { |
103 | 103 | this.converter = LwM2mValueConverterImpl.getInstance(); |
104 | - executorResponse = Executors.newFixedThreadPool(this.context.getLwM2MTransportConfigServer().getRequestPoolSize(), | |
104 | + executorResponse = Executors.newFixedThreadPool(this.lwM2mTransportContextServer.getLwM2MTransportConfigServer().getRequestPoolSize(), | |
105 | 105 | new NamedThreadFactory(String.format("LwM2M %s channel response", RESPONSE_CHANNEL))); |
106 | 106 | } |
107 | 107 | |
... | ... | @@ -120,7 +120,8 @@ public class LwM2mTransportRequest { |
120 | 120 | if (registration != null && resultIds.getObjectId() >= 0) { |
121 | 121 | DownlinkRequest request = null; |
122 | 122 | ContentFormat contentFormat = contentFormatParam != null ? ContentFormat.fromName(contentFormatParam.toUpperCase()) : null; |
123 | - ResourceModel resource = serviceImpl.lwM2mTransportContextServer.getLwM2MTransportConfigServer().getResourceModel(registration, resultIds); | |
123 | + LwM2mClient lwM2MClient = lwM2mClientContext.getLwM2mClientWithReg(registration, null); | |
124 | + ResourceModel resource = lwM2MClient.getResourceModel(target); | |
124 | 125 | timeoutInMs = timeoutInMs > 0 ? timeoutInMs : DEFAULT_TIMEOUT; |
125 | 126 | switch (typeOper) { |
126 | 127 | case GET_TYPE_OPER_READ: |
... | ... | @@ -217,7 +218,10 @@ public class LwM2mTransportRequest { |
217 | 218 | } |
218 | 219 | |
219 | 220 | if (request != null) { |
220 | - this.sendRequest(registration, request, timeoutInMs); | |
221 | + this.sendRequest(registration, lwM2MClient, request, timeoutInMs); | |
222 | + } | |
223 | + else { | |
224 | + log.error("[{}], [{}] - [{}] error SendRequest", registration.getEndpoint(), typeOper, target); | |
221 | 225 | } |
222 | 226 | } |
223 | 227 | } |
... | ... | @@ -230,8 +234,7 @@ public class LwM2mTransportRequest { |
230 | 234 | */ |
231 | 235 | |
232 | 236 | @SuppressWarnings("unchecked") |
233 | - private void sendRequest(Registration registration, DownlinkRequest request, long timeoutInMs) { | |
234 | - LwM2mClient lwM2MClient = lwM2mClientContext.getLwM2mClientWithReg(registration, null); | |
237 | + private void sendRequest(Registration registration, LwM2mClient lwM2MClient, DownlinkRequest request, long timeoutInMs) { | |
235 | 238 | leshanServer.send(registration, request, timeoutInMs, (ResponseCallback<?>) response -> { |
236 | 239 | if (!lwM2MClient.isInit()) { |
237 | 240 | lwM2MClient.initValue(this.serviceImpl, convertToIdVerFromObjectId(request.getPath().toString(), registration)); | ... | ... |
... | ... | @@ -47,6 +47,10 @@ public interface LwM2mTransportService { |
47 | 47 | |
48 | 48 | void onDeviceUpdate(TransportProtos.SessionInfoProto sessionInfo, Device device, Optional<DeviceProfile> deviceProfileOpt); |
49 | 49 | |
50 | + void onResourceUpdate (Optional<TransportProtos.ResourceUpdateMsg> resourceUpdateMsgOpt); | |
51 | + | |
52 | + void onResourceDelete(Optional<TransportProtos.ResourceDeleteMsg> resourceDeleteMsgOpt); | |
53 | + | |
50 | 54 | void doTrigger(Registration registration, String path); |
51 | 55 | |
52 | 56 | void doDisconnect(TransportProtos.SessionInfoProto sessionInfo); | ... | ... |
... | ... | @@ -52,7 +52,6 @@ import org.thingsboard.server.queue.util.TbLwM2mTransportComponent; |
52 | 52 | import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient; |
53 | 53 | import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClientContext; |
54 | 54 | import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClientProfile; |
55 | -import org.thingsboard.server.transport.lwm2m.server.client.ResourceValue; | |
56 | 55 | import org.thingsboard.server.transport.lwm2m.server.client.ResultsAnalyzerParameters; |
57 | 56 | import org.thingsboard.server.transport.lwm2m.utils.LwM2mValueConverterImpl; |
58 | 57 | |
... | ... | @@ -73,9 +72,6 @@ import java.util.concurrent.ConcurrentMap; |
73 | 72 | import java.util.concurrent.ExecutorService; |
74 | 73 | import java.util.concurrent.Executors; |
75 | 74 | import java.util.concurrent.TimeUnit; |
76 | -import java.util.concurrent.locks.Lock; | |
77 | -import java.util.concurrent.locks.ReadWriteLock; | |
78 | -import java.util.concurrent.locks.ReentrantReadWriteLock; | |
79 | 75 | import java.util.stream.Collectors; |
80 | 76 | |
81 | 77 | import static org.thingsboard.server.common.transport.util.JsonUtils.getJsonObject; |
... | ... | @@ -107,8 +103,6 @@ public class LwM2mTransportServiceImpl implements LwM2mTransportService { |
107 | 103 | private ExecutorService executorUpdateRegistered; |
108 | 104 | private ExecutorService executorUnRegistered; |
109 | 105 | private LwM2mValueConverterImpl converter; |
110 | - protected final ReadWriteLock readWriteLock = new ReentrantReadWriteLock(); | |
111 | - protected final Lock writeLock = readWriteLock.writeLock(); | |
112 | 106 | |
113 | 107 | private final TransportService transportService; |
114 | 108 | |
... | ... | @@ -162,7 +156,7 @@ public class LwM2mTransportServiceImpl implements LwM2mTransportService { |
162 | 156 | if (lwM2MClient != null) { |
163 | 157 | SessionInfoProto sessionInfo = this.getValidateSessionInfo(registration); |
164 | 158 | if (sessionInfo != null) { |
165 | - this.initLwM2mClient (lwM2MClient, sessionInfo); | |
159 | + this.initLwM2mClient(lwM2MClient, sessionInfo); | |
166 | 160 | transportService.registerAsyncSession(sessionInfo, new LwM2mSessionMsgListener(this, sessionInfo)); |
167 | 161 | transportService.process(sessionInfo, DefaultTransportService.getSessionEventMsg(SessionEvent.OPEN), null); |
168 | 162 | transportService.process(sessionInfo, TransportProtos.SubscribeToAttributeUpdatesMsg.newBuilder().build(), null); |
... | ... | @@ -223,7 +217,7 @@ public class LwM2mTransportServiceImpl implements LwM2mTransportService { |
223 | 217 | }); |
224 | 218 | } |
225 | 219 | |
226 | - private void initLwM2mClient (LwM2mClient lwM2MClient, SessionInfoProto sessionInfo) { | |
220 | + private void initLwM2mClient(LwM2mClient lwM2MClient, SessionInfoProto sessionInfo) { | |
227 | 221 | lwM2MClient.setDeviceId(new UUID(sessionInfo.getDeviceIdMSB(), sessionInfo.getDeviceIdLSB())); |
228 | 222 | lwM2MClient.setProfileId(new UUID(sessionInfo.getDeviceProfileIdMSB(), sessionInfo.getDeviceProfileIdLSB())); |
229 | 223 | lwM2MClient.setDeviceName(sessionInfo.getDeviceName()); |
... | ... | @@ -309,7 +303,7 @@ public class LwM2mTransportServiceImpl implements LwM2mTransportService { |
309 | 303 | LwM2mClient lwM2MClient = lwM2mClientContext.getLwM2mClient(new UUID(sessionInfo.getSessionIdMSB(), sessionInfo.getSessionIdLSB())); |
310 | 304 | LwM2mClientProfile clientProfile = lwM2mClientContext.getProfile(new UUID(sessionInfo.getDeviceProfileIdMSB(), sessionInfo.getDeviceProfileIdLSB())); |
311 | 305 | if (pathIdVer != null && !pathIdVer.isEmpty() && (this.validatePathInAttrProfile(clientProfile, pathIdVer) || this.validatePathInTelemetryProfile(clientProfile, pathIdVer))) { |
312 | - ResourceModel resourceModel = lwM2mTransportContextServer.getLwM2MTransportConfigServer().getResourceModel(lwM2MClient.getRegistration(), new LwM2mPath(convertToObjectIdFromIdVer(pathIdVer))); | |
306 | + ResourceModel resourceModel = lwM2MClient.getResourceModel(pathIdVer); | |
313 | 307 | if (resourceModel != null && resourceModel.operations.isWritable()) { |
314 | 308 | lwM2mTransportRequest.sendAllRequest(lwM2MClient.getRegistration(), pathIdVer, POST_TYPE_OPER_WRITE_REPLACE, |
315 | 309 | ContentFormat.TLV.getName(), null, value, this.lwM2mTransportContextServer.getLwM2MTransportConfigServer().getTimeout()); |
... | ... | @@ -361,6 +355,26 @@ public class LwM2mTransportServiceImpl implements LwM2mTransportService { |
361 | 355 | } |
362 | 356 | |
363 | 357 | /** |
358 | + * | |
359 | + * @param resourceUpdateMsgOpt - | |
360 | + */ | |
361 | + @Override | |
362 | + public void onResourceUpdate (Optional<TransportProtos.ResourceUpdateMsg> resourceUpdateMsgOpt) { | |
363 | + String idVer = resourceUpdateMsgOpt.get().getResourceKey(); // 19_1.0 | |
364 | + lwM2mClientContext.getLwM2mClients().values().stream().forEach(e -> e.updateResourceModel(idVer, this.lwM2mTransportContextServer.getLwM2MTransportConfigServer().getModelProvider())); | |
365 | + } | |
366 | + | |
367 | + /** | |
368 | + * | |
369 | + * @param resourceDeleteMsgOpt - | |
370 | + */ | |
371 | + @Override | |
372 | + public void onResourceDelete(Optional<TransportProtos.ResourceDeleteMsg> resourceDeleteMsgOpt) { | |
373 | + String pathIdVer = resourceDeleteMsgOpt.get().getResourceKey(); // 19_1.0 | |
374 | + lwM2mClientContext.getLwM2mClients().values().stream().forEach(e -> e.deleteResources(pathIdVer, this.lwM2mTransportContextServer.getLwM2MTransportConfigServer().getModelProvider())); | |
375 | + } | |
376 | + | |
377 | + /** | |
364 | 378 | * Trigger Server path = "/1/0/8" |
365 | 379 | * <p> |
366 | 380 | * Trigger bootStrap path = "/1/0/9" - have to implemented on client |
... | ... | @@ -519,10 +533,14 @@ public class LwM2mTransportServiceImpl implements LwM2mTransportService { |
519 | 533 | */ |
520 | 534 | private void updateResourcesValue(Registration registration, LwM2mResource lwM2mResource, String path) { |
521 | 535 | LwM2mClient lwM2MClient = lwM2mClientContext.getLwM2mClientWithReg(registration, null); |
522 | - lwM2MClient.updateResourceValue(path, lwM2mResource); | |
523 | - Set<String> paths = new HashSet<>(); | |
524 | - paths.add(path); | |
525 | - this.updateAttrTelemetry(registration, paths); | |
536 | + if (lwM2MClient.saveResourceValue(path, lwM2mResource, this.lwM2mTransportContextServer.getLwM2MTransportConfigServer().getModelProvider())) { | |
537 | + Set<String> paths = new HashSet<>(); | |
538 | + paths.add(path); | |
539 | + this.updateAttrTelemetry(registration, paths); | |
540 | + } | |
541 | + else { | |
542 | + log.error("Fail update Resource [{}]", lwM2mResource); | |
543 | + } | |
526 | 544 | } |
527 | 545 | |
528 | 546 | /** |
... | ... | @@ -538,12 +556,9 @@ public class LwM2mTransportServiceImpl implements LwM2mTransportService { |
538 | 556 | JsonObject attributes = new JsonObject(); |
539 | 557 | JsonObject telemetries = new JsonObject(); |
540 | 558 | try { |
541 | - writeLock.lock(); | |
542 | 559 | this.getParametersFromProfile(attributes, telemetries, registration, paths); |
543 | 560 | } catch (Exception e) { |
544 | 561 | log.error("UpdateAttrTelemetry", e); |
545 | - } finally { | |
546 | - writeLock.unlock(); | |
547 | 562 | } |
548 | 563 | if (attributes.getAsJsonObject().entrySet().size() > 0) |
549 | 564 | this.updateParametersOnThingsboard(attributes, DEVICE_ATTRIBUTES_TOPIC, registration); |
... | ... | @@ -558,8 +573,8 @@ public class LwM2mTransportServiceImpl implements LwM2mTransportService { |
558 | 573 | */ |
559 | 574 | private boolean validatePathInAttrProfile(LwM2mClientProfile clientProfile, String path) { |
560 | 575 | try { |
561 | - List<String> attributesSet = new Gson().fromJson(clientProfile.getPostAttributeProfile(), new TypeToken<List<String>>() { | |
562 | - }.getType()); | |
576 | + List<String> attributesSet = new Gson().fromJson(clientProfile.getPostAttributeProfile(), | |
577 | + new TypeToken<List<String>>() {}.getType()); | |
563 | 578 | return attributesSet.stream().anyMatch(p -> p.equals(path)); |
564 | 579 | } catch (Exception e) { |
565 | 580 | log.error("Fail Validate Path [{}] ClientProfile.Attribute", path, e); |
... | ... | @@ -717,9 +732,9 @@ public class LwM2mTransportServiceImpl implements LwM2mTransportService { |
717 | 732 | */ |
718 | 733 | private String getResourceValueToString(LwM2mClient lwM2MClient, String path) { |
719 | 734 | LwM2mPath pathIds = new LwM2mPath(convertToObjectIdFromIdVer(path)); |
720 | - ResourceValue resourceValue = this.returnResourceValueFromLwM2MClient(lwM2MClient, path); | |
735 | + LwM2mResource resourceValue = this.returnResourceValueFromLwM2MClient(lwM2MClient, path); | |
721 | 736 | return resourceValue == null ? null : |
722 | - this.converter.convertValue(resourceValue.getResourceValue(), this.lwM2mTransportContextServer.getLwM2MTransportConfigServer().getResourceModelType(lwM2MClient.getRegistration(), pathIds), ResourceModel.Type.STRING, pathIds).toString(); | |
737 | + this.converter.convertValue(resourceValue.isMultiInstances() ? resourceValue.getValues() : resourceValue.getValue(), resourceValue.getType(), ResourceModel.Type.STRING, pathIds).toString(); | |
723 | 738 | } |
724 | 739 | |
725 | 740 | /** |
... | ... | @@ -727,10 +742,10 @@ public class LwM2mTransportServiceImpl implements LwM2mTransportService { |
727 | 742 | * @param path - |
728 | 743 | * @return - return value of Resource by idPath |
729 | 744 | */ |
730 | - private ResourceValue returnResourceValueFromLwM2MClient(LwM2mClient lwM2MClient, String path) { | |
731 | - ResourceValue resourceValue = null; | |
745 | + private LwM2mResource returnResourceValueFromLwM2MClient(LwM2mClient lwM2MClient, String path) { | |
746 | + LwM2mResource resourceValue = null; | |
732 | 747 | if (new LwM2mPath(convertToObjectIdFromIdVer(path)).isResource()) { |
733 | - resourceValue = lwM2MClient.getResources().get(path); | |
748 | + resourceValue = lwM2MClient.getResources().get(path).getLwM2mResource(); | |
734 | 749 | } |
735 | 750 | return resourceValue; |
736 | 751 | } |
... | ... | @@ -967,9 +982,9 @@ public class LwM2mTransportServiceImpl implements LwM2mTransportService { |
967 | 982 | */ |
968 | 983 | private String getPathAttributeUpdateProfile(TransportProtos.SessionInfoProto sessionInfo, String name) { |
969 | 984 | LwM2mClientProfile profile = lwM2mClientContext.getProfile(new UUID(sessionInfo.getDeviceProfileIdMSB(), sessionInfo.getDeviceProfileIdLSB())); |
970 | - Registration registration = lwM2mClientContext.getLwM2MClient(sessionInfo).getRegistration(); | |
985 | + LwM2mClient lwM2mClient = lwM2mClientContext.getLwM2MClient(sessionInfo); | |
971 | 986 | return profile.getPostKeyNameProfile().getAsJsonObject().entrySet().stream() |
972 | - .filter(e -> e.getValue().getAsString().equals(name) && validateResourceInModel(registration, e.getKey(), false)).findFirst().map(Map.Entry::getKey) | |
987 | + .filter(e -> e.getValue().getAsString().equals(name) && validateResourceInModel(lwM2mClient, e.getKey(), false)).findFirst().map(Map.Entry::getKey) | |
973 | 988 | .orElse(""); |
974 | 989 | } |
975 | 990 | |
... | ... | @@ -1118,7 +1133,7 @@ public class LwM2mTransportServiceImpl implements LwM2mTransportService { |
1118 | 1133 | |
1119 | 1134 | ConcurrentMap<String, String> keyNamesIsWritable = keyNamesMap.entrySet() |
1120 | 1135 | .stream() |
1121 | - .filter(e -> (attrSet.contains(e.getKey()) && validateResourceInModel(lwM2MClient.getRegistration(), e.getKey(), true))) | |
1136 | + .filter(e -> (attrSet.contains(e.getKey()) && validateResourceInModel(lwM2MClient, e.getKey(), true))) | |
1122 | 1137 | .collect(Collectors.toConcurrentMap(Map.Entry::getKey, Map.Entry::getValue)); |
1123 | 1138 | |
1124 | 1139 | Set<String> namesIsWritable = ConcurrentHashMap.newKeySet(); |
... | ... | @@ -1126,13 +1141,12 @@ public class LwM2mTransportServiceImpl implements LwM2mTransportService { |
1126 | 1141 | return new ArrayList<>(namesIsWritable); |
1127 | 1142 | } |
1128 | 1143 | |
1129 | - private boolean validateResourceInModel(Registration registration, String pathKey, boolean isWritable) { | |
1130 | - ResourceModel resourceModel = lwM2mTransportContextServer.getLwM2MTransportConfigServer().getResourceModel(registration, | |
1131 | - new LwM2mPath(convertToObjectIdFromIdVer(pathKey))); | |
1144 | + private boolean validateResourceInModel(LwM2mClient lwM2mClient, String pathKey, boolean isWritable) { | |
1145 | + ResourceModel resourceModel = lwM2mClient.getResourceModel(pathKey); | |
1132 | 1146 | Integer objectId = validateObjectIdFromKey(pathKey); |
1133 | 1147 | String objectVer = validateObjectVerFromKey(pathKey); |
1134 | 1148 | return resourceModel != null && (isWritable ? |
1135 | - objectId != null && objectVer != null && objectVer.equals(registration.getSupportedVersion(objectId)) && resourceModel.operations.isWritable() : | |
1136 | - objectId != null && objectVer != null && objectVer.equals(registration.getSupportedVersion(objectId))); | |
1149 | + objectId != null && objectVer != null && objectVer.equals(lwM2mClient.getRegistration().getSupportedVersion(objectId)) && resourceModel.operations.isWritable() : | |
1150 | + objectId != null && objectVer != null && objectVer.equals(lwM2mClient.getRegistration().getSupportedVersion(objectId))); | |
1137 | 1151 | } |
1138 | 1152 | } | ... | ... |
... | ... | @@ -85,7 +85,7 @@ public class LwM2mVersionedModelProvider implements LwM2mModelProvider { |
85 | 85 | if (objectModel != null) |
86 | 86 | return objectModel.resources.get(resourceId); |
87 | 87 | else |
88 | - log.warn("TbResources (Object model) with id [{}/{}] not found on the server", objectId, resourceId); | |
88 | + log.warn("TbResources (Object model) with id [{}/0/{}] not found on the server", objectId, resourceId); | |
89 | 89 | return null; |
90 | 90 | } catch (Exception e) { |
91 | 91 | log.error("", e); | ... | ... |
... | ... | @@ -17,9 +17,10 @@ package org.thingsboard.server.transport.lwm2m.server.client; |
17 | 17 | |
18 | 18 | import lombok.Data; |
19 | 19 | import lombok.extern.slf4j.Slf4j; |
20 | -import org.eclipse.leshan.core.node.LwM2mMultipleResource; | |
20 | +import org.eclipse.leshan.core.model.ResourceModel; | |
21 | +import org.eclipse.leshan.core.node.LwM2mPath; | |
21 | 22 | import org.eclipse.leshan.core.node.LwM2mResource; |
22 | -import org.eclipse.leshan.core.node.LwM2mSingleResource; | |
23 | +import org.eclipse.leshan.server.model.LwM2mModelProvider; | |
23 | 24 | import org.eclipse.leshan.server.registration.Registration; |
24 | 25 | import org.eclipse.leshan.server.security.SecurityInfo; |
25 | 26 | import org.thingsboard.server.gen.transport.TransportProtos; |
... | ... | @@ -28,9 +29,14 @@ import org.thingsboard.server.transport.lwm2m.server.LwM2mTransportServiceImpl; |
28 | 29 | |
29 | 30 | import java.util.List; |
30 | 31 | import java.util.Map; |
32 | +import java.util.Set; | |
31 | 33 | import java.util.UUID; |
32 | 34 | import java.util.concurrent.ConcurrentHashMap; |
33 | 35 | import java.util.concurrent.CopyOnWriteArrayList; |
36 | +import java.util.stream.Collectors; | |
37 | + | |
38 | +import static org.thingsboard.server.common.data.lwm2m.LwM2mConstants.LWM2M_SEPARATOR_PATH; | |
39 | +import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.convertToObjectIdFromIdVer; | |
34 | 40 | |
35 | 41 | @Slf4j |
36 | 42 | @Data |
... | ... | @@ -67,21 +73,74 @@ public class LwM2mClient implements Cloneable { |
67 | 73 | this.init = false; |
68 | 74 | } |
69 | 75 | |
70 | - public void updateResourceValue(String pathRez, LwM2mResource rez) { | |
71 | - if (rez instanceof LwM2mMultipleResource) { | |
72 | - this.resources.put(pathRez, new ResourceValue(rez.getValues(), null, true)); | |
73 | - } else if (rez instanceof LwM2mSingleResource) { | |
74 | - this.resources.put(pathRez, new ResourceValue(null, rez.getValue(), false)); | |
76 | + public boolean saveResourceValue(String pathRez, LwM2mResource rez, LwM2mModelProvider modelProvider) { | |
77 | + if (this.resources.get(pathRez) != null && this.resources.get(pathRez).getResourceModel() != null) { | |
78 | + this.resources.get(pathRez).setLwM2mResource(rez); | |
79 | + return true; | |
80 | + } else { | |
81 | + LwM2mPath pathIds = new LwM2mPath(convertToObjectIdFromIdVer(pathRez)); | |
82 | + ResourceModel resourceModel = modelProvider.getObjectModel(registration).getResourceModel(pathIds.getObjectId(), pathIds.getResourceId()); | |
83 | + if (resourceModel != null) { | |
84 | + this.resources.put(pathRez, new ResourceValue(rez, resourceModel)); | |
85 | + return true; | |
86 | + } else { | |
87 | + return false; | |
88 | + } | |
89 | + } | |
90 | + } | |
91 | + | |
92 | + public ResourceModel getResourceModel(String pathRez) { | |
93 | + if (this.getResources().get(pathRez) != null) { | |
94 | + return this.getResources().get(pathRez).getResourceModel(); | |
95 | + } else { | |
96 | + return null; | |
75 | 97 | } |
76 | 98 | } |
77 | 99 | |
78 | - public void initValue(LwM2mTransportServiceImpl lwM2MTransportService, String path) { | |
100 | + /** | |
101 | + * | |
102 | + * @param pathIdVer == "3_1.0" | |
103 | + * @param modelProvider - | |
104 | + */ | |
105 | + public void deleteResources(String pathIdVer, LwM2mModelProvider modelProvider) { | |
106 | + Set key = getKeysEqualsIdVer(pathIdVer); | |
107 | + key.forEach(pathRez -> { | |
108 | + LwM2mPath pathIds = new LwM2mPath(convertToObjectIdFromIdVer(pathRez.toString())); | |
109 | + ResourceModel resourceModel = modelProvider.getObjectModel(registration).getResourceModel(pathIds.getObjectId(), pathIds.getResourceId()); | |
110 | + if (resourceModel != null) { | |
111 | + this.resources.get(pathRez).setResourceModel(resourceModel); | |
112 | + } | |
113 | + else { | |
114 | + this.resources.remove(pathRez); | |
115 | + } | |
116 | + }); | |
117 | + } | |
118 | + | |
119 | + public void updateResourceModel(String idVer, LwM2mModelProvider modelProvider) { | |
120 | + Set key = getKeysEqualsIdVer(idVer); | |
121 | + key.forEach(k -> this.saveResourceModel(k.toString(), modelProvider)); | |
122 | + } | |
123 | + | |
124 | + private void saveResourceModel(String pathRez, LwM2mModelProvider modelProvider) { | |
125 | + LwM2mPath pathIds = new LwM2mPath(convertToObjectIdFromIdVer(pathRez)); | |
126 | + ResourceModel resourceModel = modelProvider.getObjectModel(registration).getResourceModel(pathIds.getObjectId(), pathIds.getResourceId()); | |
127 | + this.resources.get(pathRez).setResourceModel(resourceModel); | |
128 | + } | |
129 | + | |
130 | + private Set getKeysEqualsIdVer(String idVer) { | |
131 | + return this.resources.keySet() | |
132 | + .stream() | |
133 | + .filter(e -> idVer.equals(e.split(LWM2M_SEPARATOR_PATH)[1])) | |
134 | + .collect(Collectors.toSet()); | |
135 | + } | |
136 | + | |
137 | + public void initValue(LwM2mTransportServiceImpl serviceImpl, String path) { | |
79 | 138 | if (path != null) { |
80 | 139 | this.pendingRequests.remove(path); |
81 | 140 | } |
82 | 141 | if (this.pendingRequests.size() == 0) { |
83 | 142 | this.init = true; |
84 | - lwM2MTransportService.putDelayedUpdateResourcesThingsboard(this); | |
143 | + serviceImpl.putDelayedUpdateResourcesThingsboard(this); | |
85 | 144 | } |
86 | 145 | } |
87 | 146 | ... | ... |
... | ... | @@ -34,25 +34,25 @@ public class LwM2mClientProfile { |
34 | 34 | |
35 | 35 | /** |
36 | 36 | * {"keyName": { |
37 | - * "/3/0/1": "modelNumber", | |
38 | - * "/3/0/0": "manufacturer", | |
39 | - * "/3/0/2": "serialNumber" | |
37 | + * "/3_1.0/0/1": "modelNumber", | |
38 | + * "/3_1.0/0/0": "manufacturer", | |
39 | + * "/3_1.0/0/2": "serialNumber" | |
40 | 40 | * } |
41 | 41 | **/ |
42 | 42 | private JsonObject postKeyNameProfile; |
43 | 43 | |
44 | 44 | /** |
45 | - * [ "/2/0/0", "/2/0/1"] | |
45 | + * [ "/3_1.0/0/0", "/3_1.0/0/1"] | |
46 | 46 | */ |
47 | 47 | private JsonArray postAttributeProfile; |
48 | 48 | |
49 | 49 | /** |
50 | - * [ "/2/0/0", "/2/0/1"] | |
50 | + * [ "/3_1.0/0/0", "/3_1.0/0/2"] | |
51 | 51 | */ |
52 | 52 | private JsonArray postTelemetryProfile; |
53 | 53 | |
54 | 54 | /** |
55 | - * [ "/2/0/0", "/2/0/1"] | |
55 | + * [ "/3_1.0/0", "/3_1.0/0/1, "/3_1.0/0/2"] | |
56 | 56 | */ |
57 | 57 | private JsonArray postObserveProfile; |
58 | 58 | ... | ... |
... | ... | @@ -16,23 +16,16 @@ |
16 | 16 | package org.thingsboard.server.transport.lwm2m.server.client; |
17 | 17 | |
18 | 18 | import lombok.Data; |
19 | - | |
20 | -import java.util.Map; | |
19 | +import org.eclipse.leshan.core.model.ResourceModel; | |
20 | +import org.eclipse.leshan.core.node.LwM2mResource; | |
21 | 21 | |
22 | 22 | @Data |
23 | 23 | public class ResourceValue { |
24 | - Map<Integer, ?> values; | |
25 | - Object value; | |
26 | - boolean multiInstances; | |
27 | - | |
28 | - public ResourceValue(Map<Integer, ?> values, Object value, boolean multiInstances) { | |
29 | - this.values = values; | |
30 | - this.value = value; | |
31 | - this.multiInstances = multiInstances; | |
32 | - } | |
24 | + private LwM2mResource lwM2mResource; | |
25 | + private ResourceModel resourceModel; | |
33 | 26 | |
34 | - public Object getResourceValue() { | |
35 | - return this.multiInstances ? this.values : this.value; | |
27 | + public ResourceValue(LwM2mResource lwM2mResource, ResourceModel resourceModel) { | |
28 | + this.lwM2mResource = lwM2mResource; | |
29 | + this.resourceModel = resourceModel; | |
36 | 30 | } |
37 | - | |
38 | 31 | } | ... | ... |
... | ... | @@ -18,11 +18,11 @@ package org.thingsboard.server.common.transport; |
18 | 18 | import org.thingsboard.server.common.data.Device; |
19 | 19 | import org.thingsboard.server.common.data.DeviceProfile; |
20 | 20 | import org.thingsboard.server.gen.transport.TransportProtos; |
21 | -import org.thingsboard.server.gen.transport.TransportProtos.ToServerRpcResponseMsg; | |
22 | 21 | import org.thingsboard.server.gen.transport.TransportProtos.AttributeUpdateNotificationMsg; |
23 | 22 | import org.thingsboard.server.gen.transport.TransportProtos.GetAttributeResponseMsg; |
24 | 23 | import org.thingsboard.server.gen.transport.TransportProtos.SessionCloseNotificationProto; |
25 | 24 | import org.thingsboard.server.gen.transport.TransportProtos.ToDeviceRpcRequestMsg; |
25 | +import org.thingsboard.server.gen.transport.TransportProtos.ToServerRpcResponseMsg; | |
26 | 26 | import org.thingsboard.server.gen.transport.TransportProtos.ToTransportUpdateCredentialsProto; |
27 | 27 | |
28 | 28 | import java.util.Optional; |
... | ... | @@ -44,9 +44,12 @@ public interface SessionMsgListener { |
44 | 44 | |
45 | 45 | default void onToTransportUpdateCredentials(ToTransportUpdateCredentialsProto toTransportUpdateCredentials){} |
46 | 46 | |
47 | - default void onDeviceProfileUpdate(TransportProtos.SessionInfoProto newSessionInfo, DeviceProfile deviceProfile) { | |
48 | - } | |
47 | + default void onDeviceProfileUpdate(TransportProtos.SessionInfoProto newSessionInfo, DeviceProfile deviceProfile) {} | |
48 | + | |
49 | + default void onDeviceUpdate(TransportProtos.SessionInfoProto sessionInfo, Device device, | |
50 | + Optional<DeviceProfile> deviceProfileOpt) {} | |
51 | + | |
52 | + default void onResourceUpdate(Optional<TransportProtos.ResourceUpdateMsg> resourceUpdateMsgOpt) {} | |
49 | 53 | |
50 | - default void onDeviceUpdate(TransportProtos.SessionInfoProto sessionInfo, Device device, Optional<DeviceProfile> deviceProfileOpt) { | |
51 | - } | |
54 | + default void onResourceDelete(Optional<TransportProtos.ResourceDeleteMsg> resourceUpdateMsgOpt) {} | |
52 | 55 | } | ... | ... |
... | ... | @@ -18,10 +18,7 @@ package org.thingsboard.server.common.transport.lwm2m; |
18 | 18 | import lombok.Getter; |
19 | 19 | import lombok.Setter; |
20 | 20 | import lombok.extern.slf4j.Slf4j; |
21 | -import org.eclipse.leshan.core.model.ResourceModel; | |
22 | -import org.eclipse.leshan.core.node.LwM2mPath; | |
23 | 21 | import org.eclipse.leshan.server.model.LwM2mModelProvider; |
24 | -import org.eclipse.leshan.server.registration.Registration; | |
25 | 22 | import org.springframework.beans.factory.annotation.Value; |
26 | 23 | import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; |
27 | 24 | import org.springframework.stereotype.Component; |
... | ... | @@ -219,13 +216,4 @@ public class LwM2MTransportConfigServer { |
219 | 216 | } |
220 | 217 | return FULL_FILE_PATH.toUri().getPath(); |
221 | 218 | } |
222 | - | |
223 | - public ResourceModel getResourceModel(Registration registration, LwM2mPath pathIds) { | |
224 | - return this.modelProvider.getObjectModel(registration).getResourceModel(pathIds.getObjectId(), pathIds.getResourceId()); | |
225 | - } | |
226 | - | |
227 | - public ResourceModel.Type getResourceModelType(Registration registration, LwM2mPath pathIds) { | |
228 | - ResourceModel resource = this.getResourceModel(registration, pathIds); | |
229 | - return (resource == null) ? null : resource.type; | |
230 | - } | |
231 | 219 | } | ... | ... |
... | ... | @@ -288,7 +288,7 @@ public class DefaultTransportService implements TransportService { |
288 | 288 | } |
289 | 289 | |
290 | 290 | @Override |
291 | - public void process(TransportProtos.ValidateDeviceLwM2MCredentialsRequestMsg msg, TransportServiceCallback<TransportProtos.ValidateDeviceCredentialsResponseMsg> callback) { | |
291 | + public void process(TransportProtos.ValidateDeviceLwM2MCredentialsRequestMsg msg, TransportServiceCallback<TransportProtos.ValidateDeviceCredentialsResponseMsg> callback) { | |
292 | 292 | log.trace("Processing msg: {}", msg); |
293 | 293 | TbProtoQueueMsg<TransportApiRequestMsg> protoMsg = new TbProtoQueueMsg<>(UUID.randomUUID(), TransportApiRequestMsg.newBuilder().setValidateDeviceLwM2MCredentialsRequestMsg(msg).build()); |
294 | 294 | AsyncCallbackTemplate.withCallback(transportApiRequestTemplate.send(protoMsg), |
... | ... | @@ -710,12 +710,21 @@ public class DefaultTransportService implements TransportService { |
710 | 710 | ResourceType resourceType = ResourceType.valueOf(msg.getResourceType()); |
711 | 711 | String resourceId = msg.getResourceKey(); |
712 | 712 | transportResourceCache.update(tenantId, resourceType, resourceId); |
713 | + sessions.forEach((id, mdRez) -> { | |
714 | + log.warn("ResourceUpdate - [{}] [{}]", id, mdRez); | |
715 | + transportCallbackExecutor.submit(() -> mdRez.getListener().onResourceUpdate(Optional.ofNullable(msg))); | |
716 | + }); | |
717 | + | |
713 | 718 | } else if (toSessionMsg.hasResourceDeleteMsg()) { |
714 | 719 | TransportProtos.ResourceDeleteMsg msg = toSessionMsg.getResourceDeleteMsg(); |
715 | 720 | TenantId tenantId = new TenantId(new UUID(msg.getTenantIdMSB(), msg.getTenantIdLSB())); |
716 | 721 | ResourceType resourceType = ResourceType.valueOf(msg.getResourceType()); |
717 | 722 | String resourceId = msg.getResourceKey(); |
718 | 723 | transportResourceCache.evict(tenantId, resourceType, resourceId); |
724 | + sessions.forEach((id, mdRez) -> { | |
725 | + log.warn("ResourceDelete - [{}] [{}]", id, mdRez); | |
726 | + transportCallbackExecutor.submit(() -> mdRez.getListener().onResourceDelete(Optional.ofNullable(msg))); | |
727 | + }); | |
719 | 728 | } else { |
720 | 729 | //TODO: should we notify the device actor about missed session? |
721 | 730 | log.debug("[{}] Missing session.", sessionId); |
... | ... | @@ -827,7 +836,7 @@ public class DefaultTransportService implements TransportService { |
827 | 836 | } |
828 | 837 | |
829 | 838 | private void sendToRuleEngine(TenantId tenantId, DeviceId deviceId, TransportProtos.SessionInfoProto sessionInfo, JsonObject json, |
830 | - TbMsgMetaData metaData, SessionMsgType sessionMsgType, TbQueueCallback callback) { | |
839 | + TbMsgMetaData metaData, SessionMsgType sessionMsgType, TbQueueCallback callback) { | |
831 | 840 | DeviceProfileId deviceProfileId = new DeviceProfileId(new UUID(sessionInfo.getDeviceProfileIdMSB(), sessionInfo.getDeviceProfileIdLSB())); |
832 | 841 | DeviceProfile deviceProfile = deviceProfileCache.get(deviceProfileId); |
833 | 842 | RuleChainId ruleChainId; | ... | ... |
... | ... | @@ -31,7 +31,7 @@ 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; |
33 | 33 | import org.thingsboard.server.common.data.lwm2m.LwM2mObject; |
34 | -import org.thingsboard.server.common.data.lwm2m.LwM2mResource; | |
34 | +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; |
... | ... | @@ -87,7 +87,9 @@ public class BaseTbResourceService implements TbResourceService { |
87 | 87 | String resourceKey = objectModel.id + LWM2M_SEPARATOR_KEY + objectModel.getVersion(); |
88 | 88 | String name = objectModel.name; |
89 | 89 | resource.setResourceKey(resourceKey); |
90 | - resource.setTitle(name + " id=" +objectModel.id + " v" + objectModel.getVersion()); | |
90 | + if (resource.getId() == null) { | |
91 | + resource.setTitle(name + " id=" + objectModel.id + " v" + objectModel.getVersion()); | |
92 | + } | |
91 | 93 | resource.setSearchText(resourceKey + LWM2M_SEPARATOR_SEARCH_TEXT + name); |
92 | 94 | } else { |
93 | 95 | throw new DataValidationException(String.format("Could not parse the XML of objectModel with name %s", resource.getSearchText())); |
... | ... | @@ -205,14 +207,14 @@ public class BaseTbResourceService implements TbResourceService { |
205 | 207 | lwM2mObject.setMandatory(obj.mandatory); |
206 | 208 | LwM2mInstance instance = new LwM2mInstance(); |
207 | 209 | instance.setId(0); |
208 | - List<LwM2mResource> resources = new ArrayList<>(); | |
210 | + List<LwM2mResourceObserve> resources = new ArrayList<>(); | |
209 | 211 | obj.resources.forEach((k, v) -> { |
210 | 212 | if (!v.operations.isExecutable()) { |
211 | - LwM2mResource lwM2mResource = new LwM2mResource(k, v.name, false, false, false); | |
212 | - resources.add(lwM2mResource); | |
213 | + LwM2mResourceObserve lwM2MResourceObserve = new LwM2mResourceObserve(k, v.name, false, false, false); | |
214 | + resources.add(lwM2MResourceObserve); | |
213 | 215 | } |
214 | 216 | }); |
215 | - instance.setResources(resources.toArray(LwM2mResource[]::new)); | |
217 | + instance.setResources(resources.toArray(LwM2mResourceObserve[]::new)); | |
216 | 218 | lwM2mObject.setInstances(new LwM2mInstance[]{instance}); |
217 | 219 | return lwM2mObject; |
218 | 220 | } | ... | ... |