Commit 6cace79b3c4558d9ef3603c72fc5d108eedc611c
Committed by
GitHub
Merge pull request #4607 from thingsboard/lwm2m_rpc_fw_sw
Lwm2m: [WIP] Rps Fw Sw
Showing
10 changed files
with
508 additions
and
318 deletions
... | ... | @@ -89,7 +89,7 @@ public class DefaultTbResourceService implements TbResourceService { |
89 | 89 | } catch (InvalidDDFFileException | IOException e) { |
90 | 90 | throw new ThingsboardException(e, ThingsboardErrorCode.GENERAL); |
91 | 91 | } |
92 | - if (resource.getResourceType().equals(ResourceType.LWM2M_MODEL) && toLwM2mObject(resource) == null) { | |
92 | + if (resource.getResourceType().equals(ResourceType.LWM2M_MODEL) && toLwM2mObject(resource, true) == null) { | |
93 | 93 | throw new DataValidationException(String.format("Could not parse the XML of objectModel with name %s", resource.getSearchText())); |
94 | 94 | } |
95 | 95 | } else { |
... | ... | @@ -131,7 +131,7 @@ public class DefaultTbResourceService implements TbResourceService { |
131 | 131 | List<TbResource> resources = resourceService.findTenantResourcesByResourceTypeAndObjectIds(tenantId, ResourceType.LWM2M_MODEL, |
132 | 132 | objectIds); |
133 | 133 | return resources.stream() |
134 | - .flatMap(s -> Stream.ofNullable(toLwM2mObject(s))) | |
134 | + .flatMap(s -> Stream.ofNullable(toLwM2mObject(s, false))) | |
135 | 135 | .sorted(getComparator(sortProperty, sortOrder)) |
136 | 136 | .collect(Collectors.toList()); |
137 | 137 | } |
... | ... | @@ -142,7 +142,7 @@ public class DefaultTbResourceService implements TbResourceService { |
142 | 142 | validateId(tenantId, INCORRECT_TENANT_ID + tenantId); |
143 | 143 | PageData<TbResource> resourcePageData = resourceService.findTenantResourcesByResourceTypeAndPageLink(tenantId, ResourceType.LWM2M_MODEL, pageLink); |
144 | 144 | return resourcePageData.getData().stream() |
145 | - .flatMap(s -> Stream.ofNullable(toLwM2mObject(s))) | |
145 | + .flatMap(s -> Stream.ofNullable(toLwM2mObject(s, false))) | |
146 | 146 | .sorted(getComparator(sortProperty, sortOrder)) |
147 | 147 | .collect(Collectors.toList()); |
148 | 148 | } |
... | ... | @@ -167,7 +167,7 @@ public class DefaultTbResourceService implements TbResourceService { |
167 | 167 | return "DESC".equals(sortOrder) ? comparator.reversed() : comparator; |
168 | 168 | } |
169 | 169 | |
170 | - private LwM2mObject toLwM2mObject(TbResource resource) { | |
170 | + private LwM2mObject toLwM2mObject(TbResource resource, boolean isSave) { | |
171 | 171 | try { |
172 | 172 | DDFFileParser ddfFileParser = new DDFFileParser(new DefaultDDFFileValidator()); |
173 | 173 | List<ObjectModel> objectModels = |
... | ... | @@ -186,12 +186,16 @@ public class DefaultTbResourceService implements TbResourceService { |
186 | 186 | instance.setId(0); |
187 | 187 | List<LwM2mResourceObserve> resources = new ArrayList<>(); |
188 | 188 | obj.resources.forEach((k, v) -> { |
189 | - if (v.operations.isReadable()) { | |
189 | + if (isSave) { | |
190 | + LwM2mResourceObserve lwM2MResourceObserve = new LwM2mResourceObserve(k, v.name, false, false, false); | |
191 | + resources.add(lwM2MResourceObserve); | |
192 | + } | |
193 | + else if (v.operations.isReadable()) { | |
190 | 194 | LwM2mResourceObserve lwM2MResourceObserve = new LwM2mResourceObserve(k, v.name, false, false, false); |
191 | 195 | resources.add(lwM2MResourceObserve); |
192 | 196 | } |
193 | 197 | }); |
194 | - if (resources.size() > 0) { | |
198 | + if (isSave || resources.size() > 0) { | |
195 | 199 | instance.setResources(resources.toArray(LwM2mResourceObserve[]::new)); |
196 | 200 | lwM2mObject.setInstances(new LwM2mInstance[]{instance}); |
197 | 201 | return lwM2mObject; | ... | ... |
... | ... | @@ -23,6 +23,7 @@ import com.google.gson.JsonElement; |
23 | 23 | import com.google.gson.JsonObject; |
24 | 24 | import com.google.gson.reflect.TypeToken; |
25 | 25 | import lombok.extern.slf4j.Slf4j; |
26 | +import org.apache.commons.lang3.StringUtils; | |
26 | 27 | import org.eclipse.leshan.core.model.ObjectModel; |
27 | 28 | import org.eclipse.leshan.core.model.ResourceModel; |
28 | 29 | import org.eclipse.leshan.core.node.LwM2mObject; |
... | ... | @@ -61,6 +62,7 @@ import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient; |
61 | 62 | import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClientContext; |
62 | 63 | import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClientProfile; |
63 | 64 | import org.thingsboard.server.transport.lwm2m.server.client.Lwm2mClientRpcRequest; |
65 | +import org.thingsboard.server.transport.lwm2m.server.client.ResourceValue; | |
64 | 66 | import org.thingsboard.server.transport.lwm2m.server.client.ResultsAddKeyValueProto; |
65 | 67 | import org.thingsboard.server.transport.lwm2m.server.client.ResultsAnalyzerParameters; |
66 | 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 | 101 | import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LOG_LW2M_VALUE; |
100 | 102 | import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LWM2M_STRATEGY_2; |
101 | 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 | 104 | import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LwM2mTypeOper.EXECUTE; |
104 | 105 | import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LwM2mTypeOper.OBSERVE; |
105 | 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 | 108 | import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LwM2mTypeOper.READ; |
108 | 109 | import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LwM2mTypeOper.WRITE_ATTRIBUTES; |
109 | 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 | 111 | import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.SW_ID; |
112 | 112 | import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.SW_RESULT_ID; |
113 | 113 | import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.convertJsonArrayToSet; |
114 | 114 | import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.convertPathFromIdVerToObjectId; |
115 | 115 | import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.convertPathFromObjectIdToIdVer; |
116 | 116 | import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.getAckCallback; |
117 | +import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.setValidTypeOper; | |
117 | 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 | 126 | private ExecutorService registrationExecutor; |
126 | 127 | private ExecutorService updateRegistrationExecutor; |
127 | 128 | private ExecutorService unRegistrationExecutor; |
128 | - private LwM2mValueConverterImpl converter; | |
129 | + public LwM2mValueConverterImpl converter; | |
129 | 130 | |
130 | 131 | private final TransportService transportService; |
131 | 132 | private final LwM2mTransportContext context; |
... | ... | @@ -133,10 +134,10 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler |
133 | 134 | public final FirmwareDataCache firmwareDataCache; |
134 | 135 | public final LwM2mTransportServerHelper helper; |
135 | 136 | private final LwM2MJsonAdaptor adaptor; |
136 | - private final LwM2mClientContext clientContext; | |
137 | - private final LwM2mTransportRequest lwM2mTransportRequest; | |
138 | 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 | 142 | public DefaultLwM2MTransportMsgHandler(TransportService transportService, LwM2MTransportServerConfig config, LwM2mTransportServerHelper helper, |
142 | 143 | LwM2mClientContext clientContext, |
... | ... | @@ -151,6 +152,7 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler |
151 | 152 | this.firmwareDataCache = firmwareDataCache; |
152 | 153 | this.context = context; |
153 | 154 | this.adaptor = adaptor; |
155 | + this.rpcSubscriptions = new ConcurrentHashMap<>(); | |
154 | 156 | this.sessionStore = sessionStore; |
155 | 157 | } |
156 | 158 | |
... | ... | @@ -241,16 +243,14 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler |
241 | 243 | |
242 | 244 | /** |
243 | 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 | 248 | public void unReg(Registration registration, Collection<Observation> observations) { |
249 | + log.error("Client unRegistration -> test", new RuntimeException()); | |
248 | 250 | unRegistrationExecutor.submit(() -> { |
249 | 251 | try { |
250 | - this.setCancelObservationsAll(registration); | |
251 | 252 | this.sendLogsToThingsboard(LOG_LW2M_INFO + ": Client unRegistration", registration.getId()); |
252 | 253 | this.closeClientSession(registration); |
253 | - ; | |
254 | 254 | } catch (Throwable t) { |
255 | 255 | log.error("[{}] endpoint [{}] error Unable un registration.", registration.getEndpoint(), t); |
256 | 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 | 285 | @Override |
286 | 286 | public void setCancelObservationsAll(Registration registration) { |
287 | 287 | if (registration != null) { |
288 | - lwM2mTransportRequest.sendAllRequest(registration, null, OBSERVE_CANCEL, | |
288 | + lwM2mTransportRequest.sendAllRequest(registration, null, OBSERVE_CANCEL_ALL, | |
289 | 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 | 350 | */ |
355 | 351 | @Override |
356 | 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 | 354 | if (msg.getSharedUpdatedCount() > 0) { |
359 | 355 | msg.getSharedUpdatedList().forEach(tsKvProto -> { |
360 | 356 | String pathName = tsKvProto.getKv().getKey(); |
361 | 357 | String pathIdVer = this.getPresentPathIntoProfile(sessionInfo, pathName); |
362 | 358 | Object valueNew = getValueFromKvProto(tsKvProto.getKv()); |
359 | + log.warn("12) Shared AttributeUpdate start pathName [{}], pathIdVer [{}], valueNew [{}]", pathName, pathIdVer, valueNew); | |
363 | 360 | if ((FirmwareUtil.getAttributeKey(FirmwareType.FIRMWARE, FirmwareKey.VERSION).equals(pathName) |
364 | 361 | && (!valueNew.equals(lwM2MClient.getFwUpdate().getCurrentVersion()))) |
365 | 362 | || (FirmwareUtil.getAttributeKey(FirmwareType.FIRMWARE, FirmwareKey.TITLE).equals(pathName) |
... | ... | @@ -438,121 +435,49 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler |
438 | 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 | 442 | @Override |
442 | 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 | 483 | public void sentRpcRequest(Lwm2mClientRpcRequest rpcRequest, String requestCode, String msg, String typeMsg) { |
... | ... | @@ -722,10 +647,10 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler |
722 | 647 | * set setClient_fw_info... = value |
723 | 648 | **/ |
724 | 649 | if (lwM2MClient.getFwUpdate().isInfoFwSwUpdate()) { |
725 | - lwM2MClient.getFwUpdate().initReadValue(this, lwM2mTransportRequest, path); | |
650 | + lwM2MClient.getFwUpdate().initReadValue(this, this.lwM2mTransportRequest, path); | |
726 | 651 | } |
727 | 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 | 667 | && (convertPathFromObjectIdToIdVer(FW_RESULT_ID, registration).equals(path))) { |
743 | 668 | if (DOWNLOADED.name().equals(lwM2MClient.getFwUpdate().getStateUpdate()) |
744 | 669 | && lwM2MClient.getFwUpdate().conditionalFwExecuteStart()) { |
745 | - lwM2MClient.getFwUpdate().executeFwSwWare(this, lwM2mTransportRequest); | |
670 | + lwM2MClient.getFwUpdate().executeFwSwWare(this, this.lwM2mTransportRequest); | |
746 | 671 | } else if (UPDATING.name().equals(lwM2MClient.getFwUpdate().getStateUpdate()) |
747 | 672 | && lwM2MClient.getFwUpdate().conditionalFwExecuteAfterSuccess()) { |
748 | 673 | lwM2MClient.getFwUpdate().finishFwSwUpdate(this, true); |
... | ... | @@ -767,7 +692,7 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler |
767 | 692 | && (convertPathFromObjectIdToIdVer(SW_RESULT_ID, registration).equals(path))) { |
768 | 693 | if (DOWNLOADED.name().equals(lwM2MClient.getSwUpdate().getStateUpdate()) |
769 | 694 | && lwM2MClient.getSwUpdate().conditionalSwUpdateExecute()) { |
770 | - lwM2MClient.getSwUpdate().executeFwSwWare(this, lwM2mTransportRequest); | |
695 | + lwM2MClient.getSwUpdate().executeFwSwWare(this, this.lwM2mTransportRequest); | |
771 | 696 | } else if (UPDATING.name().equals(lwM2MClient.getSwUpdate().getStateUpdate()) |
772 | 697 | && lwM2MClient.getSwUpdate().conditionalSwExecuteAfterSuccess()) { |
773 | 698 | lwM2MClient.getSwUpdate().finishFwSwUpdate(this, true); |
... | ... | @@ -970,11 +895,14 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler |
970 | 895 | * @return - return value of Resource by idPath |
971 | 896 | */ |
972 | 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 | 1209 | * @param name - |
1282 | 1210 | * @return - |
1283 | 1211 | */ |
1284 | - private String getPresentPathIntoProfile(TransportProtos.SessionInfoProto sessionInfo, String name) { | |
1212 | + public String getPresentPathIntoProfile(TransportProtos.SessionInfoProto sessionInfo, String name) { | |
1285 | 1213 | LwM2mClientProfile profile = clientContext.getProfile(new UUID(sessionInfo.getDeviceProfileIdMSB(), sessionInfo.getDeviceProfileIdLSB())); |
1286 | 1214 | LwM2mClient lwM2mClient = clientContext.getClient(sessionInfo); |
1287 | 1215 | return profile.getPostKeyNameProfile().getAsJsonObject().entrySet().stream() |
... | ... | @@ -1304,7 +1232,7 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler |
1304 | 1232 | |
1305 | 1233 | this.updateAttributeFromThingsboard(tsKvProtos, sessionInfo); |
1306 | 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 | 1306 | private void reportActivityAndRegister(SessionInfoProto sessionInfo) { |
1379 | 1307 | if (sessionInfo != null && transportService.reportActivity(sessionInfo) == null) { |
1380 | 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 | 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 | 94 | @Override |
95 | 95 | public void onResponse(Observation observation, Registration registration, ObserveResponse response) { |
96 | 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 | 97 | service.onUpdateValueAfterReadResponse(registration, convertPathFromObjectIdToIdVer(observation.getPath().toString(), |
104 | 98 | registration), response, null); |
105 | 99 | } | ... | ... |
... | ... | @@ -22,6 +22,8 @@ import org.eclipse.californium.core.coap.Response; |
22 | 22 | import org.eclipse.leshan.core.Link; |
23 | 23 | import org.eclipse.leshan.core.model.ResourceModel; |
24 | 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 | 27 | import org.eclipse.leshan.core.node.LwM2mPath; |
26 | 28 | import org.eclipse.leshan.core.node.LwM2mResource; |
27 | 29 | import org.eclipse.leshan.core.node.LwM2mSingleResource; |
... | ... | @@ -34,6 +36,7 @@ import org.eclipse.leshan.core.request.DownlinkRequest; |
34 | 36 | import org.eclipse.leshan.core.request.ExecuteRequest; |
35 | 37 | import org.eclipse.leshan.core.request.ObserveRequest; |
36 | 38 | import org.eclipse.leshan.core.request.ReadRequest; |
39 | +import org.eclipse.leshan.core.request.WriteAttributesRequest; | |
37 | 40 | import org.eclipse.leshan.core.request.WriteRequest; |
38 | 41 | import org.eclipse.leshan.core.request.exception.ClientSleepingException; |
39 | 42 | import org.eclipse.leshan.core.response.DeleteResponse; |
... | ... | @@ -79,10 +82,12 @@ import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.L |
79 | 82 | import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LOG_LW2M_VALUE; |
80 | 83 | import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LwM2mTypeOper; |
81 | 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 | 86 | import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LwM2mTypeOper.EXECUTE; |
84 | 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 | 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 | 91 | import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LwM2mTypeOper.WRITE_REPLACE; |
87 | 92 | import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LwM2mTypeOper.WRITE_UPDATE; |
88 | 93 | import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.RESPONSE_REQUEST_CHANNEL; |
... | ... | @@ -123,7 +128,7 @@ public class LwM2mTransportRequest { |
123 | 128 | */ |
124 | 129 | |
125 | 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 | 132 | try { |
128 | 133 | String target = convertPathFromIdVerToObjectId(targetIdVer); |
129 | 134 | ContentFormat contentFormat = contentFormatName != null ? ContentFormat.fromName(contentFormatName.toUpperCase()) : ContentFormat.DEFAULT; |
... | ... | @@ -132,41 +137,42 @@ public class LwM2mTransportRequest { |
132 | 137 | if (!OBSERVE_READ_ALL.name().equals(typeOper.name()) && resultIds != null && registration != null && resultIds.getObjectId() >= 0 && lwM2MClient != null) { |
133 | 138 | if (lwM2MClient.isValidObjectVersion(targetIdVer)) { |
134 | 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 | 142 | if (request != null) { |
138 | 143 | try { |
139 | - this.sendRequest(registration, lwM2MClient, request, timeoutInMs, rpcRequest); | |
144 | + this.sendRequest(registration, lwM2MClient, request, timeoutInMs, lwm2mClientRpcRequest); | |
140 | 145 | } catch (ClientSleepingException e) { |
141 | 146 | DownlinkRequest finalRequest = request; |
142 | 147 | long finalTimeoutInMs = timeoutInMs; |
143 | - Lwm2mClientRpcRequest finalRpcRequest = rpcRequest; | |
148 | + Lwm2mClientRpcRequest finalRpcRequest = lwm2mClientRpcRequest; | |
144 | 149 | lwM2MClient.getQueuedRequests().add(() -> sendRequest(registration, lwM2MClient, finalRequest, finalTimeoutInMs, finalRpcRequest)); |
145 | 150 | } catch (Exception e) { |
146 | 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 | - Lwm2mClientRpcRequest rpcRequestClone = (Lwm2mClientRpcRequest) rpcRequest.clone(); | |
151 | - if (rpcRequestClone != null) { | |
153 | + } else if (WRITE_UPDATE.name().equals(typeOper.name())) { | |
154 | + if (lwm2mClientRpcRequest != null) { | |
152 | 155 | String errorMsg = String.format("Path %s params is not valid", targetIdVer); |
153 | - handler.sentRpcRequest(rpcRequestClone, BAD_REQUEST.getName(), errorMsg, LOG_LW2M_ERROR); | |
154 | - rpcRequest = null; | |
156 | + handler.sentRpcRequest(lwm2mClientRpcRequest, BAD_REQUEST.getName(), errorMsg, LOG_LW2M_ERROR); | |
155 | 157 | } |
156 | - } | |
157 | - else if (!OBSERVE_CANCEL.name().equals(typeOper.name())) { | |
158 | + } else if (WRITE_REPLACE.name().equals(typeOper.name()) || EXECUTE.name().equals(typeOper.name())) { | |
159 | + if (lwm2mClientRpcRequest != null) { | |
160 | + String errorMsg = String.format("Path %s object model is absent", targetIdVer); | |
161 | + handler.sentRpcRequest(lwm2mClientRpcRequest, BAD_REQUEST.getName(), errorMsg, LOG_LW2M_ERROR); | |
162 | + } | |
163 | + } else if (!OBSERVE_CANCEL.name().equals(typeOper.name())) { | |
158 | 164 | log.error("[{}], [{}] - [{}] error SendRequest", registration.getEndpoint(), typeOper.name(), targetIdVer); |
159 | - if (rpcRequest != null) { | |
165 | + if (lwm2mClientRpcRequest != null) { | |
160 | 166 | ResourceModel resourceModel = lwM2MClient.getResourceModel(targetIdVer, this.config.getModelProvider()); |
161 | 167 | String errorMsg = resourceModel == null ? String.format("Path %s not found in object version", targetIdVer) : "SendRequest - null"; |
162 | - handler.sentRpcRequest(rpcRequest, NOT_FOUND.getName(), errorMsg, LOG_LW2M_ERROR); | |
168 | + this.handler.sentRpcRequest(lwm2mClientRpcRequest, NOT_FOUND.getName(), errorMsg, LOG_LW2M_ERROR); | |
163 | 169 | } |
164 | 170 | } |
165 | - } else if (rpcRequest != null) { | |
171 | + } else if (lwm2mClientRpcRequest != null) { | |
166 | 172 | String errorMsg = String.format("Path %s not found in object version", targetIdVer); |
167 | - handler.sentRpcRequest(rpcRequest, NOT_FOUND.getName(), errorMsg, LOG_LW2M_ERROR); | |
173 | + this.handler.sentRpcRequest(lwm2mClientRpcRequest, NOT_FOUND.getName(), errorMsg, LOG_LW2M_ERROR); | |
168 | 174 | } |
169 | - } 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())) { | |
170 | 176 | Set<String> paths; |
171 | 177 | if (OBSERVE_READ_ALL.name().equals(typeOper.name())) { |
172 | 178 | Set<Observation> observations = context.getServer().getObservationService().getObservations(registration); |
... | ... | @@ -175,34 +181,34 @@ public class LwM2mTransportRequest { |
175 | 181 | assert registration != null; |
176 | 182 | Link[] objectLinks = registration.getSortedObjectLinks(); |
177 | 183 | paths = Arrays.stream(objectLinks).map(Link::toString).collect(Collectors.toUnmodifiableSet()); |
178 | - String msg = String.format("%s: type operation %s paths - %s", LOG_LW2M_INFO, | |
179 | - typeOper.name(), paths); | |
180 | - handler.sendLogsToThingsboard(msg, registration.getId()); | |
181 | 184 | } |
182 | - 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) { | |
183 | 189 | String valueMsg = String.format("Paths - %s", paths); |
184 | - handler.sentRpcRequest(rpcRequest, CONTENT.name(), valueMsg, LOG_LW2M_VALUE); | |
190 | + this.handler.sentRpcRequest(lwm2mClientRpcRequest, CONTENT.name(), valueMsg, LOG_LW2M_VALUE); | |
185 | 191 | } |
186 | - } else if (OBSERVE_CANCEL.name().equals(typeOper.name())) { | |
192 | + } else if (OBSERVE_CANCEL_ALL.name().equals(typeOper.name())) { | |
187 | 193 | int observeCancelCnt = context.getServer().getObservationService().cancelObservations(registration); |
188 | 194 | String observeCancelMsgAll = String.format("%s: type operation %s paths: All count: %d", LOG_LW2M_INFO, |
189 | 195 | OBSERVE_CANCEL.name(), observeCancelCnt); |
190 | - this.afterObserveCancel(registration, observeCancelCnt, observeCancelMsgAll, rpcRequest); | |
196 | + this.afterObserveCancel(registration, observeCancelCnt, observeCancelMsgAll, lwm2mClientRpcRequest); | |
191 | 197 | } |
192 | 198 | } catch (Exception e) { |
193 | 199 | String msg = String.format("%s: type operation %s %s", LOG_LW2M_ERROR, |
194 | 200 | typeOper.name(), e.getMessage()); |
195 | 201 | handler.sendLogsToThingsboard(msg, registration.getId()); |
196 | - if (rpcRequest != null) { | |
202 | + if (lwm2mClientRpcRequest != null) { | |
197 | 203 | String errorMsg = String.format("Path %s type operation %s %s", targetIdVer, typeOper.name(), e.getMessage()); |
198 | - handler.sentRpcRequest(rpcRequest, NOT_FOUND.getName(), errorMsg, LOG_LW2M_ERROR); | |
204 | + handler.sentRpcRequest(lwm2mClientRpcRequest, NOT_FOUND.getName(), errorMsg, LOG_LW2M_ERROR); | |
199 | 205 | } |
200 | 206 | } |
201 | 207 | } |
202 | 208 | |
203 | - private DownlinkRequest createRequest (Registration registration, LwM2mClient lwM2MClient, LwM2mTypeOper typeOper, | |
204 | - ContentFormat contentFormat, String target, String targetIdVer, | |
205 | - 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) { | |
206 | 212 | DownlinkRequest request = null; |
207 | 213 | switch (typeOper) { |
208 | 214 | case READ: |
... | ... | @@ -212,7 +218,7 @@ public class LwM2mTransportRequest { |
212 | 218 | request = new DiscoverRequest(target); |
213 | 219 | break; |
214 | 220 | case OBSERVE: |
215 | - 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); | |
216 | 222 | log.warn(msg); |
217 | 223 | if (resultIds.isResource()) { |
218 | 224 | Set<Observation> observations = context.getServer().getObservationService().getObservations(registration); |
... | ... | @@ -240,11 +246,13 @@ public class LwM2mTransportRequest { |
240 | 246 | this.afterObserveCancel(registration, observeCancelCnt, observeCancelMsg, rpcRequest); |
241 | 247 | break; |
242 | 248 | case EXECUTE: |
243 | - ResourceModel resourceModelExe = lwM2MClient.getResourceModel(targetIdVer, this.config.getModelProvider()); | |
244 | - if (params != null && !resourceModelExe.multiple) { | |
245 | - request = new ExecuteRequest(target, (String) this.converter.convertValue(params, resourceModelExe.type, ResourceModel.Type.STRING, resultIds)); | |
246 | - } else { | |
247 | - request = new ExecuteRequest(target); | |
249 | + ResourceModel resourceModelExecute = lwM2MClient.getResourceModel(targetIdVer, this.config.getModelProvider()); | |
250 | + if (resourceModelExecute != null) { | |
251 | + if (params != null && !resourceModelExecute.multiple) { | |
252 | + request = new ExecuteRequest(target, (String) this.converter.convertValue(params, resourceModelExecute.type, ResourceModel.Type.STRING, resultIds)); | |
253 | + } else { | |
254 | + request = new ExecuteRequest(target); | |
255 | + } | |
248 | 256 | } |
249 | 257 | break; |
250 | 258 | case WRITE_REPLACE: |
... | ... | @@ -255,10 +263,12 @@ public class LwM2mTransportRequest { |
255 | 263 | * JSON, TEXT; |
256 | 264 | **/ |
257 | 265 | ResourceModel resourceModelWrite = lwM2MClient.getResourceModel(targetIdVer, this.config.getModelProvider()); |
258 | - contentFormat = getContentFormatByResourceModelType(resourceModelWrite, contentFormat); | |
259 | - request = this.getWriteRequestSingleResource(contentFormat, resultIds.getObjectId(), | |
260 | - resultIds.getObjectInstanceId(), resultIds.getResourceId(), params, resourceModelWrite.type, | |
261 | - registration, rpcRequest); | |
266 | + if (resourceModelWrite != null) { | |
267 | + contentFormat = getContentFormatByResourceModelType(resourceModelWrite, contentFormat); | |
268 | + request = this.getWriteRequestSingleResource(contentFormat, resultIds.getObjectId(), | |
269 | + resultIds.getObjectInstanceId(), resultIds.getResourceId(), params, resourceModelWrite.type, | |
270 | + registration, rpcRequest); | |
271 | + } | |
262 | 272 | break; |
263 | 273 | case WRITE_UPDATE: |
264 | 274 | if (resultIds.isResource()) { |
... | ... | @@ -297,7 +307,7 @@ public class LwM2mTransportRequest { |
297 | 307 | } |
298 | 308 | break; |
299 | 309 | case WRITE_ATTRIBUTES: |
300 | - request = createWriteAttributeRequest(target, params); | |
310 | + request = createWriteAttributeRequest(target, params, this.handler); | |
301 | 311 | break; |
302 | 312 | case DELETE: |
303 | 313 | request = new DeleteRequest(target); |
... | ... | @@ -465,7 +475,13 @@ public class LwM2mTransportRequest { |
465 | 475 | } else if (response instanceof ExecuteResponse) { |
466 | 476 | log.warn("[{}] Path [{}] ExecuteResponse 7_Send", pathIdVer, response); |
467 | 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()); | |
468 | 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 | + } | |
469 | 485 | } else if (response instanceof WriteResponse) { |
470 | 486 | log.warn("[{}] Path [{}] WriteResponse 9_Send", pathIdVer, response); |
471 | 487 | this.infoWriteResponse(registration, response, request); |
... | ... | @@ -486,29 +502,37 @@ public class LwM2mTransportRequest { |
486 | 502 | private void infoWriteResponse(Registration registration, LwM2mResponse response, DownlinkRequest request) { |
487 | 503 | try { |
488 | 504 | LwM2mNode node = ((WriteRequest) request).getNode(); |
489 | - String msg; | |
505 | + String msg = null; | |
490 | 506 | Object value; |
491 | - LwM2mSingleResource singleResource = (LwM2mSingleResource) node; | |
492 | - if (singleResource.getType() == ResourceModel.Type.STRING || singleResource.getType() == ResourceModel.Type.OPAQUE) { | |
493 | - int valueLength; | |
494 | - if (singleResource.getType() == ResourceModel.Type.STRING) { | |
495 | - valueLength = ((String) singleResource.getValue()).length(); | |
496 | - value = ((String) singleResource.getValue()) | |
497 | - .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())); | |
498 | 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); | |
499 | 530 | } else { |
500 | - valueLength = ((byte[]) singleResource.getValue()).length; | |
501 | - value = new String(Arrays.copyOf(((byte[]) singleResource.getValue()), | |
502 | - 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); | |
503 | 535 | } |
504 | - value = valueLength > config.getLogMaxLength() ? value + "..." : value; | |
505 | - msg = String.format("%s: Update finished successfully: Lwm2m code - %d Resource path: %s length: %s value: %s", | |
506 | - LOG_LW2M_INFO, response.getCode().getCode(), request.getPath().toString(), valueLength, value); | |
507 | - } else { | |
508 | - value = this.converter.convertValue(singleResource.getValue(), | |
509 | - singleResource.getType(), ResourceModel.Type.STRING, request.getPath()); | |
510 | - msg = String.format("%s: Update finished successfully. Lwm2m code: %d Resource path: %s value: %s", | |
511 | - LOG_LW2M_INFO, response.getCode().getCode(), request.getPath().toString(), value); | |
512 | 536 | } |
513 | 537 | if (msg != null) { |
514 | 538 | handler.sendLogsToThingsboard(msg, registration.getId()); |
... | ... | @@ -530,11 +554,11 @@ public class LwM2mTransportRequest { |
530 | 554 | LwM2mClient lwM2MClient = this.lwM2mClientContext.getClientByRegistrationId(registration.getId()); |
531 | 555 | if (request.getPath().toString().equals(FW_PACKAGE_ID) && lwM2MClient.getFwUpdate() != null) { |
532 | 556 | lwM2MClient.getFwUpdate().setStateUpdate(DOWNLOADED.name()); |
533 | - lwM2MClient.getFwUpdate().sendLogs(handler, WRITE_REPLACE.name(), LOG_LW2M_INFO, null); | |
557 | + lwM2MClient.getFwUpdate().sendLogs(this.handler, WRITE_REPLACE.name(), LOG_LW2M_INFO, null); | |
534 | 558 | } |
535 | 559 | if (request.getPath().toString().equals(SW_PACKAGE_ID) && lwM2MClient.getSwUpdate() != null) { |
536 | 560 | lwM2MClient.getSwUpdate().setStateUpdate(DOWNLOADED.name()); |
537 | - lwM2MClient.getSwUpdate().sendLogs(handler, WRITE_REPLACE.name(), LOG_LW2M_INFO, null); | |
561 | + lwM2MClient.getSwUpdate().sendLogs(this.handler,WRITE_REPLACE.name(), LOG_LW2M_INFO, null); | |
538 | 562 | } |
539 | 563 | } |
540 | 564 | |
... | ... | @@ -545,21 +569,21 @@ public class LwM2mTransportRequest { |
545 | 569 | LwM2mClient lwM2MClient = this.lwM2mClientContext.getClientByRegistrationId(registration.getId()); |
546 | 570 | if (request.getPath().toString().equals(FW_PACKAGE_ID) && lwM2MClient.getFwUpdate() != null) { |
547 | 571 | lwM2MClient.getFwUpdate().setStateUpdate(FAILED.name()); |
548 | - lwM2MClient.getFwUpdate().sendLogs(handler, WRITE_REPLACE.name(), LOG_LW2M_ERROR, msgError); | |
572 | + lwM2MClient.getFwUpdate().sendLogs(this.handler, WRITE_REPLACE.name(), LOG_LW2M_ERROR, msgError); | |
549 | 573 | } |
550 | 574 | if (request.getPath().toString().equals(SW_PACKAGE_ID) && lwM2MClient.getSwUpdate() != null) { |
551 | 575 | lwM2MClient.getSwUpdate().setStateUpdate(FAILED.name()); |
552 | - lwM2MClient.getSwUpdate().sendLogs(handler, WRITE_REPLACE.name(), LOG_LW2M_ERROR, msgError); | |
576 | + lwM2MClient.getSwUpdate().sendLogs(this.handler, WRITE_REPLACE.name(), LOG_LW2M_ERROR, msgError); | |
553 | 577 | } |
554 | 578 | } |
555 | 579 | |
556 | 580 | private void afterExecuteFwSwUpdateError(Registration registration, DownlinkRequest request, String msgError) { |
557 | 581 | LwM2mClient lwM2MClient = this.lwM2mClientContext.getClientByRegistrationId(registration.getId()); |
558 | 582 | if (request.getPath().toString().equals(FW_UPDATE_ID) && lwM2MClient.getFwUpdate() != null) { |
559 | - lwM2MClient.getFwUpdate().sendLogs(handler, EXECUTE.name(), LOG_LW2M_ERROR, msgError); | |
583 | + lwM2MClient.getFwUpdate().sendLogs(this.handler, EXECUTE.name(), LOG_LW2M_ERROR, msgError); | |
560 | 584 | } |
561 | 585 | if (request.getPath().toString().equals(SW_INSTALL_ID) && lwM2MClient.getSwUpdate() != null) { |
562 | - lwM2MClient.getSwUpdate().sendLogs(handler, EXECUTE.name(), LOG_LW2M_ERROR, msgError); | |
586 | + lwM2MClient.getSwUpdate().sendLogs(this.handler, EXECUTE.name(), LOG_LW2M_ERROR, msgError); | |
563 | 587 | } |
564 | 588 | } |
565 | 589 | ... | ... |
... | ... | @@ -61,9 +61,12 @@ import java.util.Set; |
61 | 61 | import java.util.concurrent.ConcurrentHashMap; |
62 | 62 | |
63 | 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 | 66 | import static org.eclipse.leshan.core.attributes.Attribute.MAXIMUM_PERIOD; |
65 | 67 | import static org.eclipse.leshan.core.attributes.Attribute.MINIMUM_PERIOD; |
66 | 68 | import static org.eclipse.leshan.core.attributes.Attribute.OBJECT_VERSION; |
69 | +import static org.eclipse.leshan.core.attributes.Attribute.STEP; | |
67 | 70 | import static org.eclipse.leshan.core.model.ResourceModel.Type.BOOLEAN; |
68 | 71 | import static org.eclipse.leshan.core.model.ResourceModel.Type.FLOAT; |
69 | 72 | import static org.eclipse.leshan.core.model.ResourceModel.Type.INTEGER; |
... | ... | @@ -104,8 +107,7 @@ public class LwM2mTransportUtil { |
104 | 107 | |
105 | 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 | 111 | public static final String LOG_LW2M_INFO = "info"; |
110 | 112 | public static final String LOG_LW2M_ERROR = "error"; |
111 | 113 | public static final String LOG_LW2M_WARN = "warn"; |
... | ... | @@ -117,6 +119,23 @@ public class LwM2mTransportUtil { |
117 | 119 | public static final String CLIENT_NOT_AUTHORIZED = "Client not authorized"; |
118 | 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 | 139 | // FirmWare |
121 | 140 | public static final String FW_UPDATE = "Firmware update"; |
122 | 141 | public static final Integer FW_ID = 5; |
... | ... | @@ -182,20 +201,21 @@ public class LwM2mTransportUtil { |
182 | 201 | */ |
183 | 202 | READ(0, "Read"), |
184 | 203 | DISCOVER(1, "Discover"), |
185 | - DISCOVER_All(2, "DiscoverAll"), | |
204 | + DISCOVER_ALL(2, "DiscoverAll"), | |
186 | 205 | OBSERVE_READ_ALL(3, "ObserveReadAll"), |
187 | 206 | /** |
188 | 207 | * POST |
189 | 208 | */ |
190 | 209 | OBSERVE(4, "Observe"), |
191 | 210 | OBSERVE_CANCEL(5, "ObserveCancel"), |
192 | - EXECUTE(6, "Execute"), | |
211 | + OBSERVE_CANCEL_ALL(6, "ObserveCancelAll"), | |
212 | + EXECUTE(7, "Execute"), | |
193 | 213 | /** |
194 | 214 | * Replaces the Object Instance or the Resource(s) with the new value provided in the “Write” operation. (see |
195 | 215 | * section 5.3.3 of the LW M2M spec). |
196 | 216 | * if all resources are to be replaced |
197 | 217 | */ |
198 | - WRITE_REPLACE(7, "WriteReplace"), | |
218 | + WRITE_REPLACE(8, "WriteReplace"), | |
199 | 219 | /* |
200 | 220 | PUT |
201 | 221 | */ |
... | ... | @@ -204,18 +224,16 @@ public class LwM2mTransportUtil { |
204 | 224 | * 5.3.3 of the LW M2M spec). |
205 | 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 | 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 | 238 | public int code; |
221 | 239 | public String type; |
... | ... | @@ -817,26 +835,29 @@ public class LwM2mTransportUtil { |
817 | 835 | * Attribute pmax = new Attribute(MAXIMUM_PERIOD, "60"); |
818 | 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 | 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 | 844 | List<Attribute> attributeLists = new ArrayList<>(); |
827 | 845 | ObjectMapper oMapper = new ObjectMapper(); |
828 | 846 | Map<String, Object> map = oMapper.convertValue(params, ConcurrentHashMap.class); |
829 | 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 | 858 | return attributeLists.toArray(Attribute[]::new); |
837 | 859 | } |
838 | 860 | |
839 | - | |
840 | 861 | public static Set<String> convertJsonArrayToSet(JsonArray jsonArray) { |
841 | 862 | List<String> attributeListOld = new Gson().fromJson(jsonArray, new TypeToken<List<String>>() { |
842 | 863 | }.getType()); |
... | ... | @@ -863,4 +884,47 @@ public class LwM2mTransportUtil { |
863 | 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 | 31 | import org.eclipse.leshan.server.security.SecurityInfo; |
32 | 32 | import org.thingsboard.server.common.data.Device; |
33 | 33 | import org.thingsboard.server.common.data.DeviceProfile; |
34 | -import org.thingsboard.server.common.transport.auth.ValidateDeviceCredentialsResponse; | |
35 | 34 | import org.thingsboard.server.common.data.firmware.FirmwareType; |
35 | +import org.thingsboard.server.common.transport.auth.ValidateDeviceCredentialsResponse; | |
36 | 36 | import org.thingsboard.server.gen.transport.TransportProtos.SessionInfoProto; |
37 | 37 | import org.thingsboard.server.gen.transport.TransportProtos.TsKvProto; |
38 | 38 | import org.thingsboard.server.transport.lwm2m.server.DefaultLwM2MTransportMsgHandler; |
... | ... | @@ -117,7 +117,6 @@ public class LwM2mClient implements Cloneable { |
117 | 117 | this.pendingReadRequests = new CopyOnWriteArrayList<>(); |
118 | 118 | this.resources = new ConcurrentHashMap<>(); |
119 | 119 | this.profileId = profileId; |
120 | - this.sessionId = sessionId; | |
121 | 120 | this.init = false; |
122 | 121 | this.queuedRequests = new ConcurrentLinkedQueue<>(); |
123 | 122 | |
... | ... | @@ -194,17 +193,31 @@ public class LwM2mClient implements Cloneable { |
194 | 193 | public Object getResourceValue(String pathRezIdVer, String pathRezId) { |
195 | 194 | String pathRez = pathRezIdVer == null ? convertPathFromObjectIdToIdVer(pathRezId, this.registration) : pathRezIdVer; |
196 | 195 | if (this.resources.get(pathRez) != null) { |
197 | - return this.resources.get(pathRez).getLwM2mResource().isMultiInstances() ? | |
196 | + return this.resources.get(pathRez).getLwM2mResource().isMultiInstances() ? | |
198 | 197 | this.resources.get(pathRez).getLwM2mResource().getValues() : |
199 | 198 | this.resources.get(pathRez).getLwM2mResource().getValue(); |
200 | 199 | } |
201 | 200 | return null; |
202 | 201 | } |
203 | 202 | |
204 | - public Object getResourceName (String pathRezIdVer, String pathRezId) { | |
203 | + public Object getResourceNameByRezId(String pathRezIdVer, String pathRezId) { | |
205 | 204 | String pathRez = pathRezIdVer == null ? convertPathFromObjectIdToIdVer(pathRezId, this.registration) : pathRezIdVer; |
206 | 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 | 222 | return null; |
210 | 223 | } |
... | ... | @@ -225,11 +238,11 @@ public class LwM2mClient implements Cloneable { |
225 | 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 | 242 | StringBuilder builder = new StringBuilder(); |
230 | 243 | builder.append("LwM2mObject [id=").append(lwM2mObject.getId()).append(", instances={"); |
231 | 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 | 247 | int startInd = builder.lastIndexOf(", "); |
235 | 248 | if (startInd > 0) { |
... | ... | @@ -238,11 +251,12 @@ public class LwM2mClient implements Cloneable { |
238 | 251 | builder.append("}]"); |
239 | 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 | 256 | StringBuilder builder = new StringBuilder(); |
243 | 257 | builder.append("LwM2mObjectInstance [id=").append(objectInstance.getId()).append(", resources={"); |
244 | 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 | 261 | int startInd = builder.lastIndexOf(", "); |
248 | 262 | if (startInd > 0) { |
... | ... | @@ -252,12 +266,11 @@ public class LwM2mClient implements Cloneable { |
252 | 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 | 270 | if (!OPAQUE.equals(lwM2mResource.getType())) { |
257 | 271 | return lwM2mResource.isMultiInstances() ? ((LwM2mMultipleResource) lwM2mResource).toString() : |
258 | 272 | ((LwM2mSingleResource) lwM2mResource).toString(); |
259 | - } | |
260 | - else { | |
273 | + } else { | |
261 | 274 | return String.format("LwM2mSingleResource [id=%s, value=%s, type=%s]", lwM2mResource.getId(), |
262 | 275 | converter.convertValue(lwM2mResource.getValue(), |
263 | 276 | OPAQUE, STRING, new LwM2mPath(convertPathFromIdVerToObjectId(pathIdVer))), lwM2mResource.getType().name()); |
... | ... | @@ -275,7 +288,8 @@ public class LwM2mClient implements Cloneable { |
275 | 288 | resources.add(LwM2mSingleResource.newResource(resId, converter.convertValue(params, |
276 | 289 | equalsResourceTypeGetSimpleName(params), resourceModel.type, pathIds), resourceModel.type)); |
277 | 290 | |
278 | - }}); | |
291 | + } | |
292 | + }); | |
279 | 293 | return resources; |
280 | 294 | } |
281 | 295 | |
... | ... | @@ -291,7 +305,8 @@ public class LwM2mClient implements Cloneable { |
291 | 305 | resources.add(LwM2mSingleResource.newResource(resId, |
292 | 306 | converter.convertValue(value, equalsResourceTypeGetSimpleName(value), resourceModel.type, pathIds), resourceModel.type)); |
293 | 307 | |
294 | - }}); | |
308 | + } | |
309 | + }); | |
295 | 310 | return resources; |
296 | 311 | } |
297 | 312 | ... | ... |
... | ... | @@ -35,8 +35,6 @@ public interface LwM2mClientContext { |
35 | 35 | |
36 | 36 | LwM2mClient getClient(TransportProtos.SessionInfoProto sessionInfo); |
37 | 37 | |
38 | - LwM2mClient getClient(UUID sessionId); | |
39 | - | |
40 | 38 | LwM2mClient getOrRegister(Registration registration); |
41 | 39 | |
42 | 40 | LwM2mClient registerOrUpdate(Registration registration); | ... | ... |
... | ... | @@ -83,13 +83,11 @@ public class LwM2mClientContextImpl implements LwM2mClientContext { |
83 | 83 | |
84 | 84 | @Override |
85 | 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 | 93 | @Override | ... | ... |
... | ... | @@ -286,7 +286,7 @@ public class LwM2mFwSwUpdate { |
286 | 286 | Long updateResult = (Long) this.lwM2MClient.getResourceValue(null, this.pathResultId); |
287 | 287 | String value = FIRMWARE.equals(this.type) ? LwM2mTransportUtil.UpdateResultFw.fromUpdateResultFwByCode(updateResult.intValue()).type : |
288 | 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 | 290 | if (success) { |
291 | 291 | this.stateUpdate = FirmwareUpdateStatus.UPDATED.name(); |
292 | 292 | this.sendLogs(handler, EXECUTE.name(), LOG_LW2M_INFO, null); | ... | ... |
... | ... | @@ -15,94 +15,93 @@ |
15 | 15 | */ |
16 | 16 | package org.thingsboard.server.transport.lwm2m.server.client; |
17 | 17 | |
18 | +import com.google.gson.Gson; | |
18 | 19 | import com.google.gson.JsonObject; |
20 | +import com.google.gson.reflect.TypeToken; | |
19 | 21 | import lombok.Data; |
20 | 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 | 25 | import org.eclipse.leshan.server.registration.Registration; |
23 | 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 | 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 | 55 | import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.validPathIdVer; |
30 | 56 | |
31 | 57 | @Slf4j |
32 | 58 | @Data |
33 | 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 | 66 | private LwM2mTypeOper typeOper; |
67 | + private String key; | |
47 | 68 | private String targetIdVer; |
48 | - private String contentFormatName; | |
49 | - private long timeoutInMs; | |
50 | 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 | 72 | private String errorMsg; |
55 | 73 | private String valueMsg; |
56 | 74 | private String infoMsg; |
57 | 75 | private String responseCode; |
58 | 76 | |
59 | - public void setValidTypeOper(String typeOper) { | |
60 | - try { | |
61 | - this.typeOper = LwM2mTypeOper.fromLwLwM2mTypeOper(typeOper); | |
62 | - } catch (Exception e) { | |
63 | - this.errorMsg = this.methodKey + " - " + typeOper + " is not valid."; | |
64 | - } | |
77 | + public Lwm2mClientRpcRequest() { | |
65 | 78 | } |
66 | 79 | |
67 | - public void setValidContentFormatName(JsonObject rpcRequest) { | |
68 | - 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."; | |
73 | - } | |
74 | - } catch (Exception e) { | |
75 | - this.errorMsg = this.contentFormatNameKey + " - " + rpcRequest.get(this.contentFormatNameKey).getAsString() + " is not valid."; | |
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."; | |
76 | 89 | } |
77 | - } | |
78 | - | |
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); | |
86 | - 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."; | |
92 | - } | |
93 | - } | |
90 | + if (this.errorMsg == null && !bodyParams.equals("null")) { | |
91 | + this.bodyParams = bodyParams; | |
92 | + this.init(handler); | |
94 | 93 | } |
95 | 94 | } |
96 | 95 | |
97 | 96 | public TransportProtos.ToDeviceRpcResponseMsg getDeviceRpcResponseResultMsg() { |
98 | 97 | JsonObject payloadResp = new JsonObject(); |
99 | - payloadResp.addProperty(this.resultKey, this.responseCode); | |
98 | + payloadResp.addProperty(RESULT_KEY, this.responseCode); | |
100 | 99 | if (this.errorMsg != null) { |
101 | - payloadResp.addProperty(this.errorKey, this.errorMsg); | |
100 | + payloadResp.addProperty(ERROR_KEY, this.errorMsg); | |
102 | 101 | } else if (this.valueMsg != null) { |
103 | - payloadResp.addProperty(this.valueKey, this.valueMsg); | |
102 | + payloadResp.addProperty(VALUE_KEY, this.valueMsg); | |
104 | 103 | } else if (this.infoMsg != null) { |
105 | - payloadResp.addProperty(this.infoKey, this.infoMsg); | |
104 | + payloadResp.addProperty(INFO_KEY, this.infoMsg); | |
106 | 105 | } |
107 | 106 | return TransportProtos.ToDeviceRpcResponseMsg.newBuilder() |
108 | 107 | .setPayload(payloadResp.getAsJsonObject().toString()) |
... | ... | @@ -110,13 +109,171 @@ public class Lwm2mClientRpcRequest { |
110 | 109 | .build(); |
111 | 110 | } |
112 | 111 | |
113 | - @Override | |
114 | - public Object clone() { | |
112 | + private void init(DefaultLwM2MTransportMsgHandler handler) { | |
115 | 113 | try { |
116 | - return super.clone(); | |
117 | - } catch (CloneNotSupportedException e) { | |
118 | - log.error("", e); | |
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 | + } | |
158 | + } catch (Exception e) { | |
159 | + this.setErrorMsg(String.format("Bad format request. %s", e.getMessage())); | |
160 | + } | |
161 | + | |
162 | + } | |
163 | + | |
164 | + private void setValidTargetIdVerKey() { | |
165 | + String targetIdVerStr = this.getValueKeyFromBody(TARGET_ID_VER_KEY); | |
166 | + // targetIdVer without ver - ok | |
167 | + try { | |
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); | |
172 | + } | |
173 | + } catch (Exception e) { | |
174 | + if (this.targetIdVer == null) { | |
175 | + this.errorMsg = TARGET_ID_VER_KEY + " - " + targetIdVerStr + " is not valid."; | |
176 | + } | |
177 | + } | |
178 | + } | |
179 | + | |
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()) { | |
195 | + if (this.targetIdVer != null) { | |
196 | + Map<String, Object> paramsResourceId = this.convertParamsToResourceId((ConcurrentHashMap<String, Object>) params, handler); | |
197 | + if (paramsResourceId.size() > 0) { | |
198 | + this.setParams(paramsResourceId); | |
199 | + } | |
200 | + } | |
201 | + } else if (WRITE_ATTRIBUTES == this.getTypeOper()) { | |
202 | + this.setParams(params); | |
203 | + } | |
204 | + } | |
205 | + } | |
206 | + | |
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()); | |
231 | + } | |
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(" ", ""); | |
119 | 241 | } |
120 | 242 | return null; |
121 | 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; | |
278 | + } | |
122 | 279 | } | ... | ... |