Commit af57637dc5ec4490b0c6c68701ec829dd9e4d488

Authored by nickAS21
1 parent 8369429f

lwm2m: notification in transport, add, update, del models

Showing 14 changed files with 186 additions and 98 deletions
... ... @@ -20,6 +20,6 @@ import lombok.Data;
20 20 @Data
21 21 public class LwM2mInstance {
22 22 int id;
23   - LwM2mResource [] resources;
  23 + LwM2mResourceObserve[] resources;
24 24
25 25 }
... ...
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 }
... ...