Commit 5f8a9e9f679f7f333a10bbabd51b22d519207144

Authored by nickAS21
Committed by GitHub
1 parent c350fb7a

Lwm2m rpc (#4473)

* Lwm2m: RPC_terminal

* Lwm2m: RPC_terminal del two file

* Lwm2m: RPC_terminal add test observe

* Lwm2m: RPC_terminal add test delete
Showing 13 changed files with 723 additions and 378 deletions
... ... @@ -35,7 +35,7 @@ import org.thingsboard.server.transport.lwm2m.secure.LwM2mCredentialsSecurityInf
35 35 import org.thingsboard.server.transport.lwm2m.secure.ReadResultSecurityStore;
36 36 import org.thingsboard.server.transport.lwm2m.server.LwM2mSessionMsgListener;
37 37 import org.thingsboard.server.transport.lwm2m.server.LwM2mTransportContextServer;
38   -import org.thingsboard.server.transport.lwm2m.utils.TypeServer;
  38 +import org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler;
39 39
40 40 import java.io.IOException;
41 41 import java.security.GeneralSecurityException;
... ... @@ -69,7 +69,7 @@ public class LwM2MBootstrapSecurityStore implements BootstrapSecurityStore {
69 69
70 70 @Override
71 71 public List<SecurityInfo> getAllByEndpoint(String endPoint) {
72   - ReadResultSecurityStore store = lwM2MCredentialsSecurityInfoValidator.createAndValidateCredentialsSecurityInfo(endPoint, TypeServer.BOOTSTRAP);
  72 + ReadResultSecurityStore store = lwM2MCredentialsSecurityInfoValidator.createAndValidateCredentialsSecurityInfo(endPoint, LwM2mTransportHandler.LwM2mTypeServer.BOOTSTRAP);
73 73 if (store.getBootstrapJsonCredential() != null && store.getSecurityMode() < LwM2MSecurityMode.DEFAULT_MODE.code) {
74 74 /** add value to store from BootstrapJson */
75 75 this.setBootstrapConfigScurityInfo(store);
... ... @@ -93,7 +93,7 @@ public class LwM2MBootstrapSecurityStore implements BootstrapSecurityStore {
93 93
94 94 @Override
95 95 public SecurityInfo getByIdentity(String identity) {
96   - ReadResultSecurityStore store = lwM2MCredentialsSecurityInfoValidator.createAndValidateCredentialsSecurityInfo(identity, TypeServer.BOOTSTRAP);
  96 + ReadResultSecurityStore store = lwM2MCredentialsSecurityInfoValidator.createAndValidateCredentialsSecurityInfo(identity, LwM2mTransportHandler.LwM2mTypeServer.BOOTSTRAP);
97 97 if (store.getBootstrapJsonCredential() != null && store.getSecurityMode() < LwM2MSecurityMode.DEFAULT_MODE.code) {
98 98 /** add value to store from BootstrapJson */
99 99 this.setBootstrapConfigScurityInfo(store);
... ...
... ... @@ -28,7 +28,6 @@ import org.thingsboard.server.gen.transport.TransportProtos.ValidateDeviceLwM2MC
28 28 import org.thingsboard.server.queue.util.TbLwM2mTransportComponent;
29 29 import org.thingsboard.server.transport.lwm2m.server.LwM2mTransportContextServer;
30 30 import org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler;
31   -import org.thingsboard.server.transport.lwm2m.utils.TypeServer;
32 31
33 32 import java.io.IOException;
34 33 import java.security.GeneralSecurityException;
... ... @@ -59,7 +58,7 @@ public class LwM2mCredentialsSecurityInfoValidator {
59 58 * @param keyValue -
60 59 * @return ValidateDeviceCredentialsResponseMsg and SecurityInfo
61 60 */
62   - public ReadResultSecurityStore createAndValidateCredentialsSecurityInfo(String endpoint, TypeServer keyValue) {
  61 + public ReadResultSecurityStore createAndValidateCredentialsSecurityInfo(String endpoint, LwM2mTransportHandler.LwM2mTypeServer keyValue) {
63 62 CountDownLatch latch = new CountDownLatch(1);
64 63 final ReadResultSecurityStore[] resultSecurityStore = new ReadResultSecurityStore[1];
65 64 contextS.getTransportService().process(ValidateDeviceLwM2MCredentialsRequestMsg.newBuilder().setCredentialsId(endpoint).build(),
... ... @@ -96,7 +95,7 @@ public class LwM2mCredentialsSecurityInfoValidator {
96 95 * @param keyValue -
97 96 * @return SecurityInfo
98 97 */
99   - private ReadResultSecurityStore createSecurityInfo(String endPoint, String jsonStr, TypeServer keyValue) {
  98 + private ReadResultSecurityStore createSecurityInfo(String endPoint, String jsonStr, LwM2mTransportHandler.LwM2mTypeServer keyValue) {
100 99 ReadResultSecurityStore result = new ReadResultSecurityStore();
101 100 JsonObject objectMsg = LwM2mTransportHandler.validateJson(jsonStr);
102 101 if (objectMsg != null && !objectMsg.isJsonNull()) {
... ... @@ -109,7 +108,7 @@ public class LwM2mCredentialsSecurityInfoValidator {
109 108 && objectMsg.get("client").getAsJsonObject().get("endpoint").isJsonPrimitive()) ? objectMsg.get("client").getAsJsonObject().get("endpoint").getAsString() : null;
110 109 endPoint = (endPointPsk == null || endPointPsk.isEmpty()) ? endPoint : endPointPsk;
111 110 if (object != null && !object.isJsonNull()) {
112   - if (keyValue.equals(TypeServer.BOOTSTRAP)) {
  111 + if (keyValue.equals(LwM2mTransportHandler.LwM2mTypeServer.BOOTSTRAP)) {
113 112 result.setBootstrapJsonCredential(object);
114 113 result.setEndPoint(endPoint);
115 114 result.setSecurityMode(LwM2MSecurityMode.fromSecurityMode(object.get("bootstrapServer").getAsJsonObject().get("securityMode").getAsString().toLowerCase()).code);
... ...
... ... @@ -92,7 +92,8 @@ public class LwM2mServerListener {
92 92 public void onResponse(Observation observation, Registration registration, ObserveResponse response) {
93 93 if (registration != null) {
94 94 try {
95   - service.onObservationResponse(registration, convertPathFromObjectIdToIdVer(observation.getPath().toString(), registration), response);
  95 + service.onObservationResponse(registration, convertPathFromObjectIdToIdVer(observation.getPath().toString(),
  96 + registration), response, null);
96 97 } catch (Exception e) {
97 98 log.error("[{}] onResponse", e.toString());
98 99
... ...
... ... @@ -75,7 +75,7 @@ public class LwM2mSessionMsgListener implements GenericFutureListener<Future<? s
75 75
76 76 @Override
77 77 public void onToDeviceRpcRequest(ToDeviceRpcRequestMsg toDeviceRequest) {
78   - this.service.onToDeviceRpcRequest(toDeviceRequest);
  78 + this.service.onToDeviceRpcRequest(toDeviceRequest,this.sessionInfo);
79 79 }
80 80
81 81 @Override
... ...
... ... @@ -16,9 +16,13 @@
16 16 package org.thingsboard.server.transport.lwm2m.server;
17 17
18 18 import com.fasterxml.jackson.databind.ObjectMapper;
  19 +import com.google.common.collect.Sets;
  20 +import com.google.gson.Gson;
  21 +import com.google.gson.JsonArray;
19 22 import com.google.gson.JsonObject;
20 23 import com.google.gson.JsonParser;
21 24 import com.google.gson.JsonSyntaxException;
  25 +import com.google.gson.reflect.TypeToken;
22 26 import lombok.extern.slf4j.Slf4j;
23 27 import org.apache.commons.lang3.StringUtils;
24 28 import org.eclipse.californium.core.network.config.NetworkConfig;
... ... @@ -26,7 +30,12 @@ import org.eclipse.leshan.core.attributes.Attribute;
26 30 import org.eclipse.leshan.core.attributes.AttributeSet;
27 31 import org.eclipse.leshan.core.model.ObjectModel;
28 32 import org.eclipse.leshan.core.model.ResourceModel;
  33 +import org.eclipse.leshan.core.node.LwM2mMultipleResource;
  34 +import org.eclipse.leshan.core.node.LwM2mNode;
  35 +import org.eclipse.leshan.core.node.LwM2mObject;
  36 +import org.eclipse.leshan.core.node.LwM2mObjectInstance;
29 37 import org.eclipse.leshan.core.node.LwM2mPath;
  38 +import org.eclipse.leshan.core.node.LwM2mSingleResource;
30 39 import org.eclipse.leshan.core.node.codec.CodecException;
31 40 import org.eclipse.leshan.core.request.DownlinkRequest;
32 41 import org.eclipse.leshan.core.request.WriteAttributesRequest;
... ... @@ -50,6 +59,7 @@ import java.util.LinkedList;
50 59 import java.util.List;
51 60 import java.util.Map;
52 61 import java.util.Optional;
  62 +import java.util.Set;
53 63 import java.util.concurrent.ConcurrentHashMap;
54 64
55 65 import static org.eclipse.leshan.core.attributes.Attribute.DIMENSION;
... ... @@ -62,8 +72,8 @@ import static org.thingsboard.server.common.data.lwm2m.LwM2mConstants.LWM2M_SEPA
62 72 @Slf4j
63 73 public class LwM2mTransportHandler {
64 74
65   - public static final String BASE_DEVICE_API_TOPIC = "v1/devices/me";
66   -
  75 + // public static final String BASE_DEVICE_API_TOPIC = "v1/devices/me";
  76 + public static final String TRANSPORT_DEFAULT_LWM2M_VERSION = "1.0";
67 77 public static final String CLIENT_LWM2M_SETTINGS = "clientLwM2mSettings";
68 78 public static final String BOOTSTRAP = "bootstrap";
69 79 public static final String SERVERS = "servers";
... ... @@ -73,21 +83,21 @@ public class LwM2mTransportHandler {
73 83 public static final String ATTRIBUTE = "attribute";
74 84 public static final String TELEMETRY = "telemetry";
75 85 public static final String KEY_NAME = "keyName";
76   - public static final String OBSERVE = "observe";
  86 + public static final String OBSERVE_LWM2M = "observe";
77 87 public static final String ATTRIBUTE_LWM2M = "attributeLwm2m";
78   - public static final String RESOURCE_VALUE = "resValue";
79   - public static final String RESOURCE_TYPE = "resType";
  88 +// public static final String RESOURCE_VALUE = "resValue";
  89 +// public static final String RESOURCE_TYPE = "resType";
80 90
81 91 private static final String REQUEST = "/request";
82   - private static final String RESPONSE = "/response";
  92 + // private static final String RESPONSE = "/response";
83 93 private static final String ATTRIBUTES = "/" + ATTRIBUTE;
84 94 public static final String TELEMETRIES = "/" + TELEMETRY;
85   - public static final String ATTRIBUTES_RESPONSE = ATTRIBUTES + RESPONSE;
  95 + // public static final String ATTRIBUTES_RESPONSE = ATTRIBUTES + RESPONSE;
86 96 public static final String ATTRIBUTES_REQUEST = ATTRIBUTES + REQUEST;
87   - public static final String DEVICE_ATTRIBUTES_RESPONSE = ATTRIBUTES_RESPONSE + "/";
  97 + // public static final String DEVICE_ATTRIBUTES_RESPONSE = ATTRIBUTES_RESPONSE + "/";
88 98 public static final String DEVICE_ATTRIBUTES_REQUEST = ATTRIBUTES_REQUEST + "/";
89   - public static final String DEVICE_ATTRIBUTES_TOPIC = BASE_DEVICE_API_TOPIC + ATTRIBUTES;
90   - public static final String DEVICE_TELEMETRY_TOPIC = BASE_DEVICE_API_TOPIC + TELEMETRIES;
  99 +// public static final String DEVICE_ATTRIBUTES_TOPIC = BASE_DEVICE_API_TOPIC + ATTRIBUTES;
  100 +// public static final String DEVICE_TELEMETRY_TOPIC = BASE_DEVICE_API_TOPIC + TELEMETRIES;
91 101
92 102 public static final long DEFAULT_TIMEOUT = 2 * 60 * 1000L; // 2min in ms
93 103
... ... @@ -95,30 +105,86 @@ public class LwM2mTransportHandler {
95 105 public static final String LOG_LW2M_INFO = "info";
96 106 public static final String LOG_LW2M_ERROR = "error";
97 107 public static final String LOG_LW2M_WARN = "warn";
  108 + public static final String LOG_LW2M_VALUE = "value";
98 109
99 110 public static final int LWM2M_STRATEGY_1 = 1;
100 111 public static final int LWM2M_STRATEGY_2 = 2;
101 112
102 113 public static final String CLIENT_NOT_AUTHORIZED = "Client not authorized";
103 114
104   - public static final String GET_TYPE_OPER_READ = "read";
105   - public static final String GET_TYPE_OPER_DISCOVER = "discover";
106   - public static final String GET_TYPE_OPER_OBSERVE = "observe";
107   - public static final String POST_TYPE_OPER_OBSERVE_CANCEL = "observeCancel";
108   - public static final String POST_TYPE_OPER_EXECUTE = "execute";
109   - /**
110   - * Replaces the Object Instance or the Resource(s) with the new value provided in the “Write” operation. (see
111   - * section 5.3.3 of the LW M2M spec).
112   - * if all resources are to be replaced
113   - */
114   - public static final String POST_TYPE_OPER_WRITE_REPLACE = "replace";
  115 + public enum LwM2mTypeServer {
  116 + BOOTSTRAP(0, "bootstrap"),
  117 + CLIENT(1, "client");
  118 +
  119 + public int code;
  120 + public String type;
  121 +
  122 + LwM2mTypeServer(int code, String type) {
  123 + this.code = code;
  124 + this.type = type;
  125 + }
  126 +
  127 + public static LwM2mTypeServer fromLwM2mTypeServer(String type) {
  128 + for (LwM2mTypeServer sm : LwM2mTypeServer.values()) {
  129 + if (sm.type.equals(type)) {
  130 + return sm;
  131 + }
  132 + }
  133 + throw new IllegalArgumentException(String.format("Unsupported typeServer type : %d", type));
  134 + }
  135 + }
  136 +
115 137 /**
116   - * Adds or updates Resources provided in the new value and leaves other existing Resources unchanged. (see section
117   - * 5.3.3 of the LW M2M spec).
118   - * if this is a partial update request
  138 + * Define the behavior of a write request.
119 139 */
120   - public static final String PUT_TYPE_OPER_WRITE_UPDATE = "update";
121   - public static final String PUT_TYPE_OPER_WRITE_ATTRIBUTES = "wright-attributes";
  140 + public enum LwM2mTypeOper {
  141 + /**
  142 + * GET
  143 + */
  144 + READ(0, "Read"),
  145 + DISCOVER(1, "Discover"),
  146 + OBSERVE_READ_ALL(2, "ObserveReadAll"),
  147 + /**
  148 + * POST
  149 + */
  150 + OBSERVE(3, "Observe"),
  151 + OBSERVE_CANCEL(4, "ObserveCancel"),
  152 + EXECUTE(5, "Execute"),
  153 + /**
  154 + * Replaces the Object Instance or the Resource(s) with the new value provided in the “Write” operation. (see
  155 + * section 5.3.3 of the LW M2M spec).
  156 + * if all resources are to be replaced
  157 + */
  158 + WRITE_REPLACE(6, "WriteReplace"),
  159 + /**
  160 + * PUT
  161 + */
  162 + /**
  163 + * Adds or updates Resources provided in the new value and leaves other existing Resources unchanged. (see section
  164 + * 5.3.3 of the LW M2M spec).
  165 + * if this is a partial update request
  166 + */
  167 + WRITE_UPDATE(7, "WriteUpdate"),
  168 + WRITE_ATTRIBUTES(8, "WriteAttributes"),
  169 + DELETE(9, "Delete");
  170 +
  171 + public int code;
  172 + public String type;
  173 +
  174 + LwM2mTypeOper(int code, String type) {
  175 + this.code = code;
  176 + this.type = type;
  177 + }
  178 +
  179 + public static LwM2mTypeOper fromLwLwM2mTypeOper(String type) {
  180 + for (LwM2mTypeOper to : LwM2mTypeOper.values()) {
  181 + if (to.type.equals(type)) {
  182 + return to;
  183 + }
  184 + }
  185 + throw new IllegalArgumentException(String.format("Unsupported typeOper type : %d", type));
  186 + }
  187 + }
122 188
123 189 public static final String EVENT_AWAKE = "AWAKE";
124 190 public static final String SERVICE_CHANNEL = "SERVICE";
... ... @@ -156,19 +222,20 @@ public class LwM2mTransportHandler {
156 222 throw new CodecException("Invalid value type for resource %s, type %s", resourcePath, type);
157 223 }
158 224 }
159   -//
160   -// public static LwM2mNode getLvM2mNodeToObject(LwM2mNode content) {
161   -// if (content instanceof LwM2mObject) {
162   -// return (LwM2mObject) content;
163   -// } else if (content instanceof LwM2mObjectInstance) {
164   -// return (LwM2mObjectInstance) content;
165   -// } else if (content instanceof LwM2mSingleResource) {
166   -// return (LwM2mSingleResource) content;
167   -// } else if (content instanceof LwM2mMultipleResource) {
168   -// return (LwM2mMultipleResource) content;
169   -// }
170   -// return null;
171   -// }
  225 +
  226 + public static LwM2mNode getLvM2mNodeToObject(LwM2mNode content) {
  227 + if (content instanceof LwM2mObject) {
  228 + return (LwM2mObject) content;
  229 + } else if (content instanceof LwM2mObjectInstance) {
  230 + return (LwM2mObjectInstance) content;
  231 + } else if (content instanceof LwM2mSingleResource) {
  232 + return (LwM2mSingleResource) content;
  233 + } else if (content instanceof LwM2mMultipleResource) {
  234 + return (LwM2mMultipleResource) content;
  235 + }
  236 + return null;
  237 + }
  238 +
172 239
173 240 public static LwM2mClientProfile getNewProfileParameters(JsonObject profilesConfigData, TenantId tenantId) {
174 241 LwM2mClientProfile lwM2MClientProfile = new LwM2mClientProfile();
... ... @@ -177,7 +244,7 @@ public class LwM2mTransportHandler {
177 244 lwM2MClientProfile.setPostKeyNameProfile(profilesConfigData.get(OBSERVE_ATTRIBUTE_TELEMETRY).getAsJsonObject().get(KEY_NAME).getAsJsonObject());
178 245 lwM2MClientProfile.setPostAttributeProfile(profilesConfigData.get(OBSERVE_ATTRIBUTE_TELEMETRY).getAsJsonObject().get(ATTRIBUTE).getAsJsonArray());
179 246 lwM2MClientProfile.setPostTelemetryProfile(profilesConfigData.get(OBSERVE_ATTRIBUTE_TELEMETRY).getAsJsonObject().get(TELEMETRY).getAsJsonArray());
180   - lwM2MClientProfile.setPostObserveProfile(profilesConfigData.get(OBSERVE_ATTRIBUTE_TELEMETRY).getAsJsonObject().get(OBSERVE).getAsJsonArray());
  247 + lwM2MClientProfile.setPostObserveProfile(profilesConfigData.get(OBSERVE_ATTRIBUTE_TELEMETRY).getAsJsonObject().get(OBSERVE_LWM2M).getAsJsonArray());
181 248 lwM2MClientProfile.setPostAttributeLwm2mProfile(profilesConfigData.get(OBSERVE_ATTRIBUTE_TELEMETRY).getAsJsonObject().get(ATTRIBUTE_LWM2M).getAsJsonObject());
182 249 return lwM2MClientProfile;
183 250 }
... ... @@ -198,8 +265,8 @@ public class LwM2mTransportHandler {
198 265 * "telemetry":["/1/0/1","/2/0/1","/6/0/1"],
199 266 * "observe":["/2/0","/2/0/0","/4/0/2"]}
200 267 * "attributeLwm2m": {"/3_1.0": {"ver": "currentTimeTest11"},
201   - * "/3_1.0/0": {"gt": 17},
202   - * "/3_1.0/0/9": {"pmax": 45}, "/3_1.2": {ver": "3_1.2"}}
  268 + * "/3_1.0/0": {"gt": 17},
  269 + * "/3_1.0/0/9": {"pmax": 45}, "/3_1.2": {ver": "3_1.2"}}
203 270 */
204 271 public static LwM2mClientProfile getLwM2MClientProfileFromThingsboard(DeviceProfile deviceProfile) {
205 272 if (deviceProfile != null && ((Lwm2mDeviceProfileTransportConfiguration) deviceProfile.getProfileData().getTransportConfiguration()).getProperties().size() > 0) {
... ... @@ -254,9 +321,9 @@ public class LwM2mTransportHandler {
254 321 objectMsg.get(OBSERVE_ATTRIBUTE_TELEMETRY).getAsJsonObject().has(TELEMETRY) &&
255 322 !objectMsg.get(OBSERVE_ATTRIBUTE_TELEMETRY).getAsJsonObject().get(TELEMETRY).isJsonNull() &&
256 323 objectMsg.get(OBSERVE_ATTRIBUTE_TELEMETRY).getAsJsonObject().get(TELEMETRY).isJsonArray() &&
257   - objectMsg.get(OBSERVE_ATTRIBUTE_TELEMETRY).getAsJsonObject().has(OBSERVE) &&
258   - !objectMsg.get(OBSERVE_ATTRIBUTE_TELEMETRY).getAsJsonObject().get(OBSERVE).isJsonNull() &&
259   - objectMsg.get(OBSERVE_ATTRIBUTE_TELEMETRY).getAsJsonObject().get(OBSERVE).isJsonArray() &&
  324 + objectMsg.get(OBSERVE_ATTRIBUTE_TELEMETRY).getAsJsonObject().has(OBSERVE_LWM2M) &&
  325 + !objectMsg.get(OBSERVE_ATTRIBUTE_TELEMETRY).getAsJsonObject().get(OBSERVE_LWM2M).isJsonNull() &&
  326 + objectMsg.get(OBSERVE_ATTRIBUTE_TELEMETRY).getAsJsonObject().get(OBSERVE_LWM2M).isJsonArray() &&
260 327 objectMsg.get(OBSERVE_ATTRIBUTE_TELEMETRY).getAsJsonObject().has(ATTRIBUTE_LWM2M) &&
261 328 !objectMsg.get(OBSERVE_ATTRIBUTE_TELEMETRY).getAsJsonObject().get(ATTRIBUTE_LWM2M).isJsonNull() &&
262 329 objectMsg.get(OBSERVE_ATTRIBUTE_TELEMETRY).getAsJsonObject().get(ATTRIBUTE_LWM2M).isJsonObject());
... ... @@ -341,8 +408,7 @@ public class LwM2mTransportHandler {
341 408 if (keyArray.length > 1 && keyArray[1].split(LWM2M_SEPARATOR_KEY).length == 2) {
342 409 keyArray[1] = keyArray[1].split(LWM2M_SEPARATOR_KEY)[0];
343 410 return StringUtils.join(keyArray, LWM2M_SEPARATOR_PATH);
344   - }
345   - else {
  411 + } else {
346 412 return pathIdVer;
347 413 }
348 414 } catch (Exception e) {
... ... @@ -350,6 +416,37 @@ public class LwM2mTransportHandler {
350 416 }
351 417 }
352 418
  419 + /**
  420 + * @param path - pathId or pathIdVer
  421 + * @return
  422 + */
  423 + public static String getVerFromPathIdVerOrId(String path) {
  424 + try {
  425 + String[] keyArray = path.split(LWM2M_SEPARATOR_PATH);
  426 + if (keyArray.length > 1) {
  427 + String[] keyArrayVer = keyArray[1].split(LWM2M_SEPARATOR_KEY);
  428 + return keyArrayVer.length == 2 ? keyArrayVer[1] : null;
  429 + }
  430 + } catch (Exception e) {
  431 + return null;
  432 + }
  433 + return null;
  434 + }
  435 +
  436 + public static String validPathIdVer(String pathIdVer, Registration registration) throws IllegalArgumentException {
  437 + if (pathIdVer.indexOf(LWM2M_SEPARATOR_PATH) < 0) {
  438 + throw new IllegalArgumentException(String.format("Error:"));
  439 + } else {
  440 + String[] keyArray = pathIdVer.split(LWM2M_SEPARATOR_PATH);
  441 + if (keyArray.length > 1 && keyArray[1].split(LWM2M_SEPARATOR_KEY).length == 2) {
  442 + return pathIdVer;
  443 + } else {
  444 + LwM2mPath pathObjId = new LwM2mPath(pathIdVer);
  445 + return convertPathFromObjectIdToIdVer(pathIdVer, registration);
  446 + }
  447 + }
  448 + }
  449 +
353 450 public static String convertPathFromObjectIdToIdVer(String path, Registration registration) {
354 451 String ver = registration.getSupportedObject().get(new LwM2mPath(path).getObjectId());
355 452 try {
... ... @@ -357,8 +454,7 @@ public class LwM2mTransportHandler {
357 454 if (keyArray.length > 1) {
358 455 keyArray[1] = keyArray[1] + LWM2M_SEPARATOR_KEY + ver;
359 456 return StringUtils.join(keyArray, LWM2M_SEPARATOR_PATH);
360   - }
361   - else {
  457 + } else {
362 458 return path;
363 459 }
364 460 } catch (Exception e) {
... ... @@ -397,13 +493,13 @@ public class LwM2mTransportHandler {
397 493 * when:
398 494 * a.old value is 17 and new value is 24 due to lt condition
399 495 * b.old value is 75 and new value is 90 due to both gt and step conditions
400   - * String uriQueries = "pmin=10&pmax=60";
401   - * AttributeSet attributes = AttributeSet.parse(uriQueries);
402   - * WriteAttributesRequest request = new WriteAttributesRequest(target, attributes);
403   - * Attribute gt = new Attribute(GREATER_THAN, Double.valueOf("45"));
404   - * Attribute st = new Attribute(LESSER_THAN, Double.valueOf("10"));
405   - * Attribute pmax = new Attribute(MAXIMUM_PERIOD, "60");
406   - * Attribute [] attrs = {gt, st};
  496 + * String uriQueries = "pmin=10&pmax=60";
  497 + * AttributeSet attributes = AttributeSet.parse(uriQueries);
  498 + * WriteAttributesRequest request = new WriteAttributesRequest(target, attributes);
  499 + * Attribute gt = new Attribute(GREATER_THAN, Double.valueOf("45"));
  500 + * Attribute st = new Attribute(LESSER_THAN, Double.valueOf("10"));
  501 + * Attribute pmax = new Attribute(MAXIMUM_PERIOD, "60");
  502 + * Attribute [] attrs = {gt, st};
407 503 */
408 504 public static DownlinkRequest createWriteAttributeRequest(String target, Object params) {
409 505 AttributeSet attrSet = new AttributeSet(createWriteAttributes(params));
... ... @@ -423,4 +519,12 @@ public class LwM2mTransportHandler {
423 519 });
424 520 return (Attribute[]) attributeLists.toArray(Attribute[]::new);
425 521 }
  522 +
  523 +
  524 + public static Set<String> convertJsonArrayToSet(JsonArray jsonArray) {
  525 + List<String> attributeListOld = new Gson().fromJson(jsonArray, new TypeToken<List<String>>() {
  526 + }.getType());
  527 + return Sets.newConcurrentHashSet(attributeListOld);
  528 + }
  529 +
426 530 }
... ...
... ... @@ -15,6 +15,7 @@
15 15 */
16 16 package org.thingsboard.server.transport.lwm2m.server;
17 17
  18 +import lombok.SneakyThrows;
18 19 import lombok.extern.slf4j.Slf4j;
19 20 import org.eclipse.californium.core.coap.CoAP;
20 21 import org.eclipse.californium.core.coap.Response;
... ... @@ -24,8 +25,8 @@ import org.eclipse.leshan.core.node.LwM2mPath;
24 25 import org.eclipse.leshan.core.node.LwM2mSingleResource;
25 26 import org.eclipse.leshan.core.node.ObjectLink;
26 27 import org.eclipse.leshan.core.observation.Observation;
27   -import org.eclipse.leshan.core.request.CancelObservationRequest;
28 28 import org.eclipse.leshan.core.request.ContentFormat;
  29 +import org.eclipse.leshan.core.request.DeleteRequest;
29 30 import org.eclipse.leshan.core.request.DiscoverRequest;
30 31 import org.eclipse.leshan.core.request.DownlinkRequest;
31 32 import org.eclipse.leshan.core.request.ExecuteRequest;
... ... @@ -47,27 +48,31 @@ import org.eclipse.leshan.core.util.NamedThreadFactory;
47 48 import org.eclipse.leshan.server.californium.LeshanServer;
48 49 import org.eclipse.leshan.server.registration.Registration;
49 50 import org.springframework.stereotype.Service;
  51 +import org.thingsboard.server.common.transport.TransportService;
50 52 import org.thingsboard.server.queue.util.TbLwM2mTransportComponent;
51 53 import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient;
52 54 import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClientContext;
  55 +import org.thingsboard.server.transport.lwm2m.server.client.Lwm2mClientRpcRequest;
53 56 import org.thingsboard.server.transport.lwm2m.utils.LwM2mValueConverterImpl;
54 57
55 58 import javax.annotation.PostConstruct;
  59 +import java.util.Arrays;
56 60 import java.util.Date;
  61 +import java.util.Set;
57 62 import java.util.concurrent.ExecutorService;
58 63 import java.util.concurrent.Executors;
  64 +import java.util.stream.Collectors;
59 65
  66 +import static org.eclipse.californium.core.coap.CoAP.ResponseCode.CONTENT;
  67 +import static org.eclipse.leshan.core.ResponseCode.BAD_REQUEST;
  68 +import static org.eclipse.leshan.core.ResponseCode.NOT_FOUND;
60 69 import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.DEFAULT_TIMEOUT;
61   -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.GET_TYPE_OPER_DISCOVER;
62   -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.GET_TYPE_OPER_OBSERVE;
63   -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.GET_TYPE_OPER_READ;
64 70 import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.LOG_LW2M_ERROR;
65 71 import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.LOG_LW2M_INFO;
66   -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.POST_TYPE_OPER_EXECUTE;
67   -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.POST_TYPE_OPER_OBSERVE_CANCEL;
68   -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.POST_TYPE_OPER_WRITE_REPLACE;
69   -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.PUT_TYPE_OPER_WRITE_ATTRIBUTES;
70   -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.PUT_TYPE_OPER_WRITE_UPDATE;
  72 +import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.LOG_LW2M_VALUE;
  73 +import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.LwM2mTypeOper;
  74 +import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.LwM2mTypeOper.OBSERVE_CANCEL;
  75 +import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.LwM2mTypeOper.OBSERVE_READ_ALL;
71 76 import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.RESPONSE_CHANNEL;
72 77 import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.convertPathFromIdVerToObjectId;
73 78 import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.convertPathFromObjectIdToIdVer;
... ... @@ -79,7 +84,7 @@ import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandle
79 84 public class LwM2mTransportRequest {
80 85 private ExecutorService executorResponse;
81 86
82   - private LwM2mValueConverterImpl converter;
  87 + public LwM2mValueConverterImpl converter;
83 88
84 89 private final LwM2mTransportContextServer lwM2mTransportContextServer;
85 90
... ... @@ -89,11 +94,16 @@ public class LwM2mTransportRequest {
89 94
90 95 private final LwM2mTransportServiceImpl serviceImpl;
91 96
92   - public LwM2mTransportRequest(LwM2mTransportContextServer lwM2mTransportContextServer, LwM2mClientContext lwM2mClientContext, LeshanServer leshanServer, LwM2mTransportServiceImpl serviceImpl) {
  97 + private final TransportService transportService;
  98 +
  99 + public LwM2mTransportRequest(LwM2mTransportContextServer lwM2mTransportContextServer,
  100 + LwM2mClientContext lwM2mClientContext, LeshanServer leshanServer,
  101 + LwM2mTransportServiceImpl serviceImpl, TransportService transportService) {
93 102 this.lwM2mTransportContextServer = lwM2mTransportContextServer;
94 103 this.lwM2mClientContext = lwM2mClientContext;
95 104 this.leshanServer = leshanServer;
96 105 this.serviceImpl = serviceImpl;
  106 + this.transportService = transportService;
97 107 }
98 108
99 109 @PostConstruct
... ... @@ -106,108 +116,155 @@ public class LwM2mTransportRequest {
106 116 /**
107 117 * Device management and service enablement, including Read, Write, Execute, Discover, Create, Delete and Write-Attributes
108 118 *
109   - * @param registration -
110   - * @param targetIdVer -
111   - * @param typeOper -
112   - * @param contentFormatParam -
113   - * @param observation -
  119 + * @param registration -
  120 + * @param targetIdVer -
  121 + * @param typeOper -
  122 + * @param contentFormatName -
114 123 */
115   - public void sendAllRequest(Registration registration, String targetIdVer, String typeOper,
116   - String contentFormatParam, Observation observation, Object params, long timeoutInMs) {
117   - String target = convertPathFromIdVerToObjectId(targetIdVer);
118   - LwM2mPath resultIds = new LwM2mPath(target);
119   - if (registration != null && resultIds.getObjectId() >= 0) {
  124 + @SneakyThrows
  125 + public void sendAllRequest(Registration registration, String targetIdVer, LwM2mTypeOper typeOper,
  126 + String contentFormatName, Object params, long timeoutInMs, Lwm2mClientRpcRequest rpcRequest) {
  127 + try {
  128 +
  129 + String target = convertPathFromIdVerToObjectId(targetIdVer);
120 130 DownlinkRequest request = null;
121   - ContentFormat contentFormat = contentFormatParam != null ? ContentFormat.fromName(contentFormatParam.toUpperCase()) : null;
122   - LwM2mClient lwM2MClient = lwM2mClientContext.getLwM2mClientWithReg(registration, null);
123   - ResourceModel resource = null;
124   - timeoutInMs = timeoutInMs > 0 ? timeoutInMs : DEFAULT_TIMEOUT;
125   - switch (typeOper) {
126   - case GET_TYPE_OPER_READ:
127   - request = new ReadRequest(contentFormat, target);
128   - break;
129   - case GET_TYPE_OPER_DISCOVER:
130   - request = new DiscoverRequest(target);
131   - break;
132   - case GET_TYPE_OPER_OBSERVE:
133   - if (resultIds.isResource()) {
134   - request = new ObserveRequest(resultIds.getObjectId(), resultIds.getObjectInstanceId(), resultIds.getResourceId());
135   - } else if (resultIds.isObjectInstance()) {
136   - request = new ObserveRequest(resultIds.getObjectId(), resultIds.getObjectInstanceId());
137   - } else if (resultIds.getObjectId() >= 0) {
138   - request = new ObserveRequest(resultIds.getObjectId());
139   - }
140   - break;
141   - case POST_TYPE_OPER_OBSERVE_CANCEL:
142   - request = new CancelObservationRequest(observation);
143   - break;
144   - case POST_TYPE_OPER_EXECUTE:
145   - resource = lwM2MClient.getResourceModel(targetIdVer);
146   - if (params != null && resource != null && !resource.multiple) {
147   - request = new ExecuteRequest(target, (String) this.converter.convertValue(params, resource.type, ResourceModel.Type.STRING, resultIds));
148   - } else {
149   - request = new ExecuteRequest(target);
150   - }
151   - break;
152   - case POST_TYPE_OPER_WRITE_REPLACE:
153   - // Request to write a <b>String Single-Instance Resource</b> using the TLV content format.
154   - resource = lwM2MClient.getResourceModel(targetIdVer);
155   - if (resource != null && contentFormat != null) {
  131 + ContentFormat contentFormat = contentFormatName != null ? ContentFormat.fromName(contentFormatName.toUpperCase()) : ContentFormat.DEFAULT;
  132 + LwM2mClient lwM2MClient = this.lwM2mClientContext.getLwM2mClientWithReg(registration, null);
  133 + LwM2mPath resultIds = target != null ? new LwM2mPath(target) : null;
  134 + if (!OBSERVE_READ_ALL.name().equals(typeOper.name()) && resultIds != null && registration != null && resultIds.getObjectId() >= 0 &&
  135 + lwM2MClient != null) {
  136 + if (lwM2MClient.isValidObjectVersion(targetIdVer)) {
  137 + timeoutInMs = timeoutInMs > 0 ? timeoutInMs : DEFAULT_TIMEOUT;
  138 + ResourceModel resourceModel = null;
  139 + switch (typeOper) {
  140 + case READ:
  141 + request = new ReadRequest(contentFormat, target);
  142 + break;
  143 + case DISCOVER:
  144 + request = new DiscoverRequest(target);
  145 + break;
  146 + case OBSERVE:
  147 + if (resultIds.isResource()) {
  148 + request = new ObserveRequest(resultIds.getObjectId(), resultIds.getObjectInstanceId(), resultIds.getResourceId());
  149 + } else if (resultIds.isObjectInstance()) {
  150 + request = new ObserveRequest(resultIds.getObjectId(), resultIds.getObjectInstanceId());
  151 + } else if (resultIds.getObjectId() >= 0) {
  152 + request = new ObserveRequest(resultIds.getObjectId());
  153 + }
  154 + break;
  155 + case OBSERVE_CANCEL:
  156 + /**
  157 + * lwM2MTransportRequest.sendAllRequest(lwServer, registration, path, POST_TYPE_OPER_OBSERVE_CANCEL, null, null, null, null, context.getTimeout());
  158 + * At server side this will not remove the observation from the observation store, to do it you need to use
  159 + * {@code ObservationService#cancelObservation()}
  160 + */
  161 + leshanServer.getObservationService().cancelObservations(registration, target);
  162 + break;
  163 + case EXECUTE:
  164 + resourceModel = lwM2MClient.getResourceModel(targetIdVer, this.lwM2mTransportContextServer.getLwM2MTransportConfigServer()
  165 + .getModelProvider());
  166 + if (params != null && !resourceModel.multiple) {
  167 + request = new ExecuteRequest(target, (String) this.converter.convertValue(params, resourceModel.type, ResourceModel.Type.STRING, resultIds));
  168 + } else {
  169 + request = new ExecuteRequest(target);
  170 + }
  171 + break;
  172 + case WRITE_REPLACE:
  173 + // Request to write a <b>String Single-Instance Resource</b> using the TLV content format.
  174 +// resource = lwM2MClient.getResourceModel(targetIdVer);
156 175 // if (contentFormat.equals(ContentFormat.TLV) && !resource.multiple) {
157   - if (contentFormat.equals(ContentFormat.TLV)) {
158   - request = this.getWriteRequestSingleResource(null, resultIds.getObjectId(), resultIds.getObjectInstanceId(), resultIds.getResourceId(), params, resource.type, registration);
159   - }
160   - // Mode.REPLACE && Request to write a <b>String Single-Instance Resource</b> using the given content format (TEXT, TLV, JSON)
  176 + resourceModel = lwM2MClient.getResourceModel(targetIdVer, this.lwM2mTransportContextServer.getLwM2MTransportConfigServer()
  177 + .getModelProvider());
  178 + if (contentFormat.equals(ContentFormat.TLV)) {
  179 + request = this.getWriteRequestSingleResource(null, resultIds.getObjectId(),
  180 + resultIds.getObjectInstanceId(), resultIds.getResourceId(), params, resourceModel.type,
  181 + registration, rpcRequest);
  182 + }
  183 + // Mode.REPLACE && Request to write a <b>String Single-Instance Resource</b> using the given content format (TEXT, TLV, JSON)
161 184 // else if (!contentFormat.equals(ContentFormat.TLV) && !resource.multiple) {
162   - else if (!contentFormat.equals(ContentFormat.TLV)) {
163   - request = this.getWriteRequestSingleResource(contentFormat, resultIds.getObjectId(), resultIds.getObjectInstanceId(), resultIds.getResourceId(), params, resource.type, registration);
164   - }
165   - }
166   - break;
167   - case PUT_TYPE_OPER_WRITE_UPDATE:
168   - if (resultIds.getResourceId() >= 0) {
169   -// ResourceModel resourceModel = leshanServer.getModelProvider().getObjectModel(registration).getObjectModel(resultIds.getObjectId()).resources.get(resultIds.getResourceId());
170   -// ResourceModel.Type typeRes = resourceModel.type;
171   - LwM2mNode node = LwM2mSingleResource.newStringResource(resultIds.getResourceId(), (String) this.converter.convertValue(params, resource.type, ResourceModel.Type.STRING, resultIds));
172   - request = new WriteRequest(WriteRequest.Mode.UPDATE, contentFormat, target, node);
  185 + else if (!contentFormat.equals(ContentFormat.TLV)) {
  186 + request = this.getWriteRequestSingleResource(contentFormat, resultIds.getObjectId(),
  187 + resultIds.getObjectInstanceId(), resultIds.getResourceId(), params, resourceModel.type,
  188 + registration, rpcRequest);
  189 + }
  190 + break;
  191 + case WRITE_UPDATE:
  192 +// LwM2mNode node = null;
  193 +// if (resultIds.isObjectInstance()) {
  194 +// node = new LwM2mObjectInstance(resultIds.getObjectInstanceId(), lwM2MClient.
  195 +// getNewResourcesForInstance(targetIdVer, this.lwM2mTransportContextServer.getLwM2MTransportConfigServer().getModelProvider(),
  196 +// this.converter));
  197 +// request = new WriteRequest(WriteRequest.Mode.UPDATE, contentFormat, target, node);
  198 +// } else if (resultIds.getObjectId() >= 0) {
  199 +// request = new ObserveRequest(resultIds.getObjectId());
  200 +// }
  201 + break;
  202 + case WRITE_ATTRIBUTES:
  203 + request = createWriteAttributeRequest(target, params);
  204 + break;
  205 + case DELETE:
  206 + request = new DeleteRequest(target);
  207 + break;
173 208 }
174   - break;
175   - case PUT_TYPE_OPER_WRITE_ATTRIBUTES:
176   - request = createWriteAttributeRequest(target, params);
177   - break;
178   - }
179 209
180   - if (request != null) {
181   - try {
182   - this.sendRequest(registration, lwM2MClient, request, timeoutInMs);
183   - } catch (ClientSleepingException e) {
184   - DownlinkRequest finalRequest = request;
185   - long finalTimeoutInMs = timeoutInMs;
186   - lwM2MClient.getQueuedRequests().add(() -> sendRequest(registration, lwM2MClient, finalRequest, finalTimeoutInMs));
187   - } catch (Exception e) {
188   - log.error("[{}] [{}] [{}] Failed to send downlink.", registration.getEndpoint(), targetIdVer, typeOper, e);
  210 + if (request != null) {
  211 + try {
  212 + this.sendRequest(registration, lwM2MClient, request, timeoutInMs, rpcRequest);
  213 + } catch (ClientSleepingException e) {
  214 + DownlinkRequest finalRequest = request;
  215 + long finalTimeoutInMs = timeoutInMs;
  216 + lwM2MClient.getQueuedRequests().add(() -> sendRequest(registration, lwM2MClient, finalRequest, finalTimeoutInMs, rpcRequest));
  217 + } catch (Exception e) {
  218 + log.error("[{}] [{}] [{}] Failed to send downlink.", registration.getEndpoint(), targetIdVer, typeOper, e);
  219 + }
  220 + } else if (OBSERVE_CANCEL == typeOper && rpcRequest != null) {
  221 + rpcRequest.setInfoMsg(null);
  222 + serviceImpl.sentRpcRequest(rpcRequest, CONTENT.name(), null, null);
  223 + } else {
  224 + log.error("[{}], [{}] - [{}] error SendRequest", registration.getEndpoint(), typeOper, targetIdVer);
  225 + if (rpcRequest != null) {
  226 + String errorMsg = resourceModel == null ? String.format("Path %s not found in object version", targetIdVer) : "SendRequest - null";
  227 + serviceImpl.sentRpcRequest(rpcRequest, NOT_FOUND.getName(), errorMsg, LOG_LW2M_ERROR);
  228 + }
  229 + }
  230 + } else if (rpcRequest != null) {
  231 + String errorMsg = String.format("Path %s not found in object version", targetIdVer);
  232 + serviceImpl.sentRpcRequest(rpcRequest, NOT_FOUND.getName(), errorMsg, LOG_LW2M_ERROR);
  233 + }
  234 + } else if (OBSERVE_READ_ALL.name().equals(typeOper.name())) {
  235 + Set<Observation> observations = leshanServer.getObservationService().getObservations(registration);
  236 + Set<String> observationPaths = observations.stream().map(observation -> observation.getPath().toString()).collect(Collectors.toUnmodifiableSet());
  237 + String msg = String.format("%s: type operation %s observation paths - %s", LOG_LW2M_INFO,
  238 + OBSERVE_READ_ALL.type, observationPaths);
  239 + serviceImpl.sendLogsToThingsboard(msg, registration);
  240 + log.info("[{}], [{}]", registration.getEndpoint(), msg);
  241 + if (rpcRequest != null) {
  242 + String valueMsg = String.format("Observation paths - %s", observationPaths);
  243 + serviceImpl.sentRpcRequest(rpcRequest, CONTENT.name(), valueMsg, LOG_LW2M_VALUE);
189 244 }
190   - } else {
191   - log.error("[{}], [{}] - [{}] error SendRequest", registration.getEndpoint(), typeOper, targetIdVer);
192 245 }
  246 + } catch (Exception e) {
  247 + String msg = String.format("%s: type operation %s %s", LOG_LW2M_ERROR,
  248 + typeOper.name(), e.getMessage());
  249 + serviceImpl.sendLogsToThingsboard(msg, registration);
  250 + throw new Exception(e);
193 251 }
194 252 }
195 253
196 254 /**
197   - *
198 255 * @param registration -
199   - * @param request -
200   - * @param timeoutInMs -
  256 + * @param request -
  257 + * @param timeoutInMs -
201 258 */
202 259
203 260 @SuppressWarnings("unchecked")
204   - private void sendRequest(Registration registration, LwM2mClient lwM2MClient, DownlinkRequest request, long timeoutInMs) {
  261 + private void sendRequest(Registration registration, LwM2mClient lwM2MClient, DownlinkRequest request, long timeoutInMs, Lwm2mClientRpcRequest rpcRequest) {
205 262 leshanServer.send(registration, request, timeoutInMs, (ResponseCallback<?>) response -> {
206 263 if (!lwM2MClient.isInit()) {
207 264 lwM2MClient.initValue(this.serviceImpl, convertPathFromObjectIdToIdVer(request.getPath().toString(), registration));
208 265 }
209 266 if (CoAP.ResponseCode.isSuccess(((Response) response.getCoapResponse()).getCode())) {
210   - this.handleResponse(registration, request.getPath().toString(), response, request);
  267 + this.handleResponse(registration, request.getPath().toString(), response, request, rpcRequest);
211 268 if (request instanceof WriteRequest && ((WriteRequest) request).isReplaceRequest()) {
212 269 LwM2mNode node = ((WriteRequest) request).getNode();
213 270 Object value = this.converter.convertValue(((LwM2mSingleResource) node).getValue(),
... ... @@ -216,48 +273,64 @@ public class LwM2mTransportRequest {
216 273 LOG_LW2M_INFO, ((Response) response.getCoapResponse()).getCode(), response.getCode().getCode(),
217 274 response.getCode().getName(), request.getPath().toString(), value);
218 275 serviceImpl.sendLogsToThingsboard(msg, registration);
219   - log.debug("[{}] [{}] - [{}] [{}] Update SendRequest[{}]", registration.getEndpoint(),
  276 + log.info("[{}] [{}] - [{}] [{}] Update SendRequest[{}]", registration.getEndpoint(),
220 277 ((Response) response.getCoapResponse()).getCode(), response.getCode(),
221 278 request.getPath().toString(), value);
  279 + serviceImpl.sentRpcRequest(rpcRequest, response.getCode().getName(), null, LOG_LW2M_INFO);
222 280 }
223 281 } else {
224 282 String msg = String.format("%s: sendRequest: CoapCode - %s Lwm2m code - %d name - %s Resource path - %s SendRequest to Client", LOG_LW2M_ERROR,
225 283 ((Response) response.getCoapResponse()).getCode(), response.getCode().getCode(), response.getCode().getName(), request.getPath().toString());
226 284 serviceImpl.sendLogsToThingsboard(msg, registration);
227 285 log.error("[{}], [{}] - [{}] [{}] error SendRequest", registration.getEndpoint(), ((Response) response.getCoapResponse()).getCode(), response.getCode(), request.getPath().toString());
  286 + if (rpcRequest != null) {
  287 + serviceImpl.sentRpcRequest(rpcRequest, response.getCode().getName(), response.getErrorMessage(), LOG_LW2M_ERROR);
  288 + }
228 289 }
229 290 }, e -> {
230 291 if (!lwM2MClient.isInit()) {
231 292 lwM2MClient.initValue(this.serviceImpl, convertPathFromObjectIdToIdVer(request.getPath().toString(), registration));
232 293 }
233 294 String msg = String.format("%s: sendRequest: Resource path - %s msg error - %s SendRequest to Client",
234   - LOG_LW2M_ERROR, request.getPath().toString(), e.toString());
  295 + LOG_LW2M_ERROR, request.getPath().toString(), e.getMessage());
235 296 serviceImpl.sendLogsToThingsboard(msg, registration);
236 297 log.error("[{}] - [{}] error SendRequest", request.getPath().toString(), e.toString());
  298 + if (rpcRequest != null) {
  299 + serviceImpl.sentRpcRequest(rpcRequest, CoAP.CodeClass.ERROR_RESPONSE.name(), e.getMessage(), LOG_LW2M_ERROR);
  300 + }
237 301 });
238 302
239 303 }
240 304
241   - private WriteRequest getWriteRequestSingleResource(ContentFormat contentFormat, Integer objectId, Integer instanceId, Integer resourceId, Object value, ResourceModel.Type type, Registration registration) {
  305 + private WriteRequest getWriteRequestSingleResource(ContentFormat contentFormat, Integer objectId, Integer instanceId,
  306 + Integer resourceId, Object value, ResourceModel.Type type,
  307 + Registration registration, Lwm2mClientRpcRequest rpcRequest) {
242 308 try {
243   - switch (type) {
244   - case STRING: // String
245   - return (contentFormat == null) ? new WriteRequest(objectId, instanceId, resourceId, value.toString()) : new WriteRequest(contentFormat, objectId, instanceId, resourceId, value.toString());
246   - case INTEGER: // Long
247   - final long valueInt = Integer.toUnsignedLong(Integer.parseInt(value.toString()));
248   - return (contentFormat == null) ? new WriteRequest(objectId, instanceId, resourceId, valueInt) : new WriteRequest(contentFormat, objectId, instanceId, resourceId, valueInt);
249   - case OBJLNK: // ObjectLink
250   - return (contentFormat == null) ? new WriteRequest(objectId, instanceId, resourceId, ObjectLink.fromPath(value.toString())) : new WriteRequest(contentFormat, objectId, instanceId, resourceId, ObjectLink.fromPath(value.toString()));
251   - case BOOLEAN: // Boolean
252   - return (contentFormat == null) ? new WriteRequest(objectId, instanceId, resourceId, Boolean.parseBoolean(value.toString())) : new WriteRequest(contentFormat, objectId, instanceId, resourceId, Boolean.parseBoolean(value.toString()));
253   - case FLOAT: // Double
254   - return (contentFormat == null) ? new WriteRequest(objectId, instanceId, resourceId, Double.parseDouble(value.toString())) : new WriteRequest(contentFormat, objectId, instanceId, resourceId, Double.parseDouble(value.toString()));
255   - case TIME: // Date
256   - Date date = new Date(Long.decode(value.toString()));
257   - return (contentFormat == null) ? new WriteRequest(objectId, instanceId, resourceId, date) : new WriteRequest(contentFormat, objectId, instanceId, resourceId, date);
258   - case OPAQUE: // byte[] value, base64
259   - return (contentFormat == null) ? new WriteRequest(objectId, instanceId, resourceId, Hex.decodeHex(value.toString().toCharArray())) : new WriteRequest(contentFormat, objectId, instanceId, resourceId, Hex.decodeHex(value.toString().toCharArray()));
260   - default:
  309 + if (type != null) {
  310 + switch (type) {
  311 + case STRING: // String
  312 + return (contentFormat == null) ? new WriteRequest(objectId, instanceId, resourceId, value.toString()) : new WriteRequest(contentFormat, objectId, instanceId, resourceId, value.toString());
  313 + case INTEGER: // Long
  314 + final long valueInt = Integer.toUnsignedLong(Integer.parseInt(value.toString()));
  315 + return (contentFormat == null) ? new WriteRequest(objectId, instanceId, resourceId, valueInt) : new WriteRequest(contentFormat, objectId, instanceId, resourceId, valueInt);
  316 + case OBJLNK: // ObjectLink
  317 + return (contentFormat == null) ? new WriteRequest(objectId, instanceId, resourceId, ObjectLink.fromPath(value.toString())) : new WriteRequest(contentFormat, objectId, instanceId, resourceId, ObjectLink.fromPath(value.toString()));
  318 + case BOOLEAN: // Boolean
  319 + return (contentFormat == null) ? new WriteRequest(objectId, instanceId, resourceId, Boolean.parseBoolean(value.toString())) : new WriteRequest(contentFormat, objectId, instanceId, resourceId, Boolean.parseBoolean(value.toString()));
  320 + case FLOAT: // Double
  321 + return (contentFormat == null) ? new WriteRequest(objectId, instanceId, resourceId, Double.parseDouble(value.toString())) : new WriteRequest(contentFormat, objectId, instanceId, resourceId, Double.parseDouble(value.toString()));
  322 + case TIME: // Date
  323 + Date date = new Date(Long.decode(value.toString()));
  324 + return (contentFormat == null) ? new WriteRequest(objectId, instanceId, resourceId, date) : new WriteRequest(contentFormat, objectId, instanceId, resourceId, date);
  325 + case OPAQUE: // byte[] value, base64
  326 + return (contentFormat == null) ? new WriteRequest(objectId, instanceId, resourceId, Hex.decodeHex(value.toString().toCharArray())) : new WriteRequest(contentFormat, objectId, instanceId, resourceId, Hex.decodeHex(value.toString().toCharArray()));
  327 + default:
  328 + }
  329 + }
  330 + if (rpcRequest != null) {
  331 + String patn = "/" + objectId + "/" + instanceId + "/" + resourceId;
  332 + String errorMsg = String.format("Bad ResourceModel Operations (E): Resource path - %s ResourceModel type - %s", patn, type);
  333 + rpcRequest.setErrorMsg(errorMsg);
261 334 }
262 335 return null;
263 336 } catch (NumberFormatException e) {
... ... @@ -266,14 +339,19 @@ public class LwM2mTransportRequest {
266 339 patn, type, value, e.toString());
267 340 serviceImpl.sendLogsToThingsboard(msg, registration);
268 341 log.error("Path: [{}] type: [{}] value: [{}] errorMsg: [{}]]", patn, type, value, e.toString());
  342 + if (rpcRequest != null) {
  343 + String errorMsg = String.format("NumberFormatException: Resource path - %s type - %s value - %s", patn, type, value);
  344 + serviceImpl.sentRpcRequest(rpcRequest, BAD_REQUEST.getName(), errorMsg, LOG_LW2M_ERROR);
  345 + }
269 346 return null;
270 347 }
271 348 }
272 349
273   - private void handleResponse(Registration registration, final String path, LwM2mResponse response, DownlinkRequest request) {
  350 + private void handleResponse(Registration registration, final String path, LwM2mResponse response,
  351 + DownlinkRequest request, Lwm2mClientRpcRequest rpcRequest) {
274 352 executorResponse.submit(() -> {
275 353 try {
276   - sendResponse(registration, path, response, request);
  354 + this.sendResponse(registration, path, response, request, rpcRequest);
277 355 } catch (Exception e) {
278 356 log.error("[{}] endpoint [{}] path [{}] Exception Unable to after send response.", registration.getEndpoint(), path, e);
279 357 }
... ... @@ -282,20 +360,30 @@ public class LwM2mTransportRequest {
282 360
283 361 /**
284 362 * processing a response from a client
  363 + *
285 364 * @param registration -
286   - * @param path -
287   - * @param response -
  365 + * @param path -
  366 + * @param response -
288 367 */
289   - private void sendResponse(Registration registration, String path, LwM2mResponse response, DownlinkRequest request) {
  368 + private void sendResponse(Registration registration, String path, LwM2mResponse response,
  369 + DownlinkRequest request, Lwm2mClientRpcRequest rpcRequest) {
290 370 String pathIdVer = convertPathFromObjectIdToIdVer(path, registration);
291 371 if (response instanceof ReadResponse) {
292   - serviceImpl.onObservationResponse(registration, pathIdVer, (ReadResponse) response);
  372 + serviceImpl.onObservationResponse(registration, pathIdVer, (ReadResponse) response, rpcRequest);
293 373 } else if (response instanceof CancelObservationResponse) {
294 374 log.info("[{}] Path [{}] CancelObservationResponse 3_Send", pathIdVer, response);
  375 +
295 376 } else if (response instanceof DeleteResponse) {
296 377 log.info("[{}] Path [{}] DeleteResponse 5_Send", pathIdVer, response);
297 378 } else if (response instanceof DiscoverResponse) {
298   - log.info("[{}] Path [{}] DiscoverResponse 6_Send", pathIdVer, response);
  379 + log.info("[{}] [{}] - [{}] [{}] Discovery value: [{}]", registration.getEndpoint(),
  380 + ((Response) response.getCoapResponse()).getCode(), response.getCode(),
  381 + request.getPath().toString(), ((DiscoverResponse) response).getObjectLinks());
  382 + if (rpcRequest != null) {
  383 + String discoveryMsg = String.format("%s",
  384 + Arrays.stream(((DiscoverResponse) response).getObjectLinks()).collect(Collectors.toSet()));
  385 + serviceImpl.sentRpcRequest(rpcRequest, response.getCode().getName(), discoveryMsg, LOG_LW2M_VALUE);
  386 + }
299 387 } else if (response instanceof ExecuteResponse) {
300 388 log.info("[{}] Path [{}] ExecuteResponse 7_Send", pathIdVer, response);
301 389 } else if (response instanceof WriteAttributesResponse) {
... ... @@ -304,5 +392,11 @@ public class LwM2mTransportRequest {
304 392 log.info("[{}] Path [{}] WriteAttributesResponse 9_Send", pathIdVer, response);
305 393 serviceImpl.onWriteResponseOk(registration, pathIdVer, (WriteRequest) request);
306 394 }
  395 + if (rpcRequest != null && (response instanceof ExecuteResponse
  396 + || response instanceof WriteAttributesResponse
  397 + || response instanceof DeleteResponse)) {
  398 + rpcRequest.setInfoMsg(null);
  399 + serviceImpl.sentRpcRequest(rpcRequest, response.getCode().getName(), null, null);
  400 + }
307 401 }
308 402 }
... ...
... ... @@ -21,6 +21,7 @@ import org.eclipse.leshan.server.registration.Registration;
21 21 import org.thingsboard.server.common.data.Device;
22 22 import org.thingsboard.server.common.data.DeviceProfile;
23 23 import org.thingsboard.server.gen.transport.TransportProtos;
  24 +import org.thingsboard.server.transport.lwm2m.server.client.Lwm2mClientRpcRequest;
24 25
25 26 import java.util.Collection;
26 27 import java.util.Optional;
... ... @@ -37,9 +38,7 @@ public interface LwM2mTransportService {
37 38
38 39 void setCancelObservations(Registration registration);
39 40
40   - void setCancelObservationRecourse(Registration registration, String path);
41   -
42   - void onObservationResponse(Registration registration, String path, ReadResponse response);
  41 + void onObservationResponse(Registration registration, String path, ReadResponse response, Lwm2mClientRpcRequest rpcRequest);
43 42
44 43 void onAttributeUpdate(TransportProtos.AttributeUpdateNotificationMsg msg, TransportProtos.SessionInfoProto sessionInfo);
45 44
... ... @@ -51,7 +50,9 @@ public interface LwM2mTransportService {
51 50
52 51 void onResourceDelete(Optional<TransportProtos.ResourceDeleteMsg> resourceDeleteMsgOpt);
53 52
54   - void onToDeviceRpcRequest(TransportProtos.ToDeviceRpcRequestMsg toDeviceRequest);
  53 + void onToDeviceRpcRequest(TransportProtos.ToDeviceRpcRequestMsg toDeviceRequest, TransportProtos.SessionInfoProto sessionInfo);
  54 +
  55 + void onToDeviceRpcResponse(TransportProtos.ToDeviceRpcResponseMsg toDeviceRpcResponse, TransportProtos.SessionInfoProto sessionInfo);
55 56
56 57 void onToServerRpcResponse(TransportProtos.ToServerRpcResponseMsg toServerResponse);
57 58
... ...
... ... @@ -16,7 +16,6 @@
16 16 package org.thingsboard.server.transport.lwm2m.server;
17 17
18 18 import com.fasterxml.jackson.core.type.TypeReference;
19   -import com.google.common.collect.Sets;
20 19 import com.google.gson.Gson;
21 20 import com.google.gson.GsonBuilder;
22 21 import com.google.gson.JsonArray;
... ... @@ -52,6 +51,7 @@ import org.thingsboard.server.queue.util.TbLwM2mTransportComponent;
52 51 import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient;
53 52 import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClientContext;
54 53 import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClientProfile;
  54 +import org.thingsboard.server.transport.lwm2m.server.client.Lwm2mClientRpcRequest;
55 55 import org.thingsboard.server.transport.lwm2m.server.client.ResultsAddKeyValueProto;
56 56 import org.thingsboard.server.transport.lwm2m.server.client.ResultsAnalyzerParameters;
57 57 import org.thingsboard.server.transport.lwm2m.utils.LwM2mValueConverterImpl;
... ... @@ -74,21 +74,29 @@ import java.util.concurrent.Executors;
74 74 import java.util.concurrent.TimeUnit;
75 75 import java.util.stream.Collectors;
76 76
  77 +import static org.eclipse.californium.core.coap.CoAP.ResponseCode.BAD_REQUEST;
77 78 import static org.eclipse.leshan.core.attributes.Attribute.OBJECT_VERSION;
78 79 import static org.thingsboard.server.common.data.lwm2m.LwM2mConstants.LWM2M_SEPARATOR_PATH;
79 80 import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.CLIENT_NOT_AUTHORIZED;
80 81 import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.DEVICE_ATTRIBUTES_REQUEST;
81   -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.GET_TYPE_OPER_DISCOVER;
82   -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.GET_TYPE_OPER_OBSERVE;
83   -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.GET_TYPE_OPER_READ;
84 82 import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.LOG_LW2M_ERROR;
85 83 import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.LOG_LW2M_INFO;
  84 +import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.LOG_LW2M_VALUE;
86 85 import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.LWM2M_STRATEGY_2;
87   -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.POST_TYPE_OPER_EXECUTE;
88   -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.POST_TYPE_OPER_WRITE_REPLACE;
89   -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.PUT_TYPE_OPER_WRITE_ATTRIBUTES;
  86 +import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.LwM2mTypeOper;
  87 +import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.LwM2mTypeOper.DISCOVER;
  88 +import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.LwM2mTypeOper.EXECUTE;
  89 +import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.LwM2mTypeOper.OBSERVE;
  90 +import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.LwM2mTypeOper.OBSERVE_CANCEL;
  91 +import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.LwM2mTypeOper.OBSERVE_READ_ALL;
  92 +import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.LwM2mTypeOper.READ;
  93 +import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.LwM2mTypeOper.WRITE_ATTRIBUTES;
  94 +import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.LwM2mTypeOper.WRITE_REPLACE;
  95 +import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.LwM2mTypeOper.WRITE_UPDATE;
90 96 import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.SERVICE_CHANNEL;
  97 +import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.convertJsonArrayToSet;
91 98 import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.convertPathFromIdVerToObjectId;
  99 +import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.convertPathFromObjectIdToIdVer;
92 100 import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.getAckCallback;
93 101 import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.validateObjectVerFromKey;
94 102
... ... @@ -257,21 +265,13 @@ public class LwM2mTransportServiceImpl implements LwM2mTransportService {
257 265 public void setCancelObservations(Registration registration) {
258 266 if (registration != null) {
259 267 Set<Observation> observations = leshanServer.getObservationService().getObservations(registration);
260   - observations.forEach(observation -> this.setCancelObservationRecourse(registration, observation.getPath().toString()));
  268 + observations.forEach(observation -> lwM2mTransportRequest.sendAllRequest(registration,
  269 + convertPathFromObjectIdToIdVer(observation.getPath().toString(), registration), OBSERVE_CANCEL,
  270 + null, null, this.lwM2mTransportContextServer.getLwM2MTransportConfigServer().getTimeout(), null));
261 271 }
262 272 }
263 273
264 274 /**
265   - * lwM2MTransportRequest.sendAllRequest(lwServer, registration, path, POST_TYPE_OPER_OBSERVE_CANCEL, null, null, null, null, context.getTimeout());
266   - * At server side this will not remove the observation from the observation store, to do it you need to use
267   - * {@code ObservationService#cancelObservation()}
268   - */
269   - @Override
270   - public void setCancelObservationRecourse(Registration registration, String path) {
271   - leshanServer.getObservationService().cancelObservations(registration, path);
272   - }
273   -
274   - /**
275 275 * Sending observe value to thingsboard from ObservationListener.onResponse: object, instance, SingleResource or MultipleResource
276 276 *
277 277 * @param registration - Registration LwM2M Client
... ... @@ -279,7 +279,7 @@ public class LwM2mTransportServiceImpl implements LwM2mTransportService {
279 279 * @param response - observe
280 280 */
281 281 @Override
282   - public void onObservationResponse(Registration registration, String path, ReadResponse response) {
  282 + public void onObservationResponse(Registration registration, String path, ReadResponse response, Lwm2mClientRpcRequest rpcRequest) {
283 283 if (response.getContent() != null) {
284 284 if (response.getContent() instanceof LwM2mObject) {
285 285 LwM2mObject lwM2mObject = (LwM2mObject) response.getContent();
... ... @@ -289,6 +289,13 @@ public class LwM2mTransportServiceImpl implements LwM2mTransportService {
289 289 this.updateObjectInstanceResourceValue(registration, lwM2mObjectInstance, path);
290 290 } else if (response.getContent() instanceof LwM2mResource) {
291 291 LwM2mResource lwM2mResource = (LwM2mResource) response.getContent();
  292 + if (rpcRequest != null) {
  293 + Object valueResp = lwM2mResource.isMultiInstances() ? lwM2mResource.getValues() : lwM2mResource.getValue();
  294 + Object value = this.converter.convertValue(valueResp, lwM2mResource.getType(), ResourceModel.Type.STRING,
  295 + new LwM2mPath(convertPathFromIdVerToObjectId(path)));
  296 + rpcRequest.setValueMsg(String.format("%s", value));
  297 + this.sentRpcRequest(rpcRequest, response.getCode().getName(), (String) value, LOG_LW2M_VALUE);
  298 + }
292 299 this.updateResourcesValue(registration, lwM2mResource, path);
293 300 }
294 301 }
... ... @@ -307,11 +314,12 @@ public class LwM2mTransportServiceImpl implements LwM2mTransportService {
307 314 if (msg.getSharedUpdatedCount() > 0) {
308 315 msg.getSharedUpdatedList().forEach(tsKvProto -> {
309 316 String pathName = tsKvProto.getKv().getKey();
310   - String pathIdVer = this.validatePathIntoProfile(sessionInfo, pathName);
  317 + String pathIdVer = this.getPresentPathIntoProfile(sessionInfo, pathName);
311 318 Object valueNew = this.lwM2mTransportContextServer.getValueFromKvProto(tsKvProto.getKv());
312 319 LwM2mClient lwM2MClient = lwM2mClientContext.getLwM2mClient(new UUID(sessionInfo.getSessionIdMSB(), sessionInfo.getSessionIdLSB()));
313 320 if (pathIdVer != null) {
314   - ResourceModel resourceModel = lwM2MClient.getResourceModel(pathIdVer);
  321 + ResourceModel resourceModel = lwM2MClient.getResourceModel(pathIdVer, this.lwM2mTransportContextServer.getLwM2MTransportConfigServer()
  322 + .getModelProvider());
315 323 if (resourceModel != null && resourceModel.operations.isWritable()) {
316 324 this.updateResourcesValueToClient(lwM2MClient, this.getResourceValueFormatKv(lwM2MClient, pathIdVer), valueNew, pathIdVer);
317 325 } else {
... ... @@ -380,8 +388,124 @@ public class LwM2mTransportServiceImpl implements LwM2mTransportService {
380 388 lwM2mClientContext.getLwM2mClients().values().stream().forEach(e -> e.deleteResources(pathIdVer, this.lwM2mTransportContextServer.getLwM2MTransportConfigServer().getModelProvider()));
381 389 }
382 390
383   - public void onToDeviceRpcRequest(TransportProtos.ToDeviceRpcRequestMsg toDeviceRequest) {
384   - log.info("[{}] toDeviceRpcRequest", toDeviceRequest);
  391 + @Override
  392 + public void onToDeviceRpcRequest(TransportProtos.ToDeviceRpcRequestMsg toDeviceRequest, SessionInfoProto sessionInfo) {
  393 + Lwm2mClientRpcRequest lwm2mClientRpcRequest = null;
  394 + try {
  395 + log.info("[{}] toDeviceRpcRequest", toDeviceRequest);
  396 + Registration registration = lwM2mClientContext.getLwM2mClient(new UUID(sessionInfo.getSessionIdMSB(), sessionInfo.getSessionIdLSB())).getRegistration();
  397 + lwm2mClientRpcRequest = this.getDeviceRpcRequest(toDeviceRequest, sessionInfo, registration);
  398 + if (lwm2mClientRpcRequest != null && lwm2mClientRpcRequest.getErrorMsg() != null) {
  399 + lwm2mClientRpcRequest.setResponseCode(BAD_REQUEST.name());
  400 + this.onToDeviceRpcResponse(lwm2mClientRpcRequest.getDeviceRpcResponseResultMsg(), sessionInfo);
  401 + } else {
  402 + lwM2mTransportRequest.sendAllRequest(registration, lwm2mClientRpcRequest.getTargetIdVer(), lwm2mClientRpcRequest.getTypeOper(), lwm2mClientRpcRequest.getContentFormatName(),
  403 + lwm2mClientRpcRequest.getValue() == null ? lwm2mClientRpcRequest.getParams() : lwm2mClientRpcRequest.getValue(),
  404 + this.lwM2mTransportContextServer.getLwM2MTransportConfigServer().getTimeout(), lwm2mClientRpcRequest);
  405 + }
  406 + } catch (Exception e) {
  407 + if (lwm2mClientRpcRequest == null) {
  408 + lwm2mClientRpcRequest = new Lwm2mClientRpcRequest();
  409 + }
  410 + lwm2mClientRpcRequest.setResponseCode(BAD_REQUEST.name());
  411 + if (lwm2mClientRpcRequest.getErrorMsg() == null) {
  412 + lwm2mClientRpcRequest.setErrorMsg(e.getMessage());
  413 + }
  414 + this.onToDeviceRpcResponse(lwm2mClientRpcRequest.getDeviceRpcResponseResultMsg(), sessionInfo);
  415 + }
  416 + }
  417 +
  418 + /**
  419 + * @param toDeviceRequest -
  420 + * @param sessionInfo -
  421 + * @param registration -
  422 + * @return
  423 + * @throws IllegalArgumentException
  424 + */
  425 + private Lwm2mClientRpcRequest getDeviceRpcRequest(TransportProtos.ToDeviceRpcRequestMsg toDeviceRequest,
  426 + SessionInfoProto sessionInfo, Registration registration) throws IllegalArgumentException {
  427 + Lwm2mClientRpcRequest lwm2mClientRpcRequest = new Lwm2mClientRpcRequest();
  428 + try {
  429 + lwm2mClientRpcRequest.setRequestId(toDeviceRequest.getRequestId());
  430 + lwm2mClientRpcRequest.setSessionInfo(sessionInfo);
  431 + lwm2mClientRpcRequest.setValidTypeOper(toDeviceRequest.getMethodName());
  432 + JsonObject rpcRequest = LwM2mTransportHandler.validateJson(toDeviceRequest.getParams());
  433 + if (rpcRequest != null) {
  434 + if (rpcRequest.has(lwm2mClientRpcRequest.keyNameKey)) {
  435 + String targetIdVer = this.getPresentPathIntoProfile(sessionInfo,
  436 + rpcRequest.get(lwm2mClientRpcRequest.keyNameKey).getAsString());
  437 + if (targetIdVer != null) {
  438 + lwm2mClientRpcRequest.setTargetIdVer(targetIdVer);
  439 + lwm2mClientRpcRequest.setInfoMsg(String.format("Changed by: key - %s, pathIdVer - %s",
  440 + rpcRequest.get(lwm2mClientRpcRequest.keyNameKey).getAsString(), targetIdVer));
  441 + }
  442 + }
  443 + if (lwm2mClientRpcRequest.getTargetIdVer() == null) {
  444 + lwm2mClientRpcRequest.setValidTargetIdVerKey(rpcRequest, registration);
  445 + }
  446 + if (rpcRequest.has(lwm2mClientRpcRequest.contentFormatNameKey)) {
  447 + lwm2mClientRpcRequest.setValidContentFormatName(rpcRequest);
  448 + }
  449 + if (rpcRequest.has(lwm2mClientRpcRequest.timeoutInMsKey) && rpcRequest.get(lwm2mClientRpcRequest.timeoutInMsKey).getAsLong() > 0) {
  450 + lwm2mClientRpcRequest.setTimeoutInMs(rpcRequest.get(lwm2mClientRpcRequest.timeoutInMsKey).getAsLong());
  451 + }
  452 + if (rpcRequest.has(lwm2mClientRpcRequest.valueKey)) {
  453 + lwm2mClientRpcRequest.setValue(rpcRequest.get(lwm2mClientRpcRequest.valueKey).getAsString());
  454 + }
  455 + if (rpcRequest.has(lwm2mClientRpcRequest.paramsKey) && rpcRequest.get(lwm2mClientRpcRequest.paramsKey).isJsonObject()) {
  456 + lwm2mClientRpcRequest.setParams(new Gson().fromJson(rpcRequest.get(lwm2mClientRpcRequest.paramsKey)
  457 + .getAsJsonObject().toString(), new TypeToken<ConcurrentHashMap<String, Object>>() {
  458 + }.getType()));
  459 + }
  460 + lwm2mClientRpcRequest.setSessionInfo(sessionInfo);
  461 + if (OBSERVE_READ_ALL != lwm2mClientRpcRequest.getTypeOper() && lwm2mClientRpcRequest.getTargetIdVer() == null) {
  462 + lwm2mClientRpcRequest.setErrorMsg(lwm2mClientRpcRequest.targetIdVerKey + " and " +
  463 + lwm2mClientRpcRequest.keyNameKey + " is null or bad format");
  464 + }
  465 + else if ((EXECUTE == lwm2mClientRpcRequest.getTypeOper()
  466 + || WRITE_REPLACE == lwm2mClientRpcRequest.getTypeOper())
  467 + && lwm2mClientRpcRequest.getTargetIdVer() !=null
  468 + && !(new LwM2mPath(convertPathFromIdVerToObjectId(lwm2mClientRpcRequest.getTargetIdVer())).isResource()
  469 + || new LwM2mPath(convertPathFromIdVerToObjectId(lwm2mClientRpcRequest.getTargetIdVer())).isResourceInstance())) {
  470 + lwm2mClientRpcRequest.setErrorMsg("Invalid parameter " + lwm2mClientRpcRequest.targetIdVerKey
  471 + + ". Only Resource or ResourceInstance can be this operation");
  472 + }
  473 + else if (WRITE_UPDATE == lwm2mClientRpcRequest.getTypeOper()){
  474 + lwm2mClientRpcRequest.setErrorMsg("Procedures In Development...");
  475 + }
  476 + } else {
  477 + lwm2mClientRpcRequest.setErrorMsg("Params of request is bad Json format.");
  478 + }
  479 + } catch (Exception e) {
  480 + throw new IllegalArgumentException(lwm2mClientRpcRequest.getErrorMsg());
  481 + }
  482 + return lwm2mClientRpcRequest;
  483 + }
  484 +
  485 + public void sentRpcRequest (Lwm2mClientRpcRequest rpcRequest, String requestCode, String msg, String typeMsg) {
  486 + rpcRequest.setResponseCode(requestCode);
  487 + if (LOG_LW2M_ERROR.equals(typeMsg)) {
  488 + rpcRequest.setInfoMsg(null);
  489 + rpcRequest.setValueMsg(null);
  490 + if (rpcRequest.getErrorMsg() == null) {
  491 + msg = msg.isEmpty() ? null : msg;
  492 + rpcRequest.setErrorMsg(msg);
  493 + }
  494 + } else if (LOG_LW2M_INFO.equals(typeMsg)) {
  495 + if (rpcRequest.getInfoMsg() == null) {
  496 + rpcRequest.setInfoMsg(msg);
  497 + }
  498 + } else if (LOG_LW2M_VALUE.equals(typeMsg)) {
  499 + if (rpcRequest.getValueMsg() == null) {
  500 + rpcRequest.setValueMsg(msg);
  501 + }
  502 + }
  503 + this.onToDeviceRpcResponse(rpcRequest.getDeviceRpcResponseResultMsg(), rpcRequest.getSessionInfo());
  504 + }
  505 +
  506 + @Override
  507 + public void onToDeviceRpcResponse(TransportProtos.ToDeviceRpcResponseMsg toDeviceResponse, SessionInfoProto sessionInfo) {
  508 + transportService.process(sessionInfo, toDeviceResponse, null);
385 509 }
386 510
387 511 public void onToServerRpcResponse(TransportProtos.ToServerRpcResponseMsg toServerResponse) {
... ... @@ -395,8 +519,8 @@ public class LwM2mTransportServiceImpl implements LwM2mTransportService {
395 519 */
396 520 @Override
397 521 public void doTrigger(Registration registration, String path) {
398   - lwM2mTransportRequest.sendAllRequest(registration, path, POST_TYPE_OPER_EXECUTE,
399   - ContentFormat.TLV.getName(), null, null, this.lwM2mTransportContextServer.getLwM2MTransportConfigServer().getTimeout());
  522 + lwM2mTransportRequest.sendAllRequest(registration, path, EXECUTE,
  523 + ContentFormat.TLV.getName(), null, this.lwM2mTransportContextServer.getLwM2MTransportConfigServer().getTimeout(), null);
400 524 }
401 525
402 526 /**
... ... @@ -486,14 +610,14 @@ public class LwM2mTransportServiceImpl implements LwM2mTransportService {
486 610 if (LWM2M_STRATEGY_2 == LwM2mTransportHandler.getClientOnlyObserveAfterConnect(lwM2MClientProfile)) {
487 611 // #2
488 612 lwM2MClient.getPendingRequests().addAll(clientObjects);
489   - clientObjects.forEach(path -> lwM2mTransportRequest.sendAllRequest(registration, path, GET_TYPE_OPER_READ, ContentFormat.TLV.getName(),
490   - null, null, this.lwM2mTransportContextServer.getLwM2MTransportConfigServer().getTimeout()));
  613 + clientObjects.forEach(path -> lwM2mTransportRequest.sendAllRequest(registration, path, READ, ContentFormat.TLV.getName(),
  614 + null, this.lwM2mTransportContextServer.getLwM2MTransportConfigServer().getTimeout(), null));
491 615 }
492 616 // #1
493   - this.initReadAttrTelemetryObserveToClient(registration, lwM2MClient, GET_TYPE_OPER_READ, clientObjects);
494   - this.initReadAttrTelemetryObserveToClient(registration, lwM2MClient, GET_TYPE_OPER_OBSERVE, clientObjects);
495   - this.initReadAttrTelemetryObserveToClient(registration, lwM2MClient, PUT_TYPE_OPER_WRITE_ATTRIBUTES, clientObjects);
496   - this.initReadAttrTelemetryObserveToClient(registration, lwM2MClient, GET_TYPE_OPER_DISCOVER, clientObjects);
  617 + this.initReadAttrTelemetryObserveToClient(registration, lwM2MClient, READ, clientObjects);
  618 + this.initReadAttrTelemetryObserveToClient(registration, lwM2MClient, OBSERVE, clientObjects);
  619 + this.initReadAttrTelemetryObserveToClient(registration, lwM2MClient, WRITE_ATTRIBUTES, clientObjects);
  620 + this.initReadAttrTelemetryObserveToClient(registration, lwM2MClient, DISCOVER, clientObjects);
497 621 }
498 622 }
499 623
... ... @@ -534,7 +658,8 @@ public class LwM2mTransportServiceImpl implements LwM2mTransportService {
534 658 */
535 659 private void updateResourcesValue(Registration registration, LwM2mResource lwM2mResource, String path) {
536 660 LwM2mClient lwM2MClient = lwM2mClientContext.getLwM2mClientWithReg(registration, null);
537   - if (lwM2MClient.saveResourceValue(path, lwM2mResource, this.lwM2mTransportContextServer.getLwM2MTransportConfigServer().getModelProvider())) {
  661 + if (lwM2MClient.saveResourceValue(path, lwM2mResource, this.lwM2mTransportContextServer.getLwM2MTransportConfigServer()
  662 + .getModelProvider())) {
538 663 Set<String> paths = new HashSet<>();
539 664 paths.add(path);
540 665 this.updateAttrTelemetry(registration, paths);
... ... @@ -570,64 +695,30 @@ public class LwM2mTransportServiceImpl implements LwM2mTransportService {
570 695 }
571 696
572 697 /**
573   - * @param clientProfile -
574   - * @param path -
575   - * @return true if path isPresent in postAttributeProfile
576   - */
577   - private boolean validatePathInAttrProfile(LwM2mClientProfile clientProfile, String path) {
578   - try {
579   - List<String> attributesSet = new Gson().fromJson(clientProfile.getPostAttributeProfile(),
580   - new TypeToken<List<String>>() {
581   - }.getType());
582   - return attributesSet.stream().anyMatch(p -> p.equals(path));
583   - } catch (Exception e) {
584   - log.error("Fail Validate Path [{}] ClientProfile.Attribute", path, e);
585   - return false;
586   - }
587   - }
588   -
589   - /**
590   - * @param clientProfile -
591   - * @param path -
592   - * @return true if path isPresent in postAttributeProfile
593   - */
594   - private boolean validatePathInTelemetryProfile(LwM2mClientProfile clientProfile, String path) {
595   - try {
596   - List<String> telemetriesSet = new Gson().fromJson(clientProfile.getPostTelemetryProfile(), new TypeToken<List<String>>() {
597   - }.getType());
598   - return telemetriesSet.stream().anyMatch(p -> p.equals(path));
599   - } catch (Exception e) {
600   - log.error("Fail Validate Path [{}] ClientProfile.Telemetry", path, e);
601   - return false;
602   - }
603   - }
604   -
605   - /**
606 698 * Start observe/read: Attr/Telemetry
607 699 * #1 - Analyze: path in resource profile == client resource
608 700 *
609 701 * @param registration -
610 702 */
611 703 private void initReadAttrTelemetryObserveToClient(Registration registration, LwM2mClient lwM2MClient,
612   - String typeOper, Set<String> clientObjects) {
  704 + LwM2mTypeOper typeOper, Set<String> clientObjects) {
613 705 LwM2mClientProfile lwM2MClientProfile = lwM2mClientContext.getProfile(registration);
614 706 Set<String> result = null;
615 707 ConcurrentHashMap<String, Object> params = null;
616   - if (GET_TYPE_OPER_READ.equals(typeOper)) {
  708 + if (READ.equals(typeOper)) {
617 709 result = JacksonUtil.fromString(lwM2MClientProfile.getPostAttributeProfile().toString(),
618 710 new TypeReference<>() {
619 711 });
620 712 result.addAll(JacksonUtil.fromString(lwM2MClientProfile.getPostTelemetryProfile().toString(),
621 713 new TypeReference<>() {
622 714 }));
623   - } else if (GET_TYPE_OPER_OBSERVE.equals(typeOper)) {
  715 + } else if (OBSERVE.equals(typeOper)) {
624 716 result = JacksonUtil.fromString(lwM2MClientProfile.getPostObserveProfile().toString(),
625 717 new TypeReference<>() {
626 718 });
627   - } else if (GET_TYPE_OPER_DISCOVER.equals(typeOper)) {
  719 + } else if (DISCOVER.equals(typeOper)) {
628 720 result = this.getPathForWriteAttributes(lwM2MClientProfile.getPostAttributeLwm2mProfile()).keySet();
629   - ;
630   - } else if (PUT_TYPE_OPER_WRITE_ATTRIBUTES.equals(typeOper)) {
  721 + } else if (WRITE_ATTRIBUTES.equals(typeOper)) {
631 722 params = this.getPathForWriteAttributes(lwM2MClientProfile.getPostAttributeLwm2mProfile());
632 723 result = params.keySet();
633 724 }
... ... @@ -644,8 +735,8 @@ public class LwM2mTransportServiceImpl implements LwM2mTransportService {
644 735 lwM2MClient.getPendingRequests().addAll(pathSend);
645 736 ConcurrentHashMap<String, Object> finalParams = params;
646 737 pathSend.forEach(target -> lwM2mTransportRequest.sendAllRequest(registration, target, typeOper, ContentFormat.TLV.getName(),
647   - null, finalParams != null ? finalParams.get(target) : null, this.lwM2mTransportContextServer.getLwM2MTransportConfigServer().getTimeout()));
648   - if (GET_TYPE_OPER_OBSERVE.equals(typeOper)) {
  738 + finalParams != null ? finalParams.get(target) : null, this.lwM2mTransportContextServer.getLwM2MTransportConfigServer().getTimeout(), null));
  739 + if (OBSERVE.equals(typeOper)) {
649 740 lwM2MClient.initValue(this, null);
650 741 }
651 742 }
... ... @@ -718,11 +809,6 @@ public class LwM2mTransportServiceImpl implements LwM2mTransportService {
718 809 return null;
719 810 }
720 811
721   -// public TransportProtos.KeyValueProto getKvToThingsboard(String pathIdVer, Registration registration) {
722   -// ResultsResourceValue resultsResourceValue = getResultsResourceValue(pathIdVer, registration);
723   -// return resultsResourceValue != null ? this.lwM2mTransportContextServer.getKvAttrTelemetryToThingsboard(resultsResourceValue) : null;
724   -// }
725   -
726 812 private TransportProtos.KeyValueProto getKvToThingsboard(String pathIdVer, Registration registration) {
727 813 LwM2mClient lwM2MClient = this.lwM2mClientContext.getLwM2mClientWithReg(null, registration.getId());
728 814 JsonObject names = lwM2mClientContext.getProfiles().get(lwM2MClient.getProfileId()).getPostKeyNameProfile();
... ... @@ -828,18 +914,18 @@ public class LwM2mTransportServiceImpl implements LwM2mTransportService {
828 914 if (lwM2mClientContext.addUpdateProfileParameters(deviceProfile)) {
829 915 // #1
830 916 JsonArray attributeOld = lwM2MClientProfileOld.getPostAttributeProfile();
831   - Set<String> attributeSetOld = this.convertJsonArrayToSet(attributeOld);
  917 + Set<String> attributeSetOld = convertJsonArrayToSet(attributeOld);
832 918 JsonArray telemetryOld = lwM2MClientProfileOld.getPostTelemetryProfile();
833   - Set<String> telemetrySetOld = this.convertJsonArrayToSet(telemetryOld);
  919 + Set<String> telemetrySetOld = convertJsonArrayToSet(telemetryOld);
834 920 JsonArray observeOld = lwM2MClientProfileOld.getPostObserveProfile();
835 921 JsonObject keyNameOld = lwM2MClientProfileOld.getPostKeyNameProfile();
836 922 JsonObject attributeLwm2mOld = lwM2MClientProfileOld.getPostAttributeLwm2mProfile();
837 923
838 924 LwM2mClientProfile lwM2MClientProfileNew = lwM2mClientContext.getProfiles().get(deviceProfile.getUuidId());
839 925 JsonArray attributeNew = lwM2MClientProfileNew.getPostAttributeProfile();
840   - Set<String> attributeSetNew = this.convertJsonArrayToSet(attributeNew);
  926 + Set<String> attributeSetNew = convertJsonArrayToSet(attributeNew);
841 927 JsonArray telemetryNew = lwM2MClientProfileNew.getPostTelemetryProfile();
842   - Set<String> telemetrySetNew = this.convertJsonArrayToSet(telemetryNew);
  928 + Set<String> telemetrySetNew = convertJsonArrayToSet(telemetryNew);
843 929 JsonArray observeNew = lwM2MClientProfileNew.getPostObserveProfile();
844 930 JsonObject keyNameNew = lwM2MClientProfileNew.getPostKeyNameProfile();
845 931 JsonObject attributeLwm2mNew = lwM2MClientProfileNew.getPostAttributeLwm2mProfile();
... ... @@ -882,7 +968,7 @@ public class LwM2mTransportServiceImpl implements LwM2mTransportService {
882 968 // update value in Resources
883 969 registrationIds.forEach(registrationId -> {
884 970 Registration registration = lwM2mClientContext.getRegistration(registrationId);
885   - this.readResourceValueObserve(registration, sendAttrToThingsboard.getPathPostParametersAdd(), GET_TYPE_OPER_READ);
  971 + this.readResourceValueObserve(registration, sendAttrToThingsboard.getPathPostParametersAdd(), READ);
886 972 // send attr/telemetry to tingsboard for new path
887 973 this.updateAttrTelemetry(registration, sendAttrToThingsboard.getPathPostParametersAdd());
888 974 });
... ... @@ -911,7 +997,7 @@ public class LwM2mTransportServiceImpl implements LwM2mTransportService {
911 997 registrationIds.forEach(registrationId -> {
912 998 Registration registration = lwM2mClientContext.getRegistration(registrationId);
913 999 if (postObserveAnalyzer.getPathPostParametersAdd().size() > 0) {
914   - this.readResourceValueObserve(registration, postObserveAnalyzer.getPathPostParametersAdd(), GET_TYPE_OPER_OBSERVE);
  1000 + this.readResourceValueObserve(registration, postObserveAnalyzer.getPathPostParametersAdd(), OBSERVE);
915 1001 }
916 1002 // 5.3 del
917 1003 // send Request cancel observe to Client
... ... @@ -923,12 +1009,6 @@ public class LwM2mTransportServiceImpl implements LwM2mTransportService {
923 1009 }
924 1010 }
925 1011
926   - private Set<String> convertJsonArrayToSet(JsonArray jsonArray) {
927   - List<String> attributeListOld = new Gson().fromJson(jsonArray, new TypeToken<List<String>>() {
928   - }.getType());
929   - return Sets.newConcurrentHashSet(attributeListOld);
930   - }
931   -
932 1012 /**
933 1013 * Compare old list with new list after change AttrTelemetryObserve in config Profile
934 1014 *
... ... @@ -962,16 +1042,16 @@ public class LwM2mTransportServiceImpl implements LwM2mTransportService {
962 1042 * @param registration - Registration LwM2M Client
963 1043 * @param targets - path Resources == [ "/2/0/0", "/2/0/1"]
964 1044 */
965   - private void readResourceValueObserve(Registration registration, Set<String> targets, String typeOper) {
  1045 + private void readResourceValueObserve(Registration registration, Set<String> targets, LwM2mTypeOper typeOper) {
966 1046 targets.forEach(target -> {
967 1047 LwM2mPath pathIds = new LwM2mPath(convertPathFromIdVerToObjectId(target));
968 1048 if (pathIds.isResource()) {
969   - if (GET_TYPE_OPER_READ.equals(typeOper)) {
  1049 + if (READ.equals(typeOper)) {
970 1050 lwM2mTransportRequest.sendAllRequest(registration, target, typeOper,
971   - ContentFormat.TLV.getName(), null, null, this.lwM2mTransportContextServer.getLwM2MTransportConfigServer().getTimeout());
972   - } else if (GET_TYPE_OPER_OBSERVE.equals(typeOper)) {
  1051 + ContentFormat.TLV.getName(), null, this.lwM2mTransportContextServer.getLwM2MTransportConfigServer().getTimeout(), null);
  1052 + } else if (OBSERVE.equals(typeOper)) {
973 1053 lwM2mTransportRequest.sendAllRequest(registration, target, typeOper,
974   - null, null, null, this.lwM2mTransportContextServer.getLwM2MTransportConfigServer().getTimeout());
  1054 + null, null, this.lwM2mTransportContextServer.getLwM2MTransportConfigServer().getTimeout(), null);
975 1055 }
976 1056 }
977 1057 });
... ... @@ -1026,8 +1106,8 @@ public class LwM2mTransportServiceImpl implements LwM2mTransportService {
1026 1106 .collect(Collectors.toUnmodifiableSet());
1027 1107 if (!pathSend.isEmpty()) {
1028 1108 ConcurrentHashMap<String, Object> finalParams = lwm2mAttributesNew;
1029   - pathSend.forEach(target -> lwM2mTransportRequest.sendAllRequest(registration, target, PUT_TYPE_OPER_WRITE_ATTRIBUTES, ContentFormat.TLV.getName(),
1030   - null, finalParams.get(target), this.lwM2mTransportContextServer.getLwM2MTransportConfigServer().getTimeout()));
  1109 + pathSend.forEach(target -> lwM2mTransportRequest.sendAllRequest(registration, target, WRITE_ATTRIBUTES, ContentFormat.TLV.getName(),
  1110 + finalParams.get(target), this.lwM2mTransportContextServer.getLwM2MTransportConfigServer().getTimeout(), null));
1031 1111 }
1032 1112 });
1033 1113 }
... ... @@ -1043,8 +1123,8 @@ public class LwM2mTransportServiceImpl implements LwM2mTransportService {
1043 1123 Map<String, Object> params = (Map<String, Object>) lwm2mAttributesOld.get(target);
1044 1124 params.clear();
1045 1125 params.put(OBJECT_VERSION, "");
1046   - lwM2mTransportRequest.sendAllRequest(registration, target, PUT_TYPE_OPER_WRITE_ATTRIBUTES, ContentFormat.TLV.getName(),
1047   - null, params, this.lwM2mTransportContextServer.getLwM2MTransportConfigServer().getTimeout());
  1126 + lwM2mTransportRequest.sendAllRequest(registration, target, WRITE_ATTRIBUTES, ContentFormat.TLV.getName(),
  1127 + params, this.lwM2mTransportContextServer.getLwM2MTransportConfigServer().getTimeout(), null);
1048 1128 });
1049 1129 }
1050 1130 });
... ... @@ -1054,9 +1134,10 @@ public class LwM2mTransportServiceImpl implements LwM2mTransportService {
1054 1134
1055 1135 private void cancelObserveIsValue(Registration registration, Set<String> paramAnallyzer) {
1056 1136 LwM2mClient lwM2MClient = lwM2mClientContext.getLwM2mClientWithReg(registration, null);
1057   - paramAnallyzer.forEach(p -> {
1058   - if (this.getResourceValueFromLwM2MClient(lwM2MClient, p) != null) {
1059   - this.setCancelObservationRecourse(registration, convertPathFromIdVerToObjectId(p));
  1137 + paramAnallyzer.forEach(pathIdVer -> {
  1138 + if (this.getResourceValueFromLwM2MClient(lwM2MClient, pathIdVer) != null) {
  1139 + lwM2mTransportRequest.sendAllRequest(registration, pathIdVer, OBSERVE_CANCEL, null,
  1140 + null, this.lwM2mTransportContextServer.getLwM2MTransportConfigServer().getTimeout(), null);
1060 1141 }
1061 1142 }
1062 1143 );
... ... @@ -1064,8 +1145,9 @@ public class LwM2mTransportServiceImpl implements LwM2mTransportService {
1064 1145
1065 1146 private void updateResourcesValueToClient(LwM2mClient lwM2MClient, Object valueOld, Object valueNew, String path) {
1066 1147 if (valueNew != null && (valueOld == null || !valueNew.toString().equals(valueOld.toString()))) {
1067   - lwM2mTransportRequest.sendAllRequest(lwM2MClient.getRegistration(), path, POST_TYPE_OPER_WRITE_REPLACE,
1068   - ContentFormat.TLV.getName(), null, valueNew, this.lwM2mTransportContextServer.getLwM2MTransportConfigServer().getTimeout());
  1148 + lwM2mTransportRequest.sendAllRequest(lwM2MClient.getRegistration(), path, WRITE_REPLACE,
  1149 + ContentFormat.TLV.getName(), valueNew,
  1150 + this.lwM2mTransportContextServer.getLwM2MTransportConfigServer().getTimeout(), null);
1069 1151 } else {
1070 1152 log.error("Failed update resource [{}] [{}]", path, valueNew);
1071 1153 String logMsg = String.format("%s: Failed update resource path - %s value - %s. Value is not changed or bad",
... ... @@ -1084,19 +1166,6 @@ public class LwM2mTransportServiceImpl implements LwM2mTransportService {
1084 1166 }
1085 1167
1086 1168 /**
1087   - * Get path to resource from profile equal keyName or from ModelObject equal name
1088   - * Only for resource: isWritable && isPresent as attribute in profile -> LwM2MClientProfile (format: CamelCase)
1089   - *
1090   - * @param sessionInfo -
1091   - * @param name -
1092   - * @return path if path isPresent in postProfile
1093   - */
1094   - private String validatePathIntoProfile(TransportProtos.SessionInfoProto sessionInfo, String name) {
1095   - String pathIdVer = this.getPresentPathIntoProfile(sessionInfo, name);
1096   - return !pathIdVer.isEmpty() ? pathIdVer : null;
1097   - }
1098   -
1099   - /**
1100 1169 * Get path to resource from profile equal keyName
1101 1170 *
1102 1171 * @param sessionInfo -
... ... @@ -1108,7 +1177,7 @@ public class LwM2mTransportServiceImpl implements LwM2mTransportService {
1108 1177 LwM2mClient lwM2mClient = lwM2mClientContext.getLwM2MClient(sessionInfo);
1109 1178 return profile.getPostKeyNameProfile().getAsJsonObject().entrySet().stream()
1110 1179 .filter(e -> e.getValue().getAsString().equals(name) && validateResourceInModel(lwM2mClient, e.getKey(), false)).findFirst().map(Map.Entry::getKey)
1111   - .orElse("");
  1180 + .orElse(null);
1112 1181 }
1113 1182
1114 1183 /**
... ... @@ -1140,7 +1209,7 @@ public class LwM2mTransportServiceImpl implements LwM2mTransportService {
1140 1209 public void updateAttriuteFromThingsboard(List<TransportProtos.TsKvProto> tsKvProtos, TransportProtos.SessionInfoProto sessionInfo) {
1141 1210 LwM2mClient lwM2MClient = lwM2mClientContext.getLwM2MClient(sessionInfo);
1142 1211 tsKvProtos.forEach(tsKvProto -> {
1143   - String pathIdVer = this.validatePathIntoProfile(sessionInfo, tsKvProto.getKv().getKey());
  1212 + String pathIdVer = this.getPresentPathIntoProfile(sessionInfo, tsKvProto.getKv().getKey());
1144 1213 if (pathIdVer != null) {
1145 1214 // #1.1
1146 1215 if (lwM2MClient.getDelayedRequests().containsKey(pathIdVer) && tsKvProto.getTs() > lwM2MClient.getDelayedRequests().get(pathIdVer).getTs()) {
... ... @@ -1276,7 +1345,8 @@ public class LwM2mTransportServiceImpl implements LwM2mTransportService {
1276 1345 }
1277 1346
1278 1347 private boolean validateResourceInModel(LwM2mClient lwM2mClient, String pathIdVer, boolean isWritableNotOptional) {
1279   - ResourceModel resourceModel = lwM2mClient.getResourceModel(pathIdVer);
  1348 + ResourceModel resourceModel = lwM2mClient.getResourceModel(pathIdVer, this.lwM2mTransportContextServer.getLwM2MTransportConfigServer()
  1349 + .getModelProvider());
1280 1350 Integer objectId = new LwM2mPath(convertPathFromIdVerToObjectId(pathIdVer)).getObjectId();
1281 1351 String objectVer = validateObjectVerFromKey(pathIdVer);
1282 1352 return resourceModel != null && (isWritableNotOptional ?
... ...
... ... @@ -20,6 +20,7 @@ import lombok.extern.slf4j.Slf4j;
20 20 import org.eclipse.leshan.core.model.ResourceModel;
21 21 import org.eclipse.leshan.core.node.LwM2mPath;
22 22 import org.eclipse.leshan.core.node.LwM2mResource;
  23 +import org.eclipse.leshan.core.node.LwM2mSingleResource;
23 24 import org.eclipse.leshan.server.model.LwM2mModelProvider;
24 25 import org.eclipse.leshan.server.registration.Registration;
25 26 import org.eclipse.leshan.server.security.SecurityInfo;
... ... @@ -27,7 +28,9 @@ import org.thingsboard.server.gen.transport.TransportProtos;
27 28 import org.thingsboard.server.gen.transport.TransportProtos.ValidateDeviceCredentialsResponseMsg;
28 29 import org.thingsboard.server.transport.lwm2m.server.LwM2mQueuedRequest;
29 30 import org.thingsboard.server.transport.lwm2m.server.LwM2mTransportServiceImpl;
  31 +import org.thingsboard.server.transport.lwm2m.utils.LwM2mValueConverterImpl;
30 32
  33 +import java.util.Collection;
31 34 import java.util.List;
32 35 import java.util.Map;
33 36 import java.util.Queue;
... ... @@ -39,7 +42,9 @@ import java.util.concurrent.CopyOnWriteArrayList;
39 42 import java.util.stream.Collectors;
40 43
41 44 import static org.thingsboard.server.common.data.lwm2m.LwM2mConstants.LWM2M_SEPARATOR_PATH;
  45 +import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.TRANSPORT_DEFAULT_LWM2M_VERSION;
42 46 import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.convertPathFromIdVerToObjectId;
  47 +import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.getVerFromPathIdVerOrId;
43 48
44 49 @Slf4j
45 50 @Data
... ... @@ -94,12 +99,33 @@ public class LwM2mClient implements Cloneable {
94 99 }
95 100 }
96 101
97   - public ResourceModel getResourceModel(String pathRez) {
98   - if (this.getResources().get(pathRez) != null) {
99   - return this.getResources().get(pathRez).getResourceModel();
100   - } else {
101   - return null;
102   - }
  102 + public ResourceModel getResourceModel(String pathRez, LwM2mModelProvider modelProvider) {
  103 + LwM2mPath pathIds = new LwM2mPath(convertPathFromIdVerToObjectId(pathRez));
  104 + String verSupportedObject = registration.getSupportedObject().get(pathIds.getObjectId());
  105 + String verRez = getVerFromPathIdVerOrId(pathRez);
  106 + return (verRez == null || verSupportedObject.equals(verRez)) ? modelProvider.getObjectModel(registration)
  107 + .getResourceModel(pathIds.getObjectId(), pathIds.getResourceId()) : null;
  108 + }
  109 +
  110 + public Collection<LwM2mResource> getNewResourcesForInstance(String pathRezIdVer, LwM2mModelProvider modelProvider,
  111 + LwM2mValueConverterImpl converter) {
  112 + LwM2mPath pathIds = new LwM2mPath(convertPathFromIdVerToObjectId(pathRezIdVer));
  113 + String verSupportedObject = registration.getSupportedObject().get(pathIds.getObjectId());
  114 + String verRez = getVerFromPathIdVerOrId(pathRezIdVer);
  115 + Collection<LwM2mResource> resources = ConcurrentHashMap.newKeySet();
  116 + Map<Integer, ResourceModel> resourceModels = modelProvider.getObjectModel(registration)
  117 + .getObjectModel(pathIds.getObjectId()).resources;
  118 + resourceModels.forEach((k, resourceModel) -> {
  119 + resources.add(LwM2mSingleResource.newResource(k, converter.convertValue("0", ResourceModel.Type.STRING, resourceModel.type, pathIds), resourceModel.type));
  120 + });
  121 + return resources;
  122 + }
  123 +
  124 + public boolean isValidObjectVersion (String path) {
  125 + LwM2mPath pathIds = new LwM2mPath(convertPathFromIdVerToObjectId(path));
  126 + String verSupportedObject = registration.getSupportedObject().get(pathIds.getObjectId());
  127 + String verRez = getVerFromPathIdVerOrId(path);
  128 + return verRez == null ? TRANSPORT_DEFAULT_LWM2M_VERSION.equals(verSupportedObject) : verRez.equals(verSupportedObject);
103 129 }
104 130
105 131 /**
... ...
... ... @@ -26,7 +26,6 @@ import org.thingsboard.server.transport.lwm2m.secure.LwM2MSecurityMode;
26 26 import org.thingsboard.server.transport.lwm2m.secure.LwM2mCredentialsSecurityInfoValidator;
27 27 import org.thingsboard.server.transport.lwm2m.secure.ReadResultSecurityStore;
28 28 import org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler;
29   -import org.thingsboard.server.transport.lwm2m.utils.TypeServer;
30 29
31 30 import java.util.Arrays;
32 31 import java.util.Map;
... ... @@ -119,7 +118,7 @@ public class LwM2mClientContextImpl implements LwM2mClientContext {
119 118 */
120 119 @Override
121 120 public LwM2mClient addLwM2mClientToSession(String identity) {
122   - ReadResultSecurityStore store = lwM2MCredentialsSecurityInfoValidator.createAndValidateCredentialsSecurityInfo(identity, TypeServer.CLIENT);
  121 + ReadResultSecurityStore store = lwM2MCredentialsSecurityInfoValidator.createAndValidateCredentialsSecurityInfo(identity, LwM2mTransportHandler.LwM2mTypeServer.CLIENT);
123 122 if (store.getSecurityMode() < LwM2MSecurityMode.DEFAULT_MODE.code) {
124 123 UUID profileUuid = (store.getDeviceProfile() != null && addUpdateProfileParameters(store.getDeviceProfile())) ? store.getDeviceProfile().getUuidId() : null;
125 124 LwM2mClient client;
... ...
  1 +/**
  2 + * Copyright © 2016-2021 The Thingsboard Authors
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +package org.thingsboard.server.transport.lwm2m.server.client;
  17 +
  18 +import com.google.gson.JsonObject;
  19 +import lombok.Data;
  20 +import org.eclipse.leshan.core.request.ContentFormat;
  21 +import org.eclipse.leshan.server.registration.Registration;
  22 +import org.thingsboard.server.gen.transport.TransportProtos;
  23 +import org.thingsboard.server.gen.transport.TransportProtos.SessionInfoProto;
  24 +import org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.LwM2mTypeOper;
  25 +
  26 +import java.util.concurrent.ConcurrentHashMap;
  27 +
  28 +import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.validPathIdVer;
  29 +
  30 +@Data
  31 +public class Lwm2mClientRpcRequest {
  32 + public final String targetIdVerKey = "targetIdVer";
  33 + public final String keyNameKey = "key";
  34 + public final String typeOperKey = "typeOper";
  35 + public final String contentFormatNameKey = "contentFormatName";
  36 + public final String valueKey = "value";
  37 + public final String infoKey = "info";
  38 + public final String paramsKey = "params";
  39 + public final String timeoutInMsKey = "timeOutInMs";
  40 + public final String resultKey = "result";
  41 + public final String errorKey = "error";
  42 + public final String methodKey = "methodName";
  43 +
  44 + private LwM2mTypeOper typeOper;
  45 + private String targetIdVer;
  46 + private String contentFormatName;
  47 + private long timeoutInMs;
  48 + private Object value;
  49 + private ConcurrentHashMap<String, Object> params;
  50 + private SessionInfoProto sessionInfo;
  51 + private int requestId;
  52 + private String errorMsg;
  53 + private String valueMsg;
  54 + private String infoMsg;
  55 + private String responseCode;
  56 +
  57 + public void setValidTypeOper (String typeOper){
  58 + try {
  59 + this.typeOper = LwM2mTypeOper.fromLwLwM2mTypeOper(typeOper);
  60 + } catch (Exception e) {
  61 + this.errorMsg = this.methodKey + " - " + typeOper + " is not valid.";
  62 + }
  63 + }
  64 + public void setValidContentFormatName (JsonObject rpcRequest){
  65 + try {
  66 + if (ContentFormat.fromName(rpcRequest.get(this.contentFormatNameKey).getAsString()) != null) {
  67 + this.contentFormatName = rpcRequest.get(this.contentFormatNameKey).getAsString();
  68 + }
  69 + else {
  70 + this.errorMsg = this.contentFormatNameKey + " - " + rpcRequest.get(this.contentFormatNameKey).getAsString() + " is not valid.";
  71 + }
  72 + } catch (Exception e) {
  73 + this.errorMsg = this.contentFormatNameKey + " - " + rpcRequest.get(this.contentFormatNameKey).getAsString() + " is not valid.";
  74 + }
  75 + }
  76 +
  77 + public void setValidTargetIdVerKey (JsonObject rpcRequest, Registration registration){
  78 + if (rpcRequest.has(this.targetIdVerKey)) {
  79 + String targetIdVerStr = rpcRequest.get(targetIdVerKey).getAsString();
  80 + // targetIdVer without ver - ok
  81 + try {
  82 + // targetIdVer with/without ver - ok
  83 + this.targetIdVer = validPathIdVer(targetIdVerStr, registration);
  84 + if (this.targetIdVer != null){
  85 + this.infoMsg = String.format("Changed by: pathIdVer - %s", this.targetIdVer);
  86 + }
  87 + } catch (Exception e) {
  88 + if (this.targetIdVer == null) {
  89 + this.errorMsg = this.targetIdVerKey + " - " + targetIdVerStr + " is not valid.";
  90 + }
  91 + }
  92 + }
  93 + }
  94 +
  95 + public TransportProtos.ToDeviceRpcResponseMsg getDeviceRpcResponseResultMsg() {
  96 + JsonObject payloadResp = new JsonObject();
  97 + payloadResp.addProperty(this.resultKey, this.responseCode);
  98 + if (this.errorMsg != null) {
  99 + payloadResp.addProperty(this.errorKey, this.errorMsg);
  100 + }
  101 + else if (this.valueMsg != null) {
  102 + payloadResp.addProperty(this.valueKey, this.valueMsg);
  103 + }
  104 + else if (this.infoMsg != null) {
  105 + payloadResp.addProperty(this.infoKey, this.infoMsg);
  106 + }
  107 + return TransportProtos.ToDeviceRpcResponseMsg.newBuilder()
  108 + .setPayload(payloadResp.getAsJsonObject().toString())
  109 + .setRequestId(this.requestId)
  110 + .build();
  111 + }
  112 +}
... ...
1   -/**
2   - * Copyright © 2016-2021 The Thingsboard Authors
3   - *
4   - * Licensed under the Apache License, Version 2.0 (the "License");
5   - * you may not use this file except in compliance with the License.
6   - * You may obtain a copy of the License at
7   - *
8   - * http://www.apache.org/licenses/LICENSE-2.0
9   - *
10   - * Unless required by applicable law or agreed to in writing, software
11   - * distributed under the License is distributed on an "AS IS" BASIS,
12   - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   - * See the License for the specific language governing permissions and
14   - * limitations under the License.
15   - */
16   -package org.thingsboard.server.transport.lwm2m.server.client;
17   -
18   -import lombok.Data;
19   -import org.thingsboard.server.common.data.kv.DataType;
20   -
21   -@Data
22   -public class ResultsResourceValue {
23   - DataType dataType;
24   - Object value;
25   - String resourceName;
26   -
27   - public ResultsResourceValue (DataType dataType, Object value, String resourceName) {
28   - this.dataType = dataType;
29   - this.value = value;
30   - this.resourceName = resourceName;
31   - }
32   -}
1   -/**
2   - * Copyright © 2016-2021 The Thingsboard Authors
3   - *
4   - * Licensed under the Apache License, Version 2.0 (the "License");
5   - * you may not use this file except in compliance with the License.
6   - * You may obtain a copy of the License at
7   - *
8   - * http://www.apache.org/licenses/LICENSE-2.0
9   - *
10   - * Unless required by applicable law or agreed to in writing, software
11   - * distributed under the License is distributed on an "AS IS" BASIS,
12   - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   - * See the License for the specific language governing permissions and
14   - * limitations under the License.
15   - */
16   -package org.thingsboard.server.transport.lwm2m.utils;
17   -
18   -public enum TypeServer {
19   - BOOTSTRAP(0, "bootstrap"),
20   - CLIENT(1, "client");
21   -
22   - public int code;
23   - public String type;
24   -
25   - TypeServer(int code, String type) {
26   - this.code = code;
27   - this.type = type;
28   - }
29   -}