Commit 4f2e72071d757acda77718ea7ce422a984ecc59b

Authored by nickAS21
1 parent c57fc550

LWM2M: add requestUUID

@@ -23,6 +23,7 @@ import com.google.gson.JsonElement; @@ -23,6 +23,7 @@ import com.google.gson.JsonElement;
23 import com.google.gson.JsonObject; 23 import com.google.gson.JsonObject;
24 import com.google.gson.reflect.TypeToken; 24 import com.google.gson.reflect.TypeToken;
25 import lombok.extern.slf4j.Slf4j; 25 import lombok.extern.slf4j.Slf4j;
  26 +import org.apache.commons.lang3.StringUtils;
26 import org.eclipse.leshan.core.model.ObjectModel; 27 import org.eclipse.leshan.core.model.ObjectModel;
27 import org.eclipse.leshan.core.model.ResourceModel; 28 import org.eclipse.leshan.core.model.ResourceModel;
28 import org.eclipse.leshan.core.node.LwM2mObject; 29 import org.eclipse.leshan.core.node.LwM2mObject;
@@ -61,6 +62,7 @@ import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient; @@ -61,6 +62,7 @@ import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient;
61 import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClientContext; 62 import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClientContext;
62 import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClientProfile; 63 import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClientProfile;
63 import org.thingsboard.server.transport.lwm2m.server.client.Lwm2mClientRpcRequest; 64 import org.thingsboard.server.transport.lwm2m.server.client.Lwm2mClientRpcRequest;
  65 +import org.thingsboard.server.transport.lwm2m.server.client.ResourceValue;
64 import org.thingsboard.server.transport.lwm2m.server.client.ResultsAddKeyValueProto; 66 import org.thingsboard.server.transport.lwm2m.server.client.ResultsAddKeyValueProto;
65 import org.thingsboard.server.transport.lwm2m.server.client.ResultsAnalyzerParameters; 67 import org.thingsboard.server.transport.lwm2m.server.client.ResultsAnalyzerParameters;
66 import org.thingsboard.server.transport.lwm2m.server.store.TbLwM2MDtlsSessionStore; 68 import org.thingsboard.server.transport.lwm2m.server.store.TbLwM2MDtlsSessionStore;
@@ -99,21 +101,20 @@ import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.L @@ -99,21 +101,20 @@ import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.L
99 import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LOG_LW2M_VALUE; 101 import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LOG_LW2M_VALUE;
100 import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LWM2M_STRATEGY_2; 102 import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LWM2M_STRATEGY_2;
101 import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LwM2mTypeOper.DISCOVER; 103 import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LwM2mTypeOper.DISCOVER;
102 -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LwM2mTypeOper.DISCOVER_All;  
103 import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LwM2mTypeOper.EXECUTE; 104 import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LwM2mTypeOper.EXECUTE;
104 import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LwM2mTypeOper.OBSERVE; 105 import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LwM2mTypeOper.OBSERVE;
105 import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LwM2mTypeOper.OBSERVE_CANCEL; 106 import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LwM2mTypeOper.OBSERVE_CANCEL;
106 -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LwM2mTypeOper.OBSERVE_READ_ALL; 107 +import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LwM2mTypeOper.OBSERVE_CANCEL_ALL;
107 import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LwM2mTypeOper.READ; 108 import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LwM2mTypeOper.READ;
108 import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LwM2mTypeOper.WRITE_ATTRIBUTES; 109 import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LwM2mTypeOper.WRITE_ATTRIBUTES;
109 import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LwM2mTypeOper.WRITE_REPLACE; 110 import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LwM2mTypeOper.WRITE_REPLACE;
110 -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LwM2mTypeOper.WRITE_UPDATE;  
111 import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.SW_ID; 111 import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.SW_ID;
112 import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.SW_RESULT_ID; 112 import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.SW_RESULT_ID;
113 import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.convertJsonArrayToSet; 113 import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.convertJsonArrayToSet;
114 import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.convertPathFromIdVerToObjectId; 114 import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.convertPathFromIdVerToObjectId;
115 import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.convertPathFromObjectIdToIdVer; 115 import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.convertPathFromObjectIdToIdVer;
116 import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.getAckCallback; 116 import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.getAckCallback;
  117 +import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.setValidTypeOper;
117 import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.validateObjectVerFromKey; 118 import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.validateObjectVerFromKey;
118 119
119 120
@@ -125,7 +126,7 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler @@ -125,7 +126,7 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler
125 private ExecutorService registrationExecutor; 126 private ExecutorService registrationExecutor;
126 private ExecutorService updateRegistrationExecutor; 127 private ExecutorService updateRegistrationExecutor;
127 private ExecutorService unRegistrationExecutor; 128 private ExecutorService unRegistrationExecutor;
128 - private LwM2mValueConverterImpl converter; 129 + public LwM2mValueConverterImpl converter;
129 130
130 private final TransportService transportService; 131 private final TransportService transportService;
131 private final LwM2mTransportContext context; 132 private final LwM2mTransportContext context;
@@ -133,10 +134,10 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler @@ -133,10 +134,10 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler
133 public final FirmwareDataCache firmwareDataCache; 134 public final FirmwareDataCache firmwareDataCache;
134 public final LwM2mTransportServerHelper helper; 135 public final LwM2mTransportServerHelper helper;
135 private final LwM2MJsonAdaptor adaptor; 136 private final LwM2MJsonAdaptor adaptor;
136 - private final LwM2mClientContext clientContext;  
137 - private final LwM2mTransportRequest lwM2mTransportRequest;  
138 private final TbLwM2MDtlsSessionStore sessionStore; 137 private final TbLwM2MDtlsSessionStore sessionStore;
139 - 138 + public final LwM2mClientContext clientContext;
  139 + public final LwM2mTransportRequest lwM2mTransportRequest;
  140 + private final Map<UUID, Long> rpcSubscriptions;
140 141
141 public DefaultLwM2MTransportMsgHandler(TransportService transportService, LwM2MTransportServerConfig config, LwM2mTransportServerHelper helper, 142 public DefaultLwM2MTransportMsgHandler(TransportService transportService, LwM2MTransportServerConfig config, LwM2mTransportServerHelper helper,
142 LwM2mClientContext clientContext, 143 LwM2mClientContext clientContext,
@@ -151,6 +152,7 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler @@ -151,6 +152,7 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler
151 this.firmwareDataCache = firmwareDataCache; 152 this.firmwareDataCache = firmwareDataCache;
152 this.context = context; 153 this.context = context;
153 this.adaptor = adaptor; 154 this.adaptor = adaptor;
  155 + this.rpcSubscriptions = new ConcurrentHashMap<>();
154 this.sessionStore = sessionStore; 156 this.sessionStore = sessionStore;
155 } 157 }
156 158
@@ -241,16 +243,14 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler @@ -241,16 +243,14 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler
241 243
242 /** 244 /**
243 * @param registration - Registration LwM2M Client 245 * @param registration - Registration LwM2M Client
244 - * @param observations - All paths observations before unReg  
245 - * !!! Warn: if have not finishing unReg, then this operation will be finished on next Client`s connect 246 + * @param observations - !!! Warn: if have not finishing unReg, then this operation will be finished on next Client`s connect
246 */ 247 */
247 public void unReg(Registration registration, Collection<Observation> observations) { 248 public void unReg(Registration registration, Collection<Observation> observations) {
  249 + log.error("Client unRegistration -> test", new RuntimeException());
248 unRegistrationExecutor.submit(() -> { 250 unRegistrationExecutor.submit(() -> {
249 try { 251 try {
250 - this.setCancelObservationsAll(registration);  
251 this.sendLogsToThingsboard(LOG_LW2M_INFO + ": Client unRegistration", registration.getId()); 252 this.sendLogsToThingsboard(LOG_LW2M_INFO + ": Client unRegistration", registration.getId());
252 this.closeClientSession(registration); 253 this.closeClientSession(registration);
253 - ;  
254 } catch (Throwable t) { 254 } catch (Throwable t) {
255 log.error("[{}] endpoint [{}] error Unable un registration.", registration.getEndpoint(), t); 255 log.error("[{}] endpoint [{}] error Unable un registration.", registration.getEndpoint(), t);
256 this.sendLogsToThingsboard(LOG_LW2M_ERROR + String.format(": Client Unable un Registration, %s", t.getMessage()), registration.getId()); 256 this.sendLogsToThingsboard(LOG_LW2M_ERROR + String.format(": Client Unable un Registration, %s", t.getMessage()), registration.getId());
@@ -285,12 +285,8 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler @@ -285,12 +285,8 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler
285 @Override 285 @Override
286 public void setCancelObservationsAll(Registration registration) { 286 public void setCancelObservationsAll(Registration registration) {
287 if (registration != null) { 287 if (registration != null) {
288 - lwM2mTransportRequest.sendAllRequest(registration, null, OBSERVE_CANCEL, 288 + lwM2mTransportRequest.sendAllRequest(registration, null, OBSERVE_CANCEL_ALL,
289 null, null, this.config.getTimeout(), null); 289 null, null, this.config.getTimeout(), null);
290 -// Set<Observation> observations = context.getServer().getObservationService().getObservations(registration);  
291 -// observations.forEach(observation -> lwM2mTransportRequest.sendAllRequest(registration,  
292 -// convertPathFromObjectIdToIdVer(observation.getPath().toString(), registration), OBSERVE_CANCEL,  
293 -// null, null, this.config.getTimeout(), null));  
294 } 290 }
295 } 291 }
296 292
@@ -354,12 +350,13 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler @@ -354,12 +350,13 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler
354 */ 350 */
355 @Override 351 @Override
356 public void onAttributeUpdate(AttributeUpdateNotificationMsg msg, TransportProtos.SessionInfoProto sessionInfo) { 352 public void onAttributeUpdate(AttributeUpdateNotificationMsg msg, TransportProtos.SessionInfoProto sessionInfo) {
357 - LwM2mClient lwM2MClient = clientContext.getClient(new UUID(sessionInfo.getSessionIdMSB(), sessionInfo.getSessionIdLSB())); 353 + LwM2mClient lwM2MClient = clientContext.getClient(sessionInfo);
358 if (msg.getSharedUpdatedCount() > 0) { 354 if (msg.getSharedUpdatedCount() > 0) {
359 msg.getSharedUpdatedList().forEach(tsKvProto -> { 355 msg.getSharedUpdatedList().forEach(tsKvProto -> {
360 String pathName = tsKvProto.getKv().getKey(); 356 String pathName = tsKvProto.getKv().getKey();
361 String pathIdVer = this.getPresentPathIntoProfile(sessionInfo, pathName); 357 String pathIdVer = this.getPresentPathIntoProfile(sessionInfo, pathName);
362 Object valueNew = getValueFromKvProto(tsKvProto.getKv()); 358 Object valueNew = getValueFromKvProto(tsKvProto.getKv());
  359 + log.warn("12) Shared AttributeUpdate start pathName [{}], pathIdVer [{}], valueNew [{}]", pathName, pathIdVer, valueNew);
363 if ((FirmwareUtil.getAttributeKey(FirmwareType.FIRMWARE, FirmwareKey.VERSION).equals(pathName) 360 if ((FirmwareUtil.getAttributeKey(FirmwareType.FIRMWARE, FirmwareKey.VERSION).equals(pathName)
364 && (!valueNew.equals(lwM2MClient.getFwUpdate().getCurrentVersion()))) 361 && (!valueNew.equals(lwM2MClient.getFwUpdate().getCurrentVersion())))
365 || (FirmwareUtil.getAttributeKey(FirmwareType.FIRMWARE, FirmwareKey.TITLE).equals(pathName) 362 || (FirmwareUtil.getAttributeKey(FirmwareType.FIRMWARE, FirmwareKey.TITLE).equals(pathName)
@@ -438,121 +435,49 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler @@ -438,121 +435,49 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler
438 clientContext.getLwM2mClients().forEach(e -> e.deleteResources(pathIdVer, this.config.getModelProvider())); 435 clientContext.getLwM2mClients().forEach(e -> e.deleteResources(pathIdVer, this.config.getModelProvider()));
439 } 436 }
440 437
  438 + /**
  439 + * #1 del from rpcSubscriptions by timeout
  440 + * #2 if not present in rpcSubscriptions by requestId: create new Lwm2mClientRpcRequest, after success - add requestId, timeout
  441 + */
441 @Override 442 @Override
442 public void onToDeviceRpcRequest(TransportProtos.ToDeviceRpcRequestMsg toDeviceRpcRequestMsg, SessionInfoProto sessionInfo) { 443 public void onToDeviceRpcRequest(TransportProtos.ToDeviceRpcRequestMsg toDeviceRpcRequestMsg, SessionInfoProto sessionInfo) {
443 - log.warn("4) RPC-OK finish to [{}]", toDeviceRpcRequestMsg);  
444 - Lwm2mClientRpcRequest lwm2mClientRpcRequest = null;  
445 - try {  
446 - Registration registration = clientContext.getClient(new UUID(sessionInfo.getSessionIdMSB(), sessionInfo.getSessionIdLSB())).getRegistration();  
447 - lwm2mClientRpcRequest = this.getDeviceRpcRequest(toDeviceRpcRequestMsg, sessionInfo, registration);  
448 - if (lwm2mClientRpcRequest.getErrorMsg() != null) {  
449 - lwm2mClientRpcRequest.setResponseCode(BAD_REQUEST.name());  
450 - this.onToDeviceRpcResponse(lwm2mClientRpcRequest.getDeviceRpcResponseResultMsg(), sessionInfo);  
451 - } else {  
452 - lwM2mTransportRequest.sendAllRequest(registration, lwm2mClientRpcRequest.getTargetIdVer(), lwm2mClientRpcRequest.getTypeOper(), lwm2mClientRpcRequest.getContentFormatName(),  
453 - lwm2mClientRpcRequest.getValue() == null ? lwm2mClientRpcRequest.getParams() : lwm2mClientRpcRequest.getValue(),  
454 - this.config.getTimeout(), lwm2mClientRpcRequest);  
455 - }  
456 - } catch (Exception e) {  
457 - if (lwm2mClientRpcRequest == null) {  
458 - lwm2mClientRpcRequest = new Lwm2mClientRpcRequest();  
459 - }  
460 - lwm2mClientRpcRequest.setResponseCode(BAD_REQUEST.name());  
461 - if (lwm2mClientRpcRequest.getErrorMsg() == null) {  
462 - lwm2mClientRpcRequest.setErrorMsg(e.getMessage());  
463 - }  
464 - this.onToDeviceRpcResponse(lwm2mClientRpcRequest.getDeviceRpcResponseResultMsg(), sessionInfo);  
465 - }  
466 - }  
467 -  
468 - private Lwm2mClientRpcRequest getDeviceRpcRequest(TransportProtos.ToDeviceRpcRequestMsg toDeviceRequest,  
469 - SessionInfoProto sessionInfo, Registration registration) throws IllegalArgumentException {  
470 - Lwm2mClientRpcRequest lwm2mClientRpcRequest = new Lwm2mClientRpcRequest();  
471 - try {  
472 - lwm2mClientRpcRequest.setRequestId(toDeviceRequest.getRequestId());  
473 - lwm2mClientRpcRequest.setSessionInfo(sessionInfo);  
474 - lwm2mClientRpcRequest.setValidTypeOper(toDeviceRequest.getMethodName());  
475 - JsonObject rpcRequest = LwM2mTransportUtil.validateJson(toDeviceRequest.getParams());  
476 - if (rpcRequest != null) {  
477 - if (rpcRequest.has(lwm2mClientRpcRequest.keyNameKey)) {  
478 - String targetIdVer = this.getPresentPathIntoProfile(sessionInfo,  
479 - rpcRequest.get(lwm2mClientRpcRequest.keyNameKey).getAsString());  
480 - if (targetIdVer != null) {  
481 - lwm2mClientRpcRequest.setTargetIdVer(targetIdVer);  
482 - lwm2mClientRpcRequest.setInfoMsg(String.format("Changed by: key - %s, pathIdVer - %s",  
483 - rpcRequest.get(lwm2mClientRpcRequest.keyNameKey).getAsString(), targetIdVer));  
484 - }  
485 - }  
486 - if (lwm2mClientRpcRequest.getTargetIdVer() == null) {  
487 - lwm2mClientRpcRequest.setValidTargetIdVerKey(rpcRequest, registration);  
488 - }  
489 - if (rpcRequest.has(lwm2mClientRpcRequest.contentFormatNameKey)) {  
490 - lwm2mClientRpcRequest.setValidContentFormatName(rpcRequest);  
491 - }  
492 - if (rpcRequest.has(lwm2mClientRpcRequest.timeoutInMsKey) && rpcRequest.get(lwm2mClientRpcRequest.timeoutInMsKey).getAsLong() > 0) {  
493 - lwm2mClientRpcRequest.setTimeoutInMs(rpcRequest.get(lwm2mClientRpcRequest.timeoutInMsKey).getAsLong());  
494 - }  
495 - if (rpcRequest.has(lwm2mClientRpcRequest.valueKey)) {  
496 - lwm2mClientRpcRequest.setValue(rpcRequest.get(lwm2mClientRpcRequest.valueKey).getAsString());  
497 - }  
498 - if (rpcRequest.has(lwm2mClientRpcRequest.paramsKey) && rpcRequest.get(lwm2mClientRpcRequest.paramsKey).isJsonObject()) {  
499 - ConcurrentHashMap<String, Object> params = new Gson().fromJson(rpcRequest.get(lwm2mClientRpcRequest.paramsKey)  
500 - .getAsJsonObject().toString(), new TypeToken<ConcurrentHashMap<String, Object>>() {  
501 - }.getType());  
502 - if (WRITE_UPDATE == lwm2mClientRpcRequest.getTypeOper()) {  
503 - ConcurrentHashMap<String, Object> paramsResourceId = convertParamsToResourceId(params, sessionInfo);  
504 - if (paramsResourceId.size() > 0) {  
505 - lwm2mClientRpcRequest.setParams(paramsResourceId);  
506 - }  
507 - } else {  
508 - lwm2mClientRpcRequest.setParams(params);  
509 - }  
510 - } else if (rpcRequest.has(lwm2mClientRpcRequest.paramsKey) && rpcRequest.get(lwm2mClientRpcRequest.paramsKey).isJsonArray()) {  
511 - new Gson().fromJson(rpcRequest.get(lwm2mClientRpcRequest.paramsKey)  
512 - .getAsJsonObject().toString(), new TypeToken<ConcurrentHashMap<String, Object>>() {  
513 - }.getType()); 444 + // #1
  445 + this.checkRpcRequestTimeout();
  446 + String bodyParams = StringUtils.trimToNull(toDeviceRpcRequestMsg.getParams()) != null ? toDeviceRpcRequestMsg.getParams() : "null";
  447 + LwM2mTypeOper lwM2mTypeOper = setValidTypeOper(toDeviceRpcRequestMsg.getMethodName());
  448 + UUID requestUUID = new UUID(toDeviceRpcRequestMsg.getRequestIdMSB(), toDeviceRpcRequestMsg.getRequestIdLSB());
  449 + log.warn("4) RPC-OK finish to [{}], keys: [{}]", requestUUID, this.rpcSubscriptions.keySet());
  450 + if (!this.rpcSubscriptions.containsKey(requestUUID)) {
  451 + this.rpcSubscriptions.put(requestUUID, toDeviceRpcRequestMsg.getExpirationTime());
  452 + Lwm2mClientRpcRequest lwm2mClientRpcRequest = null;
  453 + try {
  454 + Registration registration = clientContext.getClient(sessionInfo).getRegistration();
  455 + lwm2mClientRpcRequest = new Lwm2mClientRpcRequest(lwM2mTypeOper, bodyParams, toDeviceRpcRequestMsg.getRequestId(), sessionInfo, registration, this);
  456 + if (lwm2mClientRpcRequest.getErrorMsg() != null) {
  457 + lwm2mClientRpcRequest.setResponseCode(BAD_REQUEST.name());
  458 + this.onToDeviceRpcResponse(lwm2mClientRpcRequest.getDeviceRpcResponseResultMsg(), sessionInfo);
  459 + } else {
  460 + lwM2mTransportRequest.sendAllRequest(registration, lwm2mClientRpcRequest.getTargetIdVer(), lwm2mClientRpcRequest.getTypeOper(),
  461 + null,
  462 + lwm2mClientRpcRequest.getValue() == null ? lwm2mClientRpcRequest.getParams() : lwm2mClientRpcRequest.getValue(),
  463 + this.config.getTimeout(), lwm2mClientRpcRequest);
514 } 464 }
515 - lwm2mClientRpcRequest.setSessionInfo(sessionInfo);  
516 - if (!(OBSERVE_READ_ALL == lwm2mClientRpcRequest.getTypeOper()  
517 - || DISCOVER_All == lwm2mClientRpcRequest.getTypeOper()  
518 - || OBSERVE_CANCEL == lwm2mClientRpcRequest.getTypeOper())  
519 - && lwm2mClientRpcRequest.getTargetIdVer() == null) {  
520 - lwm2mClientRpcRequest.setErrorMsg(lwm2mClientRpcRequest.targetIdVerKey + " and " +  
521 - lwm2mClientRpcRequest.keyNameKey + " is null or bad format"); 465 + } catch (Exception e) {
  466 + if (lwm2mClientRpcRequest == null) {
  467 + lwm2mClientRpcRequest = new Lwm2mClientRpcRequest();
522 } 468 }
523 - /**  
524 - * EXECUTE && WRITE_REPLACE - only for Resource or ResourceInstance  
525 - */  
526 - else if ((EXECUTE == lwm2mClientRpcRequest.getTypeOper()  
527 - || WRITE_REPLACE == lwm2mClientRpcRequest.getTypeOper())  
528 - && lwm2mClientRpcRequest.getTargetIdVer() != null  
529 - && !(new LwM2mPath(convertPathFromIdVerToObjectId(lwm2mClientRpcRequest.getTargetIdVer())).isResource()  
530 - || new LwM2mPath(convertPathFromIdVerToObjectId(lwm2mClientRpcRequest.getTargetIdVer())).isResourceInstance())) {  
531 - lwm2mClientRpcRequest.setErrorMsg("Invalid parameter " + lwm2mClientRpcRequest.targetIdVerKey  
532 - + ". Only Resource or ResourceInstance can be this operation"); 469 + lwm2mClientRpcRequest.setResponseCode(BAD_REQUEST.name());
  470 + if (lwm2mClientRpcRequest.getErrorMsg() == null) {
  471 + lwm2mClientRpcRequest.setErrorMsg(e.getMessage());
533 } 472 }
534 - } else {  
535 - lwm2mClientRpcRequest.setErrorMsg("Params of request is bad Json format."); 473 + this.onToDeviceRpcResponse(lwm2mClientRpcRequest.getDeviceRpcResponseResultMsg(), sessionInfo);
536 } 474 }
537 - } catch (Exception e) {  
538 - throw new IllegalArgumentException(lwm2mClientRpcRequest.getErrorMsg());  
539 } 475 }
540 - return lwm2mClientRpcRequest;  
541 } 476 }
542 477
543 - private ConcurrentHashMap<String, Object> convertParamsToResourceId(ConcurrentHashMap<String, Object> params,  
544 - SessionInfoProto sessionInfo) {  
545 - ConcurrentHashMap<String, Object> paramsIdVer = new ConcurrentHashMap<>();  
546 - params.forEach((k, v) -> {  
547 - String targetIdVer = this.getPresentPathIntoProfile(sessionInfo, k);  
548 - if (targetIdVer != null) {  
549 - LwM2mPath targetId = new LwM2mPath(convertPathFromIdVerToObjectId(targetIdVer));  
550 - if (targetId.isResource()) {  
551 - paramsIdVer.put(String.valueOf(targetId.getResourceId()), v);  
552 - }  
553 - }  
554 - });  
555 - return paramsIdVer; 478 + private void checkRpcRequestTimeout() {
  479 + Set<UUID> rpcSubscriptionsToRemove = rpcSubscriptions.entrySet().stream().filter(kv -> System.currentTimeMillis() > kv.getValue()).map(Map.Entry::getKey).collect(Collectors.toSet());
  480 + rpcSubscriptionsToRemove.forEach(rpcSubscriptions::remove);
556 } 481 }
557 482
558 public void sentRpcRequest(Lwm2mClientRpcRequest rpcRequest, String requestCode, String msg, String typeMsg) { 483 public void sentRpcRequest(Lwm2mClientRpcRequest rpcRequest, String requestCode, String msg, String typeMsg) {
@@ -722,10 +647,10 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler @@ -722,10 +647,10 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler
722 * set setClient_fw_info... = value 647 * set setClient_fw_info... = value
723 **/ 648 **/
724 if (lwM2MClient.getFwUpdate().isInfoFwSwUpdate()) { 649 if (lwM2MClient.getFwUpdate().isInfoFwSwUpdate()) {
725 - lwM2MClient.getFwUpdate().initReadValue(this, lwM2mTransportRequest, path); 650 + lwM2MClient.getFwUpdate().initReadValue(this, this.lwM2mTransportRequest, path);
726 } 651 }
727 if (lwM2MClient.getSwUpdate().isInfoFwSwUpdate()) { 652 if (lwM2MClient.getSwUpdate().isInfoFwSwUpdate()) {
728 - lwM2MClient.getSwUpdate().initReadValue(this, lwM2mTransportRequest, path); 653 + lwM2MClient.getSwUpdate().initReadValue(this, this.lwM2mTransportRequest, path);
729 } 654 }
730 655
731 /** 656 /**
@@ -742,7 +667,7 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler @@ -742,7 +667,7 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler
742 && (convertPathFromObjectIdToIdVer(FW_RESULT_ID, registration).equals(path))) { 667 && (convertPathFromObjectIdToIdVer(FW_RESULT_ID, registration).equals(path))) {
743 if (DOWNLOADED.name().equals(lwM2MClient.getFwUpdate().getStateUpdate()) 668 if (DOWNLOADED.name().equals(lwM2MClient.getFwUpdate().getStateUpdate())
744 && lwM2MClient.getFwUpdate().conditionalFwExecuteStart()) { 669 && lwM2MClient.getFwUpdate().conditionalFwExecuteStart()) {
745 - lwM2MClient.getFwUpdate().executeFwSwWare(this, lwM2mTransportRequest); 670 + lwM2MClient.getFwUpdate().executeFwSwWare(this, this.lwM2mTransportRequest);
746 } else if (UPDATING.name().equals(lwM2MClient.getFwUpdate().getStateUpdate()) 671 } else if (UPDATING.name().equals(lwM2MClient.getFwUpdate().getStateUpdate())
747 && lwM2MClient.getFwUpdate().conditionalFwExecuteAfterSuccess()) { 672 && lwM2MClient.getFwUpdate().conditionalFwExecuteAfterSuccess()) {
748 lwM2MClient.getFwUpdate().finishFwSwUpdate(this, true); 673 lwM2MClient.getFwUpdate().finishFwSwUpdate(this, true);
@@ -767,7 +692,7 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler @@ -767,7 +692,7 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler
767 && (convertPathFromObjectIdToIdVer(SW_RESULT_ID, registration).equals(path))) { 692 && (convertPathFromObjectIdToIdVer(SW_RESULT_ID, registration).equals(path))) {
768 if (DOWNLOADED.name().equals(lwM2MClient.getSwUpdate().getStateUpdate()) 693 if (DOWNLOADED.name().equals(lwM2MClient.getSwUpdate().getStateUpdate())
769 && lwM2MClient.getSwUpdate().conditionalSwUpdateExecute()) { 694 && lwM2MClient.getSwUpdate().conditionalSwUpdateExecute()) {
770 - lwM2MClient.getSwUpdate().executeFwSwWare(this, lwM2mTransportRequest); 695 + lwM2MClient.getSwUpdate().executeFwSwWare(this, this.lwM2mTransportRequest);
771 } else if (UPDATING.name().equals(lwM2MClient.getSwUpdate().getStateUpdate()) 696 } else if (UPDATING.name().equals(lwM2MClient.getSwUpdate().getStateUpdate())
772 && lwM2MClient.getSwUpdate().conditionalSwExecuteAfterSuccess()) { 697 && lwM2MClient.getSwUpdate().conditionalSwExecuteAfterSuccess()) {
773 lwM2MClient.getSwUpdate().finishFwSwUpdate(this, true); 698 lwM2MClient.getSwUpdate().finishFwSwUpdate(this, true);
@@ -970,11 +895,14 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler @@ -970,11 +895,14 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler
970 * @return - return value of Resource by idPath 895 * @return - return value of Resource by idPath
971 */ 896 */
972 private LwM2mResource getResourceValueFromLwM2MClient(LwM2mClient lwM2MClient, String path) { 897 private LwM2mResource getResourceValueFromLwM2MClient(LwM2mClient lwM2MClient, String path) {
973 - LwM2mResource resourceValue = null;  
974 - if (new LwM2mPath(convertPathFromIdVerToObjectId(path)).isResource()) {  
975 - resourceValue = lwM2MClient.getResources().get(path).getLwM2mResource(); 898 + LwM2mResource lwm2mResourceValue = null;
  899 + ResourceValue resourceValue = lwM2MClient.getResources().get(path);
  900 + if (resourceValue != null) {
  901 + if (new LwM2mPath(convertPathFromIdVerToObjectId(path)).isResource()) {
  902 + lwm2mResourceValue = lwM2MClient.getResources().get(path).getLwM2mResource();
  903 + }
976 } 904 }
977 - return resourceValue; 905 + return lwm2mResourceValue;
978 } 906 }
979 907
980 /** 908 /**
@@ -1281,7 +1209,7 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler @@ -1281,7 +1209,7 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler
1281 * @param name - 1209 * @param name -
1282 * @return - 1210 * @return -
1283 */ 1211 */
1284 - private String getPresentPathIntoProfile(TransportProtos.SessionInfoProto sessionInfo, String name) { 1212 + public String getPresentPathIntoProfile(TransportProtos.SessionInfoProto sessionInfo, String name) {
1285 LwM2mClientProfile profile = clientContext.getProfile(new UUID(sessionInfo.getDeviceProfileIdMSB(), sessionInfo.getDeviceProfileIdLSB())); 1213 LwM2mClientProfile profile = clientContext.getProfile(new UUID(sessionInfo.getDeviceProfileIdMSB(), sessionInfo.getDeviceProfileIdLSB()));
1286 LwM2mClient lwM2mClient = clientContext.getClient(sessionInfo); 1214 LwM2mClient lwM2mClient = clientContext.getClient(sessionInfo);
1287 return profile.getPostKeyNameProfile().getAsJsonObject().entrySet().stream() 1215 return profile.getPostKeyNameProfile().getAsJsonObject().entrySet().stream()
@@ -1304,7 +1232,7 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler @@ -1304,7 +1232,7 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler
1304 1232
1305 this.updateAttributeFromThingsboard(tsKvProtos, sessionInfo); 1233 this.updateAttributeFromThingsboard(tsKvProtos, sessionInfo);
1306 } catch (Exception e) { 1234 } catch (Exception e) {
1307 - log.error(String.valueOf(e)); 1235 + log.error("", e);
1308 } 1236 }
1309 } 1237 }
1310 1238
@@ -1378,6 +1306,7 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler @@ -1378,6 +1306,7 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler
1378 private void reportActivityAndRegister(SessionInfoProto sessionInfo) { 1306 private void reportActivityAndRegister(SessionInfoProto sessionInfo) {
1379 if (sessionInfo != null && transportService.reportActivity(sessionInfo) == null) { 1307 if (sessionInfo != null && transportService.reportActivity(sessionInfo) == null) {
1380 transportService.registerAsyncSession(sessionInfo, new LwM2mSessionMsgListener(this, sessionInfo)); 1308 transportService.registerAsyncSession(sessionInfo, new LwM2mSessionMsgListener(this, sessionInfo));
  1309 + this.reportActivitySubscription(sessionInfo);
1381 } 1310 }
1382 } 1311 }
1383 1312
@@ -1510,4 +1439,11 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler @@ -1510,4 +1439,11 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler
1510 return this.config; 1439 return this.config;
1511 } 1440 }
1512 1441
  1442 + private void reportActivitySubscription(TransportProtos.SessionInfoProto sessionInfo) {
  1443 + transportService.process(sessionInfo, TransportProtos.SubscriptionInfoProto.newBuilder()
  1444 + .setAttributeSubscription(true)
  1445 + .setRpcSubscription(true)
  1446 + .setLastActivityTime(System.currentTimeMillis())
  1447 + .build(), TransportServiceCallback.EMPTY);
  1448 + }
1513 } 1449 }
@@ -94,12 +94,6 @@ public class LwM2mServerListener { @@ -94,12 +94,6 @@ public class LwM2mServerListener {
94 @Override 94 @Override
95 public void onResponse(Observation observation, Registration registration, ObserveResponse response) { 95 public void onResponse(Observation observation, Registration registration, ObserveResponse response) {
96 if (registration != null) { 96 if (registration != null) {
97 -// if (observation.getPath().isResource() || observation.getPath().isResourceInstance()) {  
98 -// String msg = String.format("%s: Successful Observation %s.", LOG_LW2M_INFO,  
99 -// observation.getPath());  
100 -// log.warn(msg);  
101 -// service.sendLogsToThingsboard(msg, registration.getId());  
102 -// }  
103 service.onUpdateValueAfterReadResponse(registration, convertPathFromObjectIdToIdVer(observation.getPath().toString(), 97 service.onUpdateValueAfterReadResponse(registration, convertPathFromObjectIdToIdVer(observation.getPath().toString(),
104 registration), response, null); 98 registration), response, null);
105 } 99 }
@@ -22,6 +22,8 @@ import org.eclipse.californium.core.coap.Response; @@ -22,6 +22,8 @@ import org.eclipse.californium.core.coap.Response;
22 import org.eclipse.leshan.core.Link; 22 import org.eclipse.leshan.core.Link;
23 import org.eclipse.leshan.core.model.ResourceModel; 23 import org.eclipse.leshan.core.model.ResourceModel;
24 import org.eclipse.leshan.core.node.LwM2mNode; 24 import org.eclipse.leshan.core.node.LwM2mNode;
  25 +import org.eclipse.leshan.core.node.LwM2mObject;
  26 +import org.eclipse.leshan.core.node.LwM2mObjectInstance;
25 import org.eclipse.leshan.core.node.LwM2mPath; 27 import org.eclipse.leshan.core.node.LwM2mPath;
26 import org.eclipse.leshan.core.node.LwM2mResource; 28 import org.eclipse.leshan.core.node.LwM2mResource;
27 import org.eclipse.leshan.core.node.LwM2mSingleResource; 29 import org.eclipse.leshan.core.node.LwM2mSingleResource;
@@ -34,6 +36,7 @@ import org.eclipse.leshan.core.request.DownlinkRequest; @@ -34,6 +36,7 @@ import org.eclipse.leshan.core.request.DownlinkRequest;
34 import org.eclipse.leshan.core.request.ExecuteRequest; 36 import org.eclipse.leshan.core.request.ExecuteRequest;
35 import org.eclipse.leshan.core.request.ObserveRequest; 37 import org.eclipse.leshan.core.request.ObserveRequest;
36 import org.eclipse.leshan.core.request.ReadRequest; 38 import org.eclipse.leshan.core.request.ReadRequest;
  39 +import org.eclipse.leshan.core.request.WriteAttributesRequest;
37 import org.eclipse.leshan.core.request.WriteRequest; 40 import org.eclipse.leshan.core.request.WriteRequest;
38 import org.eclipse.leshan.core.request.exception.ClientSleepingException; 41 import org.eclipse.leshan.core.request.exception.ClientSleepingException;
39 import org.eclipse.leshan.core.response.DeleteResponse; 42 import org.eclipse.leshan.core.response.DeleteResponse;
@@ -79,10 +82,12 @@ import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.L @@ -79,10 +82,12 @@ import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.L
79 import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LOG_LW2M_VALUE; 82 import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LOG_LW2M_VALUE;
80 import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LwM2mTypeOper; 83 import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LwM2mTypeOper;
81 import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LwM2mTypeOper.DISCOVER; 84 import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LwM2mTypeOper.DISCOVER;
82 -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LwM2mTypeOper.DISCOVER_All; 85 +import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LwM2mTypeOper.DISCOVER_ALL;
83 import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LwM2mTypeOper.EXECUTE; 86 import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LwM2mTypeOper.EXECUTE;
84 import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LwM2mTypeOper.OBSERVE_CANCEL; 87 import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LwM2mTypeOper.OBSERVE_CANCEL;
  88 +import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LwM2mTypeOper.OBSERVE_CANCEL_ALL;
85 import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LwM2mTypeOper.OBSERVE_READ_ALL; 89 import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LwM2mTypeOper.OBSERVE_READ_ALL;
  90 +import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LwM2mTypeOper.WRITE_ATTRIBUTES;
86 import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LwM2mTypeOper.WRITE_REPLACE; 91 import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LwM2mTypeOper.WRITE_REPLACE;
87 import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LwM2mTypeOper.WRITE_UPDATE; 92 import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LwM2mTypeOper.WRITE_UPDATE;
88 import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.RESPONSE_REQUEST_CHANNEL; 93 import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.RESPONSE_REQUEST_CHANNEL;
@@ -123,7 +128,7 @@ public class LwM2mTransportRequest { @@ -123,7 +128,7 @@ public class LwM2mTransportRequest {
123 */ 128 */
124 129
125 public void sendAllRequest(Registration registration, String targetIdVer, LwM2mTypeOper typeOper, 130 public void sendAllRequest(Registration registration, String targetIdVer, LwM2mTypeOper typeOper,
126 - String contentFormatName, Object params, long timeoutInMs, Lwm2mClientRpcRequest rpcRequest) { 131 + String contentFormatName, Object params, long timeoutInMs, Lwm2mClientRpcRequest lwm2mClientRpcRequest) {
127 try { 132 try {
128 String target = convertPathFromIdVerToObjectId(targetIdVer); 133 String target = convertPathFromIdVerToObjectId(targetIdVer);
129 ContentFormat contentFormat = contentFormatName != null ? ContentFormat.fromName(contentFormatName.toUpperCase()) : ContentFormat.DEFAULT; 134 ContentFormat contentFormat = contentFormatName != null ? ContentFormat.fromName(contentFormatName.toUpperCase()) : ContentFormat.DEFAULT;
@@ -132,45 +137,42 @@ public class LwM2mTransportRequest { @@ -132,45 +137,42 @@ public class LwM2mTransportRequest {
132 if (!OBSERVE_READ_ALL.name().equals(typeOper.name()) && resultIds != null && registration != null && resultIds.getObjectId() >= 0 && lwM2MClient != null) { 137 if (!OBSERVE_READ_ALL.name().equals(typeOper.name()) && resultIds != null && registration != null && resultIds.getObjectId() >= 0 && lwM2MClient != null) {
133 if (lwM2MClient.isValidObjectVersion(targetIdVer)) { 138 if (lwM2MClient.isValidObjectVersion(targetIdVer)) {
134 timeoutInMs = timeoutInMs > 0 ? timeoutInMs : DEFAULT_TIMEOUT; 139 timeoutInMs = timeoutInMs > 0 ? timeoutInMs : DEFAULT_TIMEOUT;
135 - DownlinkRequest request = createRequest (registration, lwM2MClient, typeOper, contentFormat, target,  
136 - targetIdVer, resultIds, params, rpcRequest); 140 + DownlinkRequest request = createRequest(registration, lwM2MClient, typeOper, contentFormat, target,
  141 + targetIdVer, resultIds, params, lwm2mClientRpcRequest);
137 if (request != null) { 142 if (request != null) {
138 try { 143 try {
139 - this.sendRequest(registration, lwM2MClient, request, timeoutInMs, rpcRequest); 144 + this.sendRequest(registration, lwM2MClient, request, timeoutInMs, lwm2mClientRpcRequest);
140 } catch (ClientSleepingException e) { 145 } catch (ClientSleepingException e) {
141 DownlinkRequest finalRequest = request; 146 DownlinkRequest finalRequest = request;
142 long finalTimeoutInMs = timeoutInMs; 147 long finalTimeoutInMs = timeoutInMs;
143 - Lwm2mClientRpcRequest finalRpcRequest = rpcRequest; 148 + Lwm2mClientRpcRequest finalRpcRequest = lwm2mClientRpcRequest;
144 lwM2MClient.getQueuedRequests().add(() -> sendRequest(registration, lwM2MClient, finalRequest, finalTimeoutInMs, finalRpcRequest)); 149 lwM2MClient.getQueuedRequests().add(() -> sendRequest(registration, lwM2MClient, finalRequest, finalTimeoutInMs, finalRpcRequest));
145 } catch (Exception e) { 150 } catch (Exception e) {
146 log.error("[{}] [{}] [{}] Failed to send downlink.", registration.getEndpoint(), targetIdVer, typeOper.name(), e); 151 log.error("[{}] [{}] [{}] Failed to send downlink.", registration.getEndpoint(), targetIdVer, typeOper.name(), e);
147 } 152 }
148 - }  
149 - else if (WRITE_UPDATE.name().equals(typeOper.name())) {  
150 - if (rpcRequest != null) { 153 + } else if (WRITE_UPDATE.name().equals(typeOper.name())) {
  154 + if (lwm2mClientRpcRequest != null) {
151 String errorMsg = String.format("Path %s params is not valid", targetIdVer); 155 String errorMsg = String.format("Path %s params is not valid", targetIdVer);
152 - handler.sentRpcRequest(rpcRequest, BAD_REQUEST.getName(), errorMsg, LOG_LW2M_ERROR); 156 + handler.sentRpcRequest(lwm2mClientRpcRequest, BAD_REQUEST.getName(), errorMsg, LOG_LW2M_ERROR);
153 } 157 }
154 - }  
155 - else if (WRITE_REPLACE.name().equals(typeOper.name()) || EXECUTE.name().equals(typeOper.name()) ) {  
156 - if (rpcRequest != null) { 158 + } else if (WRITE_REPLACE.name().equals(typeOper.name()) || EXECUTE.name().equals(typeOper.name())) {
  159 + if (lwm2mClientRpcRequest != null) {
157 String errorMsg = String.format("Path %s object model is absent", targetIdVer); 160 String errorMsg = String.format("Path %s object model is absent", targetIdVer);
158 - handler.sentRpcRequest(rpcRequest, BAD_REQUEST.getName(), errorMsg, LOG_LW2M_ERROR); 161 + handler.sentRpcRequest(lwm2mClientRpcRequest, BAD_REQUEST.getName(), errorMsg, LOG_LW2M_ERROR);
159 } 162 }
160 - }  
161 - else if (!OBSERVE_CANCEL.name().equals(typeOper.name())) { 163 + } else if (!OBSERVE_CANCEL.name().equals(typeOper.name())) {
162 log.error("[{}], [{}] - [{}] error SendRequest", registration.getEndpoint(), typeOper.name(), targetIdVer); 164 log.error("[{}], [{}] - [{}] error SendRequest", registration.getEndpoint(), typeOper.name(), targetIdVer);
163 - if (rpcRequest != null) { 165 + if (lwm2mClientRpcRequest != null) {
164 ResourceModel resourceModel = lwM2MClient.getResourceModel(targetIdVer, this.config.getModelProvider()); 166 ResourceModel resourceModel = lwM2MClient.getResourceModel(targetIdVer, this.config.getModelProvider());
165 String errorMsg = resourceModel == null ? String.format("Path %s not found in object version", targetIdVer) : "SendRequest - null"; 167 String errorMsg = resourceModel == null ? String.format("Path %s not found in object version", targetIdVer) : "SendRequest - null";
166 - handler.sentRpcRequest(rpcRequest, NOT_FOUND.getName(), errorMsg, LOG_LW2M_ERROR); 168 + this.handler.sentRpcRequest(lwm2mClientRpcRequest, NOT_FOUND.getName(), errorMsg, LOG_LW2M_ERROR);
167 } 169 }
168 } 170 }
169 - } else if (rpcRequest != null) { 171 + } else if (lwm2mClientRpcRequest != null) {
170 String errorMsg = String.format("Path %s not found in object version", targetIdVer); 172 String errorMsg = String.format("Path %s not found in object version", targetIdVer);
171 - handler.sentRpcRequest(rpcRequest, NOT_FOUND.getName(), errorMsg, LOG_LW2M_ERROR); 173 + this.handler.sentRpcRequest(lwm2mClientRpcRequest, NOT_FOUND.getName(), errorMsg, LOG_LW2M_ERROR);
172 } 174 }
173 - } else if (OBSERVE_READ_ALL.name().equals(typeOper.name()) || DISCOVER_All.name().equals(typeOper.name())) { 175 + } else if (OBSERVE_READ_ALL.name().equals(typeOper.name()) || DISCOVER_ALL.name().equals(typeOper.name())) {
174 Set<String> paths; 176 Set<String> paths;
175 if (OBSERVE_READ_ALL.name().equals(typeOper.name())) { 177 if (OBSERVE_READ_ALL.name().equals(typeOper.name())) {
176 Set<Observation> observations = context.getServer().getObservationService().getObservations(registration); 178 Set<Observation> observations = context.getServer().getObservationService().getObservations(registration);
@@ -179,34 +181,34 @@ public class LwM2mTransportRequest { @@ -179,34 +181,34 @@ public class LwM2mTransportRequest {
179 assert registration != null; 181 assert registration != null;
180 Link[] objectLinks = registration.getSortedObjectLinks(); 182 Link[] objectLinks = registration.getSortedObjectLinks();
181 paths = Arrays.stream(objectLinks).map(Link::toString).collect(Collectors.toUnmodifiableSet()); 183 paths = Arrays.stream(objectLinks).map(Link::toString).collect(Collectors.toUnmodifiableSet());
182 - String msg = String.format("%s: type operation %s paths - %s", LOG_LW2M_INFO,  
183 - typeOper.name(), paths);  
184 - handler.sendLogsToThingsboard(msg, registration.getId());  
185 } 184 }
186 - if (rpcRequest != null) { 185 + String msg = String.format("%s: type operation %s paths - %s", LOG_LW2M_INFO,
  186 + typeOper.name(), paths);
  187 + this.handler.sendLogsToThingsboard(msg, registration.getId());
  188 + if (lwm2mClientRpcRequest != null) {
187 String valueMsg = String.format("Paths - %s", paths); 189 String valueMsg = String.format("Paths - %s", paths);
188 - handler.sentRpcRequest(rpcRequest, CONTENT.name(), valueMsg, LOG_LW2M_VALUE); 190 + this.handler.sentRpcRequest(lwm2mClientRpcRequest, CONTENT.name(), valueMsg, LOG_LW2M_VALUE);
189 } 191 }
190 - } else if (OBSERVE_CANCEL.name().equals(typeOper.name())) { 192 + } else if (OBSERVE_CANCEL_ALL.name().equals(typeOper.name())) {
191 int observeCancelCnt = context.getServer().getObservationService().cancelObservations(registration); 193 int observeCancelCnt = context.getServer().getObservationService().cancelObservations(registration);
192 String observeCancelMsgAll = String.format("%s: type operation %s paths: All count: %d", LOG_LW2M_INFO, 194 String observeCancelMsgAll = String.format("%s: type operation %s paths: All count: %d", LOG_LW2M_INFO,
193 OBSERVE_CANCEL.name(), observeCancelCnt); 195 OBSERVE_CANCEL.name(), observeCancelCnt);
194 - this.afterObserveCancel(registration, observeCancelCnt, observeCancelMsgAll, rpcRequest); 196 + this.afterObserveCancel(registration, observeCancelCnt, observeCancelMsgAll, lwm2mClientRpcRequest);
195 } 197 }
196 } catch (Exception e) { 198 } catch (Exception e) {
197 String msg = String.format("%s: type operation %s %s", LOG_LW2M_ERROR, 199 String msg = String.format("%s: type operation %s %s", LOG_LW2M_ERROR,
198 typeOper.name(), e.getMessage()); 200 typeOper.name(), e.getMessage());
199 handler.sendLogsToThingsboard(msg, registration.getId()); 201 handler.sendLogsToThingsboard(msg, registration.getId());
200 - if (rpcRequest != null) { 202 + if (lwm2mClientRpcRequest != null) {
201 String errorMsg = String.format("Path %s type operation %s %s", targetIdVer, typeOper.name(), e.getMessage()); 203 String errorMsg = String.format("Path %s type operation %s %s", targetIdVer, typeOper.name(), e.getMessage());
202 - handler.sentRpcRequest(rpcRequest, NOT_FOUND.getName(), errorMsg, LOG_LW2M_ERROR); 204 + handler.sentRpcRequest(lwm2mClientRpcRequest, NOT_FOUND.getName(), errorMsg, LOG_LW2M_ERROR);
203 } 205 }
204 } 206 }
205 } 207 }
206 208
207 - private DownlinkRequest createRequest (Registration registration, LwM2mClient lwM2MClient, LwM2mTypeOper typeOper,  
208 - ContentFormat contentFormat, String target, String targetIdVer,  
209 - LwM2mPath resultIds, Object params, Lwm2mClientRpcRequest rpcRequest) { 209 + private DownlinkRequest createRequest(Registration registration, LwM2mClient lwM2MClient, LwM2mTypeOper typeOper,
  210 + ContentFormat contentFormat, String target, String targetIdVer,
  211 + LwM2mPath resultIds, Object params, Lwm2mClientRpcRequest rpcRequest) {
210 DownlinkRequest request = null; 212 DownlinkRequest request = null;
211 switch (typeOper) { 213 switch (typeOper) {
212 case READ: 214 case READ:
@@ -216,7 +218,7 @@ public class LwM2mTransportRequest { @@ -216,7 +218,7 @@ public class LwM2mTransportRequest {
216 request = new DiscoverRequest(target); 218 request = new DiscoverRequest(target);
217 break; 219 break;
218 case OBSERVE: 220 case OBSERVE:
219 - String msg = String.format("%s: Send Observation %s.", LOG_LW2M_INFO, targetIdVer); 221 + String msg = String.format("%s: Send Observation %s.", LOG_LW2M_INFO, targetIdVer);
220 log.warn(msg); 222 log.warn(msg);
221 if (resultIds.isResource()) { 223 if (resultIds.isResource()) {
222 Set<Observation> observations = context.getServer().getObservationService().getObservations(registration); 224 Set<Observation> observations = context.getServer().getObservationService().getObservations(registration);
@@ -305,7 +307,7 @@ public class LwM2mTransportRequest { @@ -305,7 +307,7 @@ public class LwM2mTransportRequest {
305 } 307 }
306 break; 308 break;
307 case WRITE_ATTRIBUTES: 309 case WRITE_ATTRIBUTES:
308 - request = createWriteAttributeRequest(target, params); 310 + request = createWriteAttributeRequest(target, params, this.handler);
309 break; 311 break;
310 case DELETE: 312 case DELETE:
311 request = new DeleteRequest(target); 313 request = new DeleteRequest(target);
@@ -347,10 +349,10 @@ public class LwM2mTransportRequest { @@ -347,10 +349,10 @@ public class LwM2mTransportRequest {
347 set setClient_fw_info... = empty 349 set setClient_fw_info... = empty
348 **/ 350 **/
349 if (lwM2MClient.getFwUpdate().isInfoFwSwUpdate()) { 351 if (lwM2MClient.getFwUpdate().isInfoFwSwUpdate()) {
350 - lwM2MClient.getFwUpdate().initReadValue(handler, request.getPath().toString()); 352 + lwM2MClient.getFwUpdate().initReadValue(handler, this, request.getPath().toString());
351 } 353 }
352 if (lwM2MClient.getSwUpdate().isInfoFwSwUpdate()) { 354 if (lwM2MClient.getSwUpdate().isInfoFwSwUpdate()) {
353 - lwM2MClient.getSwUpdate().initReadValue(handler, request.getPath().toString()); 355 + lwM2MClient.getSwUpdate().initReadValue(handler, this, request.getPath().toString());
354 } 356 }
355 if (request.getPath().toString().equals(FW_PACKAGE_ID) || request.getPath().toString().equals(SW_PACKAGE_ID)) { 357 if (request.getPath().toString().equals(FW_PACKAGE_ID) || request.getPath().toString().equals(SW_PACKAGE_ID)) {
356 this.afterWriteFwSWUpdateError(registration, request, response.getErrorMessage()); 358 this.afterWriteFwSWUpdateError(registration, request, response.getErrorMessage());
@@ -364,10 +366,10 @@ public class LwM2mTransportRequest { @@ -364,10 +366,10 @@ public class LwM2mTransportRequest {
364 set setClient_fw_info... = empty 366 set setClient_fw_info... = empty
365 **/ 367 **/
366 if (lwM2MClient.getFwUpdate().isInfoFwSwUpdate()) { 368 if (lwM2MClient.getFwUpdate().isInfoFwSwUpdate()) {
367 - lwM2MClient.getFwUpdate().initReadValue(handler, request.getPath().toString()); 369 + lwM2MClient.getFwUpdate().initReadValue(handler, this, request.getPath().toString());
368 } 370 }
369 if (lwM2MClient.getSwUpdate().isInfoFwSwUpdate()) { 371 if (lwM2MClient.getSwUpdate().isInfoFwSwUpdate()) {
370 - lwM2MClient.getSwUpdate().initReadValue(handler, request.getPath().toString()); 372 + lwM2MClient.getSwUpdate().initReadValue(handler, this, request.getPath().toString());
371 } 373 }
372 if (request.getPath().toString().equals(FW_PACKAGE_ID) || request.getPath().toString().equals(SW_PACKAGE_ID)) { 374 if (request.getPath().toString().equals(FW_PACKAGE_ID) || request.getPath().toString().equals(SW_PACKAGE_ID)) {
373 this.afterWriteFwSWUpdateError(registration, request, e.getMessage()); 375 this.afterWriteFwSWUpdateError(registration, request, e.getMessage());
@@ -473,7 +475,13 @@ public class LwM2mTransportRequest { @@ -473,7 +475,13 @@ public class LwM2mTransportRequest {
473 } else if (response instanceof ExecuteResponse) { 475 } else if (response instanceof ExecuteResponse) {
474 log.warn("[{}] Path [{}] ExecuteResponse 7_Send", pathIdVer, response); 476 log.warn("[{}] Path [{}] ExecuteResponse 7_Send", pathIdVer, response);
475 } else if (response instanceof WriteAttributesResponse) { 477 } else if (response instanceof WriteAttributesResponse) {
  478 + msgLog = String.format("%s: type operation: %s path: %s value: %s",
  479 + LOG_LW2M_INFO, WRITE_ATTRIBUTES.name(), request.getPath().toString(), ((WriteAttributesRequest) request).getAttributes().toString());
  480 + handler.sendLogsToThingsboard(msgLog, registration.getId());
476 log.warn("[{}] Path [{}] WriteAttributesResponse 8_Send", pathIdVer, response); 481 log.warn("[{}] Path [{}] WriteAttributesResponse 8_Send", pathIdVer, response);
  482 + if (rpcRequest != null) {
  483 + handler.sentRpcRequest(rpcRequest, response.getCode().getName(), response.toString(), LOG_LW2M_VALUE);
  484 + }
477 } else if (response instanceof WriteResponse) { 485 } else if (response instanceof WriteResponse) {
478 log.warn("[{}] Path [{}] WriteResponse 9_Send", pathIdVer, response); 486 log.warn("[{}] Path [{}] WriteResponse 9_Send", pathIdVer, response);
479 this.infoWriteResponse(registration, response, request); 487 this.infoWriteResponse(registration, response, request);
@@ -494,29 +502,37 @@ public class LwM2mTransportRequest { @@ -494,29 +502,37 @@ public class LwM2mTransportRequest {
494 private void infoWriteResponse(Registration registration, LwM2mResponse response, DownlinkRequest request) { 502 private void infoWriteResponse(Registration registration, LwM2mResponse response, DownlinkRequest request) {
495 try { 503 try {
496 LwM2mNode node = ((WriteRequest) request).getNode(); 504 LwM2mNode node = ((WriteRequest) request).getNode();
497 - String msg; 505 + String msg = null;
498 Object value; 506 Object value;
499 - LwM2mSingleResource singleResource = (LwM2mSingleResource) node;  
500 - if (singleResource.getType() == ResourceModel.Type.STRING || singleResource.getType() == ResourceModel.Type.OPAQUE) {  
501 - int valueLength;  
502 - if (singleResource.getType() == ResourceModel.Type.STRING) {  
503 - valueLength = ((String) singleResource.getValue()).length();  
504 - value = ((String) singleResource.getValue())  
505 - .substring(Math.min(valueLength, config.getLogMaxLength())); 507 + if (node instanceof LwM2mObject) {
  508 + msg = String.format("%s: Update finished successfully: Lwm2m code - %d Source path: %s value: %s",
  509 + LOG_LW2M_INFO, response.getCode().getCode(), request.getPath().toString(), ((LwM2mObject) node).toString());
  510 + } else if (node instanceof LwM2mObjectInstance) {
  511 + msg = String.format("%s: Update finished successfully: Lwm2m code - %d Source path: %s value: %s",
  512 + LOG_LW2M_INFO, response.getCode().getCode(), request.getPath().toString(), ((LwM2mObjectInstance) node).prettyPrint());
  513 + } else if (node instanceof LwM2mSingleResource) {
  514 + LwM2mSingleResource singleResource = (LwM2mSingleResource) node;
  515 + if (singleResource.getType() == ResourceModel.Type.STRING || singleResource.getType() == ResourceModel.Type.OPAQUE) {
  516 + int valueLength;
  517 + if (singleResource.getType() == ResourceModel.Type.STRING) {
  518 + valueLength = ((String) singleResource.getValue()).length();
  519 + value = ((String) singleResource.getValue())
  520 + .substring(Math.min(valueLength, config.getLogMaxLength()));
506 521
  522 + } else {
  523 + valueLength = ((byte[]) singleResource.getValue()).length;
  524 + value = new String(Arrays.copyOf(((byte[]) singleResource.getValue()),
  525 + Math.min(valueLength, config.getLogMaxLength())));
  526 + }
  527 + value = valueLength > config.getLogMaxLength() ? value + "..." : value;
  528 + msg = String.format("%s: Update finished successfully: Lwm2m code - %d Resource path: %s length: %s value: %s",
  529 + LOG_LW2M_INFO, response.getCode().getCode(), request.getPath().toString(), valueLength, value);
507 } else { 530 } else {
508 - valueLength = ((byte[]) singleResource.getValue()).length;  
509 - value = new String(Arrays.copyOf(((byte[]) singleResource.getValue()),  
510 - Math.min(valueLength, config.getLogMaxLength()))); 531 + value = this.converter.convertValue(singleResource.getValue(),
  532 + singleResource.getType(), ResourceModel.Type.STRING, request.getPath());
  533 + msg = String.format("%s: Update finished successfully. Lwm2m code: %d Resource path: %s value: %s",
  534 + LOG_LW2M_INFO, response.getCode().getCode(), request.getPath().toString(), value);
511 } 535 }
512 - value = valueLength > config.getLogMaxLength() ? value + "..." : value;  
513 - msg = String.format("%s: Update finished successfully: Lwm2m code - %d Resource path: %s length: %s value: %s",  
514 - LOG_LW2M_INFO, response.getCode().getCode(), request.getPath().toString(), valueLength, value);  
515 - } else {  
516 - value = this.converter.convertValue(singleResource.getValue(),  
517 - singleResource.getType(), ResourceModel.Type.STRING, request.getPath());  
518 - msg = String.format("%s: Update finished successfully. Lwm2m code: %d Resource path: %s value: %s",  
519 - LOG_LW2M_INFO, response.getCode().getCode(), request.getPath().toString(), value);  
520 } 536 }
521 if (msg != null) { 537 if (msg != null) {
522 handler.sendLogsToThingsboard(msg, registration.getId()); 538 handler.sendLogsToThingsboard(msg, registration.getId());
@@ -538,11 +554,11 @@ public class LwM2mTransportRequest { @@ -538,11 +554,11 @@ public class LwM2mTransportRequest {
538 LwM2mClient lwM2MClient = this.lwM2mClientContext.getClientByRegistrationId(registration.getId()); 554 LwM2mClient lwM2MClient = this.lwM2mClientContext.getClientByRegistrationId(registration.getId());
539 if (request.getPath().toString().equals(FW_PACKAGE_ID) && lwM2MClient.getFwUpdate() != null) { 555 if (request.getPath().toString().equals(FW_PACKAGE_ID) && lwM2MClient.getFwUpdate() != null) {
540 lwM2MClient.getFwUpdate().setStateUpdate(DOWNLOADED.name()); 556 lwM2MClient.getFwUpdate().setStateUpdate(DOWNLOADED.name());
541 - lwM2MClient.getFwUpdate().sendLogs(WRITE_REPLACE.name(), LOG_LW2M_INFO, null); 557 + lwM2MClient.getFwUpdate().sendLogs(this.handler, WRITE_REPLACE.name(), LOG_LW2M_INFO, null);
542 } 558 }
543 if (request.getPath().toString().equals(SW_PACKAGE_ID) && lwM2MClient.getSwUpdate() != null) { 559 if (request.getPath().toString().equals(SW_PACKAGE_ID) && lwM2MClient.getSwUpdate() != null) {
544 lwM2MClient.getSwUpdate().setStateUpdate(DOWNLOADED.name()); 560 lwM2MClient.getSwUpdate().setStateUpdate(DOWNLOADED.name());
545 - lwM2MClient.getSwUpdate().sendLogs(WRITE_REPLACE.name(), LOG_LW2M_INFO, null); 561 + lwM2MClient.getSwUpdate().sendLogs(this.handler,WRITE_REPLACE.name(), LOG_LW2M_INFO, null);
546 } 562 }
547 } 563 }
548 564
@@ -553,21 +569,21 @@ public class LwM2mTransportRequest { @@ -553,21 +569,21 @@ public class LwM2mTransportRequest {
553 LwM2mClient lwM2MClient = this.lwM2mClientContext.getClientByRegistrationId(registration.getId()); 569 LwM2mClient lwM2MClient = this.lwM2mClientContext.getClientByRegistrationId(registration.getId());
554 if (request.getPath().toString().equals(FW_PACKAGE_ID) && lwM2MClient.getFwUpdate() != null) { 570 if (request.getPath().toString().equals(FW_PACKAGE_ID) && lwM2MClient.getFwUpdate() != null) {
555 lwM2MClient.getFwUpdate().setStateUpdate(FAILED.name()); 571 lwM2MClient.getFwUpdate().setStateUpdate(FAILED.name());
556 - lwM2MClient.getFwUpdate().sendLogs(WRITE_REPLACE.name(), LOG_LW2M_ERROR, msgError); 572 + lwM2MClient.getFwUpdate().sendLogs(this.handler, WRITE_REPLACE.name(), LOG_LW2M_ERROR, msgError);
557 } 573 }
558 if (request.getPath().toString().equals(SW_PACKAGE_ID) && lwM2MClient.getSwUpdate() != null) { 574 if (request.getPath().toString().equals(SW_PACKAGE_ID) && lwM2MClient.getSwUpdate() != null) {
559 lwM2MClient.getSwUpdate().setStateUpdate(FAILED.name()); 575 lwM2MClient.getSwUpdate().setStateUpdate(FAILED.name());
560 - lwM2MClient.getSwUpdate().sendLogs(WRITE_REPLACE.name(), LOG_LW2M_ERROR, msgError); 576 + lwM2MClient.getSwUpdate().sendLogs(this.handler, WRITE_REPLACE.name(), LOG_LW2M_ERROR, msgError);
561 } 577 }
562 } 578 }
563 579
564 private void afterExecuteFwSwUpdateError(Registration registration, DownlinkRequest request, String msgError) { 580 private void afterExecuteFwSwUpdateError(Registration registration, DownlinkRequest request, String msgError) {
565 LwM2mClient lwM2MClient = this.lwM2mClientContext.getClientByRegistrationId(registration.getId()); 581 LwM2mClient lwM2MClient = this.lwM2mClientContext.getClientByRegistrationId(registration.getId());
566 if (request.getPath().toString().equals(FW_UPDATE_ID) && lwM2MClient.getFwUpdate() != null) { 582 if (request.getPath().toString().equals(FW_UPDATE_ID) && lwM2MClient.getFwUpdate() != null) {
567 - lwM2MClient.getFwUpdate().sendLogs(EXECUTE.name(), LOG_LW2M_ERROR, msgError); 583 + lwM2MClient.getFwUpdate().sendLogs(this.handler, EXECUTE.name(), LOG_LW2M_ERROR, msgError);
568 } 584 }
569 if (request.getPath().toString().equals(SW_INSTALL_ID) && lwM2MClient.getSwUpdate() != null) { 585 if (request.getPath().toString().equals(SW_INSTALL_ID) && lwM2MClient.getSwUpdate() != null) {
570 - lwM2MClient.getSwUpdate().sendLogs(EXECUTE.name(), LOG_LW2M_ERROR, msgError); 586 + lwM2MClient.getSwUpdate().sendLogs(this.handler, EXECUTE.name(), LOG_LW2M_ERROR, msgError);
571 } 587 }
572 } 588 }
573 589
@@ -61,9 +61,12 @@ import java.util.Set; @@ -61,9 +61,12 @@ import java.util.Set;
61 import java.util.concurrent.ConcurrentHashMap; 61 import java.util.concurrent.ConcurrentHashMap;
62 62
63 import static org.eclipse.leshan.core.attributes.Attribute.DIMENSION; 63 import static org.eclipse.leshan.core.attributes.Attribute.DIMENSION;
  64 +import static org.eclipse.leshan.core.attributes.Attribute.GREATER_THAN;
  65 +import static org.eclipse.leshan.core.attributes.Attribute.LESSER_THAN;
64 import static org.eclipse.leshan.core.attributes.Attribute.MAXIMUM_PERIOD; 66 import static org.eclipse.leshan.core.attributes.Attribute.MAXIMUM_PERIOD;
65 import static org.eclipse.leshan.core.attributes.Attribute.MINIMUM_PERIOD; 67 import static org.eclipse.leshan.core.attributes.Attribute.MINIMUM_PERIOD;
66 import static org.eclipse.leshan.core.attributes.Attribute.OBJECT_VERSION; 68 import static org.eclipse.leshan.core.attributes.Attribute.OBJECT_VERSION;
  69 +import static org.eclipse.leshan.core.attributes.Attribute.STEP;
67 import static org.eclipse.leshan.core.model.ResourceModel.Type.BOOLEAN; 70 import static org.eclipse.leshan.core.model.ResourceModel.Type.BOOLEAN;
68 import static org.eclipse.leshan.core.model.ResourceModel.Type.FLOAT; 71 import static org.eclipse.leshan.core.model.ResourceModel.Type.FLOAT;
69 import static org.eclipse.leshan.core.model.ResourceModel.Type.INTEGER; 72 import static org.eclipse.leshan.core.model.ResourceModel.Type.INTEGER;
@@ -104,8 +107,7 @@ public class LwM2mTransportUtil { @@ -104,8 +107,7 @@ public class LwM2mTransportUtil {
104 107
105 public static final long DEFAULT_TIMEOUT = 2 * 60 * 1000L; // 2min in ms 108 public static final long DEFAULT_TIMEOUT = 2 * 60 * 1000L; // 2min in ms
106 109
107 - public static final String  
108 - LOG_LW2M_TELEMETRY = "LwM2MLog"; 110 + public static final String LOG_LW2M_TELEMETRY = "logLwm2m";
109 public static final String LOG_LW2M_INFO = "info"; 111 public static final String LOG_LW2M_INFO = "info";
110 public static final String LOG_LW2M_ERROR = "error"; 112 public static final String LOG_LW2M_ERROR = "error";
111 public static final String LOG_LW2M_WARN = "warn"; 113 public static final String LOG_LW2M_WARN = "warn";
@@ -117,6 +119,23 @@ public class LwM2mTransportUtil { @@ -117,6 +119,23 @@ public class LwM2mTransportUtil {
117 public static final String CLIENT_NOT_AUTHORIZED = "Client not authorized"; 119 public static final String CLIENT_NOT_AUTHORIZED = "Client not authorized";
118 public static final String LWM2M_VERSION_DEFAULT = "1.0"; 120 public static final String LWM2M_VERSION_DEFAULT = "1.0";
119 121
  122 + // RPC
  123 + public static final String TYPE_OPER_KEY = "typeOper";
  124 + public static final String TARGET_ID_VER_KEY = "targetIdVer";
  125 + public static final String KEY_NAME_KEY = "key";
  126 + public static final String VALUE_KEY = "value";
  127 + public static final String PARAMS_KEY = "params";
  128 + public static final String SEPARATOR_KEY = ":";
  129 + public static final String FINISH_VALUE_KEY = ",";
  130 + public static final String START_JSON_KEY = "{";
  131 + public static final String FINISH_JSON_KEY = "}";
  132 + // public static final String contentFormatNameKey = "contentFormatName";
  133 + public static final String INFO_KEY = "info";
  134 + // public static final String TIME_OUT_IN_MS = "timeOutInMs";
  135 + public static final String RESULT_KEY = "result";
  136 + public static final String ERROR_KEY = "error";
  137 + public static final String METHOD_KEY = "methodName";
  138 +
120 // FirmWare 139 // FirmWare
121 public static final String FW_UPDATE = "Firmware update"; 140 public static final String FW_UPDATE = "Firmware update";
122 public static final Integer FW_ID = 5; 141 public static final Integer FW_ID = 5;
@@ -182,20 +201,21 @@ public class LwM2mTransportUtil { @@ -182,20 +201,21 @@ public class LwM2mTransportUtil {
182 */ 201 */
183 READ(0, "Read"), 202 READ(0, "Read"),
184 DISCOVER(1, "Discover"), 203 DISCOVER(1, "Discover"),
185 - DISCOVER_All(2, "DiscoverAll"), 204 + DISCOVER_ALL(2, "DiscoverAll"),
186 OBSERVE_READ_ALL(3, "ObserveReadAll"), 205 OBSERVE_READ_ALL(3, "ObserveReadAll"),
187 /** 206 /**
188 * POST 207 * POST
189 */ 208 */
190 OBSERVE(4, "Observe"), 209 OBSERVE(4, "Observe"),
191 OBSERVE_CANCEL(5, "ObserveCancel"), 210 OBSERVE_CANCEL(5, "ObserveCancel"),
192 - EXECUTE(6, "Execute"), 211 + OBSERVE_CANCEL_ALL(6, "ObserveCancelAll"),
  212 + EXECUTE(7, "Execute"),
193 /** 213 /**
194 * Replaces the Object Instance or the Resource(s) with the new value provided in the “Write” operation. (see 214 * Replaces the Object Instance or the Resource(s) with the new value provided in the “Write” operation. (see
195 * section 5.3.3 of the LW M2M spec). 215 * section 5.3.3 of the LW M2M spec).
196 * if all resources are to be replaced 216 * if all resources are to be replaced
197 */ 217 */
198 - WRITE_REPLACE(7, "WriteReplace"), 218 + WRITE_REPLACE(8, "WriteReplace"),
199 /* 219 /*
200 PUT 220 PUT
201 */ 221 */
@@ -204,18 +224,16 @@ public class LwM2mTransportUtil { @@ -204,18 +224,16 @@ public class LwM2mTransportUtil {
204 * 5.3.3 of the LW M2M spec). 224 * 5.3.3 of the LW M2M spec).
205 * if this is a partial update request 225 * if this is a partial update request
206 */ 226 */
207 - WRITE_UPDATE(8, "WriteUpdate"),  
208 - WRITE_ATTRIBUTES(9, "WriteAttributes"),  
209 - DELETE(10, "Delete"), 227 + WRITE_UPDATE(9, "WriteUpdate"),
  228 + WRITE_ATTRIBUTES(10, "WriteAttributes"),
  229 + DELETE(11, "Delete");
210 230
211 // only for RPC 231 // only for RPC
212 - FW_READ_INFO(11, "FirmwareReadInfo"),  
213 - FW_UPDATE(12, "FirmwareUpdate"),  
214 - FW_UPDATE_URL(14, "FirmwareUpdateUrl"),  
215 - SW_READ_INFO(15, "SoftwareReadInfo"),  
216 - SW_UPDATE(16, "SoftwareUpdate"),  
217 - SW_UPDATE_URL(17, "SoftwareUpdateUrl"),  
218 - SW_UNINSTALL(18, "SoftwareUninstall"); 232 +// FW_READ_INFO(12, "FirmwareReadInfo"),
  233 +// FW_UPDATE(13, "FirmwareUpdate"),
  234 +// SW_READ_INFO(15, "SoftwareReadInfo"),
  235 +// SW_UPDATE(16, "SoftwareUpdate"),
  236 +// SW_UNINSTALL(18, "SoftwareUninstall");
219 237
220 public int code; 238 public int code;
221 public String type; 239 public String type;
@@ -817,26 +835,29 @@ public class LwM2mTransportUtil { @@ -817,26 +835,29 @@ public class LwM2mTransportUtil {
817 * Attribute pmax = new Attribute(MAXIMUM_PERIOD, "60"); 835 * Attribute pmax = new Attribute(MAXIMUM_PERIOD, "60");
818 * Attribute [] attrs = {gt, st}; 836 * Attribute [] attrs = {gt, st};
819 */ 837 */
820 - public static DownlinkRequest createWriteAttributeRequest(String target, Object params) {  
821 - AttributeSet attrSet = new AttributeSet(createWriteAttributes(params)); 838 + public static DownlinkRequest createWriteAttributeRequest(String target, Object params, DefaultLwM2MTransportMsgHandler serviceImpl) {
  839 + AttributeSet attrSet = new AttributeSet(createWriteAttributes(params, serviceImpl, target));
822 return attrSet.getAttributes().size() > 0 ? new WriteAttributesRequest(target, attrSet) : null; 840 return attrSet.getAttributes().size() > 0 ? new WriteAttributesRequest(target, attrSet) : null;
823 } 841 }
824 842
825 - private static Attribute[] createWriteAttributes(Object params) { 843 + private static Attribute[] createWriteAttributes(Object params, DefaultLwM2MTransportMsgHandler serviceImpl, String target) {
826 List<Attribute> attributeLists = new ArrayList<>(); 844 List<Attribute> attributeLists = new ArrayList<>();
827 ObjectMapper oMapper = new ObjectMapper(); 845 ObjectMapper oMapper = new ObjectMapper();
828 Map<String, Object> map = oMapper.convertValue(params, ConcurrentHashMap.class); 846 Map<String, Object> map = oMapper.convertValue(params, ConcurrentHashMap.class);
829 map.forEach((k, v) -> { 847 map.forEach((k, v) -> {
830 - if (!v.toString().isEmpty() || (v.toString().isEmpty() && OBJECT_VERSION.equals(k))) {  
831 - attributeLists.add(new Attribute(k,  
832 - (DIMENSION.equals(k) || MINIMUM_PERIOD.equals(k) || MAXIMUM_PERIOD.equals(k)) ?  
833 - ((Double) v).longValue() : v)); 848 + if (StringUtils.trimToNull(v.toString()) != null) {
  849 + Object attrValue = convertWriteAttributes(k, v, serviceImpl, target);
  850 + if (attrValue != null) {
  851 + Attribute attribute = createAttribute(k, attrValue);
  852 + if (attribute != null) {
  853 + attributeLists.add(new Attribute(k, attrValue));
  854 + }
  855 + }
834 } 856 }
835 }); 857 });
836 return attributeLists.toArray(Attribute[]::new); 858 return attributeLists.toArray(Attribute[]::new);
837 } 859 }
838 860
839 -  
840 public static Set<String> convertJsonArrayToSet(JsonArray jsonArray) { 861 public static Set<String> convertJsonArrayToSet(JsonArray jsonArray) {
841 List<String> attributeListOld = new Gson().fromJson(jsonArray, new TypeToken<List<String>>() { 862 List<String> attributeListOld = new Gson().fromJson(jsonArray, new TypeToken<List<String>>() {
842 }.getType()); 863 }.getType());
@@ -863,4 +884,47 @@ public class LwM2mTransportUtil { @@ -863,4 +884,47 @@ public class LwM2mTransportUtil {
863 return null; 884 return null;
864 } 885 }
865 } 886 }
  887 +
  888 + public static LwM2mTypeOper setValidTypeOper(String typeOper) {
  889 + try {
  890 + return LwM2mTransportUtil.LwM2mTypeOper.fromLwLwM2mTypeOper(typeOper);
  891 + } catch (Exception e) {
  892 + return null;
  893 + }
  894 + }
  895 +
  896 + public static Object convertWriteAttributes(String type, Object value, DefaultLwM2MTransportMsgHandler serviceImpl, String target) {
  897 + switch (type) {
  898 + /** Integer [0:255]; */
  899 + case DIMENSION:
  900 + Long dim = (Long) serviceImpl.converter.convertValue(value, equalsResourceTypeGetSimpleName(value), INTEGER, new LwM2mPath(target));
  901 + return dim >= 0 && dim <= 255 ? dim : null;
  902 + /**String;*/
  903 + case OBJECT_VERSION:
  904 + return serviceImpl.converter.convertValue(value, equalsResourceTypeGetSimpleName(value), STRING, new LwM2mPath(target));
  905 + /**INTEGER */
  906 + case MINIMUM_PERIOD:
  907 + case MAXIMUM_PERIOD:
  908 + return serviceImpl.converter.convertValue(value, equalsResourceTypeGetSimpleName(value), INTEGER, new LwM2mPath(target));
  909 + /**Float; */
  910 + case GREATER_THAN:
  911 + case LESSER_THAN:
  912 + case STEP:
  913 + if (value.getClass().getSimpleName().equals("String") ) {
  914 + value = Double.valueOf((String) value);
  915 + }
  916 + return serviceImpl.converter.convertValue(value, equalsResourceTypeGetSimpleName(value), FLOAT, new LwM2mPath(target));
  917 + default:
  918 + return null;
  919 + }
  920 + }
  921 +
  922 + private static Attribute createAttribute(String key, Object attrValue) {
  923 + try {
  924 + return new Attribute(key, attrValue);
  925 + } catch (Exception e) {
  926 + log.error("CreateAttribute, not valid parameter key: [{}], attrValue: [{}], error: [{}]", key, attrValue, e.getMessage());
  927 + return null;
  928 + }
  929 + }
866 } 930 }
@@ -31,8 +31,8 @@ import org.eclipse.leshan.server.registration.Registration; @@ -31,8 +31,8 @@ import org.eclipse.leshan.server.registration.Registration;
31 import org.eclipse.leshan.server.security.SecurityInfo; 31 import org.eclipse.leshan.server.security.SecurityInfo;
32 import org.thingsboard.server.common.data.Device; 32 import org.thingsboard.server.common.data.Device;
33 import org.thingsboard.server.common.data.DeviceProfile; 33 import org.thingsboard.server.common.data.DeviceProfile;
34 -import org.thingsboard.server.common.transport.auth.ValidateDeviceCredentialsResponse;  
35 import org.thingsboard.server.common.data.firmware.FirmwareType; 34 import org.thingsboard.server.common.data.firmware.FirmwareType;
  35 +import org.thingsboard.server.common.transport.auth.ValidateDeviceCredentialsResponse;
36 import org.thingsboard.server.gen.transport.TransportProtos.SessionInfoProto; 36 import org.thingsboard.server.gen.transport.TransportProtos.SessionInfoProto;
37 import org.thingsboard.server.gen.transport.TransportProtos.TsKvProto; 37 import org.thingsboard.server.gen.transport.TransportProtos.TsKvProto;
38 import org.thingsboard.server.transport.lwm2m.server.DefaultLwM2MTransportMsgHandler; 38 import org.thingsboard.server.transport.lwm2m.server.DefaultLwM2MTransportMsgHandler;
@@ -117,7 +117,6 @@ public class LwM2mClient implements Cloneable { @@ -117,7 +117,6 @@ public class LwM2mClient implements Cloneable {
117 this.pendingReadRequests = new CopyOnWriteArrayList<>(); 117 this.pendingReadRequests = new CopyOnWriteArrayList<>();
118 this.resources = new ConcurrentHashMap<>(); 118 this.resources = new ConcurrentHashMap<>();
119 this.profileId = profileId; 119 this.profileId = profileId;
120 - this.sessionId = sessionId;  
121 this.init = false; 120 this.init = false;
122 this.queuedRequests = new ConcurrentLinkedQueue<>(); 121 this.queuedRequests = new ConcurrentLinkedQueue<>();
123 122
@@ -194,17 +193,31 @@ public class LwM2mClient implements Cloneable { @@ -194,17 +193,31 @@ public class LwM2mClient implements Cloneable {
194 public Object getResourceValue(String pathRezIdVer, String pathRezId) { 193 public Object getResourceValue(String pathRezIdVer, String pathRezId) {
195 String pathRez = pathRezIdVer == null ? convertPathFromObjectIdToIdVer(pathRezId, this.registration) : pathRezIdVer; 194 String pathRez = pathRezIdVer == null ? convertPathFromObjectIdToIdVer(pathRezId, this.registration) : pathRezIdVer;
196 if (this.resources.get(pathRez) != null) { 195 if (this.resources.get(pathRez) != null) {
197 - return this.resources.get(pathRez).getLwM2mResource().isMultiInstances() ? 196 + return this.resources.get(pathRez).getLwM2mResource().isMultiInstances() ?
198 this.resources.get(pathRez).getLwM2mResource().getValues() : 197 this.resources.get(pathRez).getLwM2mResource().getValues() :
199 this.resources.get(pathRez).getLwM2mResource().getValue(); 198 this.resources.get(pathRez).getLwM2mResource().getValue();
200 } 199 }
201 return null; 200 return null;
202 } 201 }
203 202
204 - public Object getResourceName (String pathRezIdVer, String pathRezId) { 203 + public Object getResourceNameByRezId(String pathRezIdVer, String pathRezId) {
205 String pathRez = pathRezIdVer == null ? convertPathFromObjectIdToIdVer(pathRezId, this.registration) : pathRezIdVer; 204 String pathRez = pathRezIdVer == null ? convertPathFromObjectIdToIdVer(pathRezId, this.registration) : pathRezIdVer;
206 if (this.resources.get(pathRez) != null) { 205 if (this.resources.get(pathRez) != null) {
207 - return this.resources.get(pathRez).getResourceModel().name; 206 + return this.resources.get(pathRez).getResourceModel().name;
  207 + }
  208 + return null;
  209 + }
  210 +
  211 + public String getRezIdByResourceNameAndObjectInstanceId(String resourceName, String pathObjectInstanceIdVer, LwM2mModelProvider modelProvider) {
  212 + LwM2mPath pathIds = new LwM2mPath(convertPathFromIdVerToObjectId(pathObjectInstanceIdVer));
  213 + if (pathIds.isObjectInstance()) {
  214 + Set<Integer> rezIds = modelProvider.getObjectModel(registration)
  215 + .getObjectModel(pathIds.getObjectId()).resources.entrySet()
  216 + .stream()
  217 + .filter(map -> resourceName.equals(map.getValue().name))
  218 + .map(map -> map.getKey())
  219 + .collect(Collectors.toSet());
  220 + return rezIds.size() > 0 ? String.valueOf(rezIds.stream().findFirst().get()) : null;
208 } 221 }
209 return null; 222 return null;
210 } 223 }
@@ -225,11 +238,11 @@ public class LwM2mClient implements Cloneable { @@ -225,11 +238,11 @@ public class LwM2mClient implements Cloneable {
225 .getObjectModel(pathIds.getObjectId()) : null; 238 .getObjectModel(pathIds.getObjectId()) : null;
226 } 239 }
227 240
228 - public String objectToString (LwM2mObject lwM2mObject, LwM2mValueConverterImpl converter, String pathIdVer) { 241 + public String objectToString(LwM2mObject lwM2mObject, LwM2mValueConverterImpl converter, String pathIdVer) {
229 StringBuilder builder = new StringBuilder(); 242 StringBuilder builder = new StringBuilder();
230 builder.append("LwM2mObject [id=").append(lwM2mObject.getId()).append(", instances={"); 243 builder.append("LwM2mObject [id=").append(lwM2mObject.getId()).append(", instances={");
231 lwM2mObject.getInstances().forEach((instId, inst) -> { 244 lwM2mObject.getInstances().forEach((instId, inst) -> {
232 - builder.append(instId).append("=").append(this.instanceToString(inst, converter, pathIdVer)).append(", "); 245 + builder.append(instId).append("=").append(this.instanceToString(inst, converter, pathIdVer)).append(", ");
233 }); 246 });
234 int startInd = builder.lastIndexOf(", "); 247 int startInd = builder.lastIndexOf(", ");
235 if (startInd > 0) { 248 if (startInd > 0) {
@@ -238,11 +251,12 @@ public class LwM2mClient implements Cloneable { @@ -238,11 +251,12 @@ public class LwM2mClient implements Cloneable {
238 builder.append("}]"); 251 builder.append("}]");
239 return builder.toString(); 252 return builder.toString();
240 } 253 }
241 - public String instanceToString (LwM2mObjectInstance objectInstance, LwM2mValueConverterImpl converter, String pathIdVer) { 254 +
  255 + public String instanceToString(LwM2mObjectInstance objectInstance, LwM2mValueConverterImpl converter, String pathIdVer) {
242 StringBuilder builder = new StringBuilder(); 256 StringBuilder builder = new StringBuilder();
243 builder.append("LwM2mObjectInstance [id=").append(objectInstance.getId()).append(", resources={"); 257 builder.append("LwM2mObjectInstance [id=").append(objectInstance.getId()).append(", resources={");
244 objectInstance.getResources().forEach((resId, res) -> { 258 objectInstance.getResources().forEach((resId, res) -> {
245 - builder.append(resId).append("=").append(this.resourceToString (res, converter, pathIdVer)).append(", "); 259 + builder.append(resId).append("=").append(this.resourceToString(res, converter, pathIdVer)).append(", ");
246 }); 260 });
247 int startInd = builder.lastIndexOf(", "); 261 int startInd = builder.lastIndexOf(", ");
248 if (startInd > 0) { 262 if (startInd > 0) {
@@ -252,12 +266,11 @@ public class LwM2mClient implements Cloneable { @@ -252,12 +266,11 @@ public class LwM2mClient implements Cloneable {
252 return builder.toString(); 266 return builder.toString();
253 } 267 }
254 268
255 - public String resourceToString (LwM2mResource lwM2mResource, LwM2mValueConverterImpl converter, String pathIdVer) { 269 + public String resourceToString(LwM2mResource lwM2mResource, LwM2mValueConverterImpl converter, String pathIdVer) {
256 if (!OPAQUE.equals(lwM2mResource.getType())) { 270 if (!OPAQUE.equals(lwM2mResource.getType())) {
257 return lwM2mResource.isMultiInstances() ? ((LwM2mMultipleResource) lwM2mResource).toString() : 271 return lwM2mResource.isMultiInstances() ? ((LwM2mMultipleResource) lwM2mResource).toString() :
258 ((LwM2mSingleResource) lwM2mResource).toString(); 272 ((LwM2mSingleResource) lwM2mResource).toString();
259 - }  
260 - else { 273 + } else {
261 return String.format("LwM2mSingleResource [id=%s, value=%s, type=%s]", lwM2mResource.getId(), 274 return String.format("LwM2mSingleResource [id=%s, value=%s, type=%s]", lwM2mResource.getId(),
262 converter.convertValue(lwM2mResource.getValue(), 275 converter.convertValue(lwM2mResource.getValue(),
263 OPAQUE, STRING, new LwM2mPath(convertPathFromIdVerToObjectId(pathIdVer))), lwM2mResource.getType().name()); 276 OPAQUE, STRING, new LwM2mPath(convertPathFromIdVerToObjectId(pathIdVer))), lwM2mResource.getType().name());
@@ -275,7 +288,8 @@ public class LwM2mClient implements Cloneable { @@ -275,7 +288,8 @@ public class LwM2mClient implements Cloneable {
275 resources.add(LwM2mSingleResource.newResource(resId, converter.convertValue(params, 288 resources.add(LwM2mSingleResource.newResource(resId, converter.convertValue(params,
276 equalsResourceTypeGetSimpleName(params), resourceModel.type, pathIds), resourceModel.type)); 289 equalsResourceTypeGetSimpleName(params), resourceModel.type, pathIds), resourceModel.type));
277 290
278 - }}); 291 + }
  292 + });
279 return resources; 293 return resources;
280 } 294 }
281 295
@@ -291,7 +305,8 @@ public class LwM2mClient implements Cloneable { @@ -291,7 +305,8 @@ public class LwM2mClient implements Cloneable {
291 resources.add(LwM2mSingleResource.newResource(resId, 305 resources.add(LwM2mSingleResource.newResource(resId,
292 converter.convertValue(value, equalsResourceTypeGetSimpleName(value), resourceModel.type, pathIds), resourceModel.type)); 306 converter.convertValue(value, equalsResourceTypeGetSimpleName(value), resourceModel.type, pathIds), resourceModel.type));
293 307
294 - }}); 308 + }
  309 + });
295 return resources; 310 return resources;
296 } 311 }
297 312
@@ -35,8 +35,6 @@ public interface LwM2mClientContext { @@ -35,8 +35,6 @@ public interface LwM2mClientContext {
35 35
36 LwM2mClient getClient(TransportProtos.SessionInfoProto sessionInfo); 36 LwM2mClient getClient(TransportProtos.SessionInfoProto sessionInfo);
37 37
38 - LwM2mClient getClient(UUID sessionId);  
39 -  
40 LwM2mClient getOrRegister(Registration registration); 38 LwM2mClient getOrRegister(Registration registration);
41 39
42 LwM2mClient registerOrUpdate(Registration registration); 40 LwM2mClient registerOrUpdate(Registration registration);
@@ -83,13 +83,11 @@ public class LwM2mClientContextImpl implements LwM2mClientContext { @@ -83,13 +83,11 @@ public class LwM2mClientContextImpl implements LwM2mClientContext {
83 83
84 @Override 84 @Override
85 public LwM2mClient getClient(TransportProtos.SessionInfoProto sessionInfo) { 85 public LwM2mClient getClient(TransportProtos.SessionInfoProto sessionInfo) {
86 - return getClient(new UUID(sessionInfo.getSessionIdMSB(), sessionInfo.getSessionIdLSB()));  
87 - } 86 + return lwM2mClientsByEndpoint.values().stream().filter(c ->
  87 + (new UUID(sessionInfo.getSessionIdMSB(), sessionInfo.getSessionIdLSB()))
  88 + .equals((new UUID(c.getSession().getSessionIdMSB(), c.getSession().getSessionIdLSB())))
88 89
89 - @Override  
90 - public LwM2mClient getClient(UUID sessionId) {  
91 - //TODO: refactor this to search by sessionId efficiently.  
92 - return lwM2mClientsByEndpoint.values().stream().filter(c -> c.getSessionId().equals(sessionId)).findAny().get(); 90 + ).findAny().get();
93 } 91 }
94 92
95 @Override 93 @Override
@@ -286,7 +286,7 @@ public class LwM2mFwSwUpdate { @@ -286,7 +286,7 @@ public class LwM2mFwSwUpdate {
286 Long updateResult = (Long) this.lwM2MClient.getResourceValue(null, this.pathResultId); 286 Long updateResult = (Long) this.lwM2MClient.getResourceValue(null, this.pathResultId);
287 String value = FIRMWARE.equals(this.type) ? LwM2mTransportUtil.UpdateResultFw.fromUpdateResultFwByCode(updateResult.intValue()).type : 287 String value = FIRMWARE.equals(this.type) ? LwM2mTransportUtil.UpdateResultFw.fromUpdateResultFwByCode(updateResult.intValue()).type :
288 LwM2mTransportUtil.UpdateResultSw.fromUpdateResultSwByCode(updateResult.intValue()).type; 288 LwM2mTransportUtil.UpdateResultSw.fromUpdateResultSwByCode(updateResult.intValue()).type;
289 - String key = splitCamelCaseString((String) this.lwM2MClient.getResourceName(null, this.pathResultId)); 289 + String key = splitCamelCaseString((String) this.lwM2MClient.getResourceNameByRezId(null, this.pathResultId));
290 if (success) { 290 if (success) {
291 this.stateUpdate = FirmwareUpdateStatus.UPDATED.name(); 291 this.stateUpdate = FirmwareUpdateStatus.UPDATED.name();
292 this.sendLogs(handler, EXECUTE.name(), LOG_LW2M_INFO, null); 292 this.sendLogs(handler, EXECUTE.name(), LOG_LW2M_INFO, null);
@@ -15,98 +15,265 @@ @@ -15,98 +15,265 @@
15 */ 15 */
16 package org.thingsboard.server.transport.lwm2m.server.client; 16 package org.thingsboard.server.transport.lwm2m.server.client;
17 17
  18 +import com.google.gson.Gson;
18 import com.google.gson.JsonObject; 19 import com.google.gson.JsonObject;
  20 +import com.google.gson.reflect.TypeToken;
19 import lombok.Data; 21 import lombok.Data;
20 import lombok.extern.slf4j.Slf4j; 22 import lombok.extern.slf4j.Slf4j;
21 -import org.eclipse.leshan.core.request.ContentFormat; 23 +import org.apache.commons.lang3.StringUtils;
  24 +import org.eclipse.leshan.core.node.LwM2mPath;
22 import org.eclipse.leshan.server.registration.Registration; 25 import org.eclipse.leshan.server.registration.Registration;
23 import org.thingsboard.server.gen.transport.TransportProtos; 26 import org.thingsboard.server.gen.transport.TransportProtos;
24 -import org.thingsboard.server.gen.transport.TransportProtos.SessionInfoProto;  
25 -import org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LwM2mTypeOper; 27 +import org.thingsboard.server.transport.lwm2m.server.DefaultLwM2MTransportMsgHandler;
26 28
  29 +import java.util.Map;
  30 +import java.util.Objects;
27 import java.util.concurrent.ConcurrentHashMap; 31 import java.util.concurrent.ConcurrentHashMap;
  32 +import java.util.concurrent.TimeoutException;
28 33
  34 +import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.ERROR_KEY;
  35 +import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.FINISH_JSON_KEY;
  36 +import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.FINISH_VALUE_KEY;
  37 +import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.INFO_KEY;
  38 +import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.KEY_NAME_KEY;
  39 +import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LwM2mTypeOper;
  40 +import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LwM2mTypeOper.DISCOVER_ALL;
  41 +import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LwM2mTypeOper.EXECUTE;
  42 +import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LwM2mTypeOper.OBSERVE_CANCEL;
  43 +import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LwM2mTypeOper.OBSERVE_READ_ALL;
  44 +import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LwM2mTypeOper.WRITE_ATTRIBUTES;
  45 +import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LwM2mTypeOper.WRITE_REPLACE;
  46 +import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LwM2mTypeOper.WRITE_UPDATE;
  47 +import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.METHOD_KEY;
  48 +import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.PARAMS_KEY;
  49 +import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.RESULT_KEY;
  50 +import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.SEPARATOR_KEY;
  51 +import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.START_JSON_KEY;
  52 +import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.TARGET_ID_VER_KEY;
  53 +import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.VALUE_KEY;
  54 +import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.convertPathFromIdVerToObjectId;
29 import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.validPathIdVer; 55 import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.validPathIdVer;
30 56
31 @Slf4j 57 @Slf4j
32 @Data 58 @Data
33 public class Lwm2mClientRpcRequest { 59 public class Lwm2mClientRpcRequest {
34 - public final String targetIdVerKey = "targetIdVer";  
35 - public final String keyNameKey = "key";  
36 - public final String typeOperKey = "typeOper";  
37 - public final String contentFormatNameKey = "contentFormatName";  
38 - public final String valueKey = "value";  
39 - public final String infoKey = "info";  
40 - public final String paramsKey = "params";  
41 - public final String timeoutInMsKey = "timeOutInMs";  
42 - public final String resultKey = "result";  
43 - public final String errorKey = "error";  
44 - public final String methodKey = "methodName"; 60 +
  61 + private Registration registration;
  62 + private TransportProtos.SessionInfoProto sessionInfo;
  63 + private String bodyParams;
  64 + private int requestId;
45 65
46 private LwM2mTypeOper typeOper; 66 private LwM2mTypeOper typeOper;
  67 + private String key;
47 private String targetIdVer; 68 private String targetIdVer;
48 - private String contentFormatName;  
49 - private long timeoutInMs;  
50 private Object value; 69 private Object value;
51 - private ConcurrentHashMap<String, Object> params;  
52 - private SessionInfoProto sessionInfo;  
53 - private int requestId; 70 + private Map<String, Object> params;
  71 +
54 private String errorMsg; 72 private String errorMsg;
55 private String valueMsg; 73 private String valueMsg;
56 private String infoMsg; 74 private String infoMsg;
57 private String responseCode; 75 private String responseCode;
58 76
59 - public void setValidTypeOper(String typeOper) { 77 + public Lwm2mClientRpcRequest() {
  78 + }
  79 +
  80 + public Lwm2mClientRpcRequest(LwM2mTypeOper lwM2mTypeOper, String bodyParams, int requestId,
  81 + TransportProtos.SessionInfoProto sessionInfo, Registration registration, DefaultLwM2MTransportMsgHandler handler) {
  82 + this.registration = registration;
  83 + this.sessionInfo = sessionInfo;
  84 + this.requestId = requestId;
  85 + if (lwM2mTypeOper != null) {
  86 + this.typeOper = lwM2mTypeOper;
  87 + } else {
  88 + this.errorMsg = METHOD_KEY + " - " + typeOper + " is not valid.";
  89 + }
  90 + if (this.errorMsg == null && !bodyParams.equals("null")) {
  91 + this.bodyParams = bodyParams;
  92 + this.init(handler);
  93 + }
  94 + }
  95 +
  96 + public TransportProtos.ToDeviceRpcResponseMsg getDeviceRpcResponseResultMsg() {
  97 + JsonObject payloadResp = new JsonObject();
  98 + payloadResp.addProperty(RESULT_KEY, this.responseCode);
  99 + if (this.errorMsg != null) {
  100 + payloadResp.addProperty(ERROR_KEY, this.errorMsg);
  101 + } else if (this.valueMsg != null) {
  102 + payloadResp.addProperty(VALUE_KEY, this.valueMsg);
  103 + } else if (this.infoMsg != null) {
  104 + payloadResp.addProperty(INFO_KEY, this.infoMsg);
  105 + }
  106 + return TransportProtos.ToDeviceRpcResponseMsg.newBuilder()
  107 + .setPayload(payloadResp.getAsJsonObject().toString())
  108 + .setRequestId(this.requestId)
  109 + .build();
  110 + }
  111 +
  112 + private void init(DefaultLwM2MTransportMsgHandler handler) {
60 try { 113 try {
61 - this.typeOper = LwM2mTypeOper.fromLwLwM2mTypeOper(typeOper); 114 + // #1
  115 + if (this.bodyParams.contains(KEY_NAME_KEY)) {
  116 + String targetIdVerStr = this.getValueKeyFromBody(KEY_NAME_KEY);
  117 + if (targetIdVerStr != null) {
  118 + String targetIdVer = handler.getPresentPathIntoProfile(sessionInfo, targetIdVerStr);
  119 + if (targetIdVer != null) {
  120 + this.targetIdVer = targetIdVer;
  121 + this.setInfoMsg(String.format("Changed by: key - %s, pathIdVer - %s",
  122 + targetIdVerStr, targetIdVer));
  123 + }
  124 + }
  125 + }
  126 + if (this.getTargetIdVer() == null && this.bodyParams.contains(TARGET_ID_VER_KEY)) {
  127 + this.setValidTargetIdVerKey();
  128 + }
  129 + if (this.bodyParams.contains(VALUE_KEY)) {
  130 + this.value = this.getValueKeyFromBody(VALUE_KEY);
  131 + }
  132 + try {
  133 + if (this.bodyParams.contains(PARAMS_KEY)) {
  134 + this.setValidParamsKey(handler);
  135 + }
  136 + } catch (Exception e) {
  137 + this.setErrorMsg(String.format("Params of request is bad Json format. %s", e.getMessage()));
  138 + }
  139 +
  140 + if (this.getTargetIdVer() == null
  141 + && !(OBSERVE_READ_ALL == this.getTypeOper()
  142 + || DISCOVER_ALL == this.getTypeOper()
  143 + || OBSERVE_CANCEL == this.getTypeOper())) {
  144 + this.setErrorMsg(TARGET_ID_VER_KEY + " and " +
  145 + KEY_NAME_KEY + " is null or bad format");
  146 + }
  147 + /**
  148 + * EXECUTE && WRITE_REPLACE - only for Resource or ResourceInstance
  149 + */
  150 + else if (this.getTargetIdVer() != null
  151 + && (EXECUTE == this.getTypeOper()
  152 + || WRITE_REPLACE == this.getTypeOper())
  153 + && !(new LwM2mPath(Objects.requireNonNull(convertPathFromIdVerToObjectId(this.getTargetIdVer()))).isResource()
  154 + || new LwM2mPath(Objects.requireNonNull(convertPathFromIdVerToObjectId(this.getTargetIdVer()))).isResourceInstance())) {
  155 + this.setErrorMsg("Invalid parameter " + TARGET_ID_VER_KEY
  156 + + ". Only Resource or ResourceInstance can be this operation");
  157 + }
62 } catch (Exception e) { 158 } catch (Exception e) {
63 - this.errorMsg = this.methodKey + " - " + typeOper + " is not valid."; 159 + this.setErrorMsg(String.format("Bad format request. %s", e.getMessage()));
64 } 160 }
  161 +
65 } 162 }
66 163
67 - public void setValidContentFormatName(JsonObject rpcRequest) { 164 + private void setValidTargetIdVerKey() {
  165 + String targetIdVerStr = this.getValueKeyFromBody(TARGET_ID_VER_KEY);
  166 + // targetIdVer without ver - ok
68 try { 167 try {
69 - if (ContentFormat.fromName(rpcRequest.get(this.contentFormatNameKey).getAsString()) != null) {  
70 - this.contentFormatName = rpcRequest.get(this.contentFormatNameKey).getAsString();  
71 - } else {  
72 - this.errorMsg = this.contentFormatNameKey + " - " + rpcRequest.get(this.contentFormatNameKey).getAsString() + " is not valid."; 168 + // targetIdVer with/without ver - ok
  169 + this.targetIdVer = validPathIdVer(targetIdVerStr, this.registration);
  170 + if (this.targetIdVer != null) {
  171 + this.infoMsg = String.format("Changed by: pathIdVer - %s", this.targetIdVer);
73 } 172 }
74 } catch (Exception e) { 173 } catch (Exception e) {
75 - this.errorMsg = this.contentFormatNameKey + " - " + rpcRequest.get(this.contentFormatNameKey).getAsString() + " is not valid."; 174 + if (this.targetIdVer == null) {
  175 + this.errorMsg = TARGET_ID_VER_KEY + " - " + targetIdVerStr + " is not valid.";
  176 + }
76 } 177 }
77 } 178 }
78 179
79 - public void setValidTargetIdVerKey(JsonObject rpcRequest, Registration registration) {  
80 - if (rpcRequest.has(this.targetIdVerKey)) {  
81 - String targetIdVerStr = rpcRequest.get(targetIdVerKey).getAsString();  
82 - // targetIdVer without ver - ok  
83 - try {  
84 - // targetIdVer with/without ver - ok  
85 - this.targetIdVer = validPathIdVer(targetIdVerStr, registration); 180 + private void setValidParamsKey(DefaultLwM2MTransportMsgHandler handler) {
  181 + String paramsStr = this.getValueKeyFromBody(PARAMS_KEY);
  182 + if (paramsStr != null) {
  183 + String params2Json =
  184 + START_JSON_KEY
  185 + + "\""
  186 + + paramsStr
  187 + .replaceAll(SEPARATOR_KEY, "\"" + SEPARATOR_KEY + "\"")
  188 + .replaceAll(FINISH_VALUE_KEY, "\"" + FINISH_VALUE_KEY + "\"")
  189 + + "\""
  190 + + FINISH_JSON_KEY;
  191 + // jsonObject
  192 + Map<String, Object> params = new Gson().fromJson(params2Json, new TypeToken<ConcurrentHashMap<String, Object>>() {
  193 + }.getType());
  194 + if (WRITE_UPDATE == this.getTypeOper()) {
86 if (this.targetIdVer != null) { 195 if (this.targetIdVer != null) {
87 - this.infoMsg = String.format("Changed by: pathIdVer - %s", this.targetIdVer);  
88 - }  
89 - } catch (Exception e) {  
90 - if (this.targetIdVer == null) {  
91 - this.errorMsg = this.targetIdVerKey + " - " + targetIdVerStr + " is not valid."; 196 + Map<String, Object> paramsResourceId = this.convertParamsToResourceId((ConcurrentHashMap<String, Object>) params, handler);
  197 + if (paramsResourceId.size() > 0) {
  198 + this.setParams(paramsResourceId);
  199 + }
92 } 200 }
  201 + } else if (WRITE_ATTRIBUTES == this.getTypeOper()) {
  202 + this.setParams(params);
93 } 203 }
94 } 204 }
95 } 205 }
96 206
97 - public TransportProtos.ToDeviceRpcResponseMsg getDeviceRpcResponseResultMsg() {  
98 - JsonObject payloadResp = new JsonObject();  
99 - payloadResp.addProperty(this.resultKey, this.responseCode);  
100 - if (this.errorMsg != null) {  
101 - payloadResp.addProperty(this.errorKey, this.errorMsg);  
102 - } else if (this.valueMsg != null) {  
103 - payloadResp.addProperty(this.valueKey, this.valueMsg);  
104 - } else if (this.infoMsg != null) {  
105 - payloadResp.addProperty(this.infoKey, this.infoMsg); 207 + private String getValueKeyFromBody(String key) {
  208 + String valueKey = null;
  209 + int startInd = -1;
  210 + int finishInd = -1;
  211 + try {
  212 + switch (key) {
  213 + case KEY_NAME_KEY:
  214 + case TARGET_ID_VER_KEY:
  215 + case VALUE_KEY:
  216 + startInd = this.bodyParams.indexOf(SEPARATOR_KEY, this.bodyParams.indexOf(key));
  217 + finishInd = this.bodyParams.indexOf(FINISH_VALUE_KEY, this.bodyParams.indexOf(key));
  218 + if (startInd >= 0 && finishInd < 0) {
  219 + finishInd = this.bodyParams.indexOf(FINISH_JSON_KEY, this.bodyParams.indexOf(key));
  220 + }
  221 + break;
  222 + case PARAMS_KEY:
  223 + startInd = this.bodyParams.indexOf(START_JSON_KEY, this.bodyParams.indexOf(key));
  224 + finishInd = this.bodyParams.indexOf(FINISH_JSON_KEY, this.bodyParams.indexOf(key));
  225 + }
  226 + if (startInd >= 0 && finishInd > 0) {
  227 + valueKey = this.bodyParams.substring(startInd + 1, finishInd);
  228 + }
  229 + } catch (Exception e) {
  230 + log.error("", new TimeoutException());
106 } 231 }
107 - return TransportProtos.ToDeviceRpcResponseMsg.newBuilder()  
108 - .setPayload(payloadResp.getAsJsonObject().toString())  
109 - .setRequestId(this.requestId)  
110 - .build(); 232 + /**
  233 + * ReplaceAll "\""
  234 + */
  235 + if (StringUtils.trimToNull(valueKey) != null) {
  236 + char[] chars = valueKey.toCharArray();
  237 + for (int i = 0; i < chars.length; i++) {
  238 + if (chars[i] == 92 || chars[i] == 34) chars[i] = 32;
  239 + }
  240 + return key.equals(PARAMS_KEY) ? String.valueOf(chars) : String.valueOf(chars).replaceAll(" ", "");
  241 + }
  242 + return null;
  243 + }
  244 +
  245 + private ConcurrentHashMap<String, Object> convertParamsToResourceId(ConcurrentHashMap<String, Object> params,
  246 + DefaultLwM2MTransportMsgHandler serviceImpl) {
  247 + Map<String, Object> paramsIdVer = new ConcurrentHashMap<>();
  248 + LwM2mPath targetId = new LwM2mPath(Objects.requireNonNull(convertPathFromIdVerToObjectId(this.targetIdVer)));
  249 + if (targetId.isObjectInstance()) {
  250 + params.forEach((k, v) -> {
  251 + try {
  252 + int id = Integer.parseInt(k);
  253 + paramsIdVer.put(String.valueOf(id), v);
  254 + } catch (NumberFormatException e) {
  255 + String targetIdVer = serviceImpl.getPresentPathIntoProfile(sessionInfo, k);
  256 + if (targetIdVer != null) {
  257 + LwM2mPath lwM2mPath = new LwM2mPath(Objects.requireNonNull(convertPathFromIdVerToObjectId(targetIdVer)));
  258 + paramsIdVer.put(String.valueOf(lwM2mPath.getResourceId()), v);
  259 + }
  260 + /** WRITE_UPDATE*/
  261 + else {
  262 + String rezId = this.getRezIdByResourceNameAndObjectInstanceId(k, serviceImpl);
  263 + if (rezId != null) {
  264 + paramsIdVer.put(rezId, v);
  265 + }
  266 + }
  267 + }
  268 + });
  269 + }
  270 + return (ConcurrentHashMap<String, Object>) paramsIdVer;
  271 + }
  272 +
  273 + private String getRezIdByResourceNameAndObjectInstanceId(String resourceName, DefaultLwM2MTransportMsgHandler handler) {
  274 + LwM2mClient lwM2mClient = handler.clientContext.getClient(this.sessionInfo);
  275 + return lwM2mClient != null ?
  276 + lwM2mClient.getRezIdByResourceNameAndObjectInstanceId(resourceName, this.targetIdVer, handler.config.getModelProvider()) :
  277 + null;
111 } 278 }
112 } 279 }