Browse Source

Refactoring of the Device profile update

pull/4718/head
Andrii Shvaika 5 years ago
parent
commit
3012e5e545
  1. 14
      common/data/src/main/java/org/thingsboard/server/common/data/device/data/lwm2m/ObjectAttributes.java
  2. 51
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2MBootstrapSecurityStore.java
  3. 317
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/DefaultLwM2MUplinkMsgHandler.java
  4. 130
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mTransportRequest.java
  5. 167
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mTransportUtil.java
  6. 2
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mVersionedModelProvider.java
  7. 49
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClient.java
  8. 14
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClientContext.java
  9. 40
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClientContextImpl.java
  10. 113
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClientProfile.java
  11. 10
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClientRpcRequest.java
  12. 4
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/ParametersAnalyzeResult.java

14
common/data/src/main/java/org/thingsboard/server/common/data/device/data/lwm2m/ObjectAttributes.java

@ -15,17 +15,19 @@
*/ */
package org.thingsboard.server.common.data.device.data.lwm2m; package org.thingsboard.server.common.data.device.data.lwm2m;
import com.fasterxml.jackson.annotation.JsonInclude;
import lombok.Data; import lombok.Data;
@Data @Data
@JsonInclude(JsonInclude.Include.NON_NULL)
public class ObjectAttributes { public class ObjectAttributes {
private Integer dim; private Long dim;
private String ver; private String ver;
private Integer pmin; private Long pmin;
private Integer pmax; private Long pmax;
private Integer gt; private Double gt;
private Integer lt; private Double lt;
private Integer st; private Double st;
} }

51
common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2MBootstrapSecurityStore.java

@ -29,6 +29,8 @@ import org.eclipse.leshan.server.security.BootstrapSecurityStore;
import org.eclipse.leshan.server.security.SecurityInfo; import org.eclipse.leshan.server.security.SecurityInfo;
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.thingsboard.common.util.JacksonUtil;
import org.thingsboard.server.common.data.device.data.lwm2m.BootstrapConfiguration;
import org.thingsboard.server.gen.transport.TransportProtos; import org.thingsboard.server.gen.transport.TransportProtos;
import org.thingsboard.server.transport.lwm2m.secure.TbLwM2MSecurityInfo; import org.thingsboard.server.transport.lwm2m.secure.TbLwM2MSecurityInfo;
import org.thingsboard.server.transport.lwm2m.secure.LwM2mCredentialsSecurityInfoValidator; import org.thingsboard.server.transport.lwm2m.secure.LwM2mCredentialsSecurityInfoValidator;
@ -151,35 +153,30 @@ public class LwM2MBootstrapSecurityStore implements BootstrapSecurityStore {
} }
private LwM2MBootstrapConfig getParametersBootstrap(TbLwM2MSecurityInfo store) { private LwM2MBootstrapConfig getParametersBootstrap(TbLwM2MSecurityInfo store) {
try { LwM2MBootstrapConfig lwM2MBootstrapConfig = store.getBootstrapCredentialConfig();
LwM2MBootstrapConfig lwM2MBootstrapConfig = store.getBootstrapCredentialConfig(); if (lwM2MBootstrapConfig != null) {
if (lwM2MBootstrapConfig != null) { BootstrapConfiguration bootstrapObject = getBootstrapParametersFromThingsboard(store.getDeviceProfile());
ObjectMapper mapper = new ObjectMapper(); lwM2MBootstrapConfig.servers = JacksonUtil.fromString(JacksonUtil.toString(bootstrapObject.getServers()), LwM2MBootstrapServers.class);
JsonObject bootstrapObject = getBootstrapParametersFromThingsboard(store.getDeviceProfile()); LwM2MServerBootstrap profileServerBootstrap = JacksonUtil.fromString(JacksonUtil.toString(bootstrapObject.getBootstrapServer()), LwM2MServerBootstrap.class);
lwM2MBootstrapConfig.servers = mapper.readValue(bootstrapObject.get(SERVERS).toString(), LwM2MBootstrapServers.class); LwM2MServerBootstrap profileLwm2mServer = JacksonUtil.fromString(JacksonUtil.toString(bootstrapObject.getLwm2mServer()), LwM2MServerBootstrap.class);
LwM2MServerBootstrap profileServerBootstrap = mapper.readValue(bootstrapObject.get(BOOTSTRAP_SERVER).toString(), LwM2MServerBootstrap.class); UUID sessionUUiD = UUID.randomUUID();
LwM2MServerBootstrap profileLwm2mServer = mapper.readValue(bootstrapObject.get(LWM2M_SERVER).toString(), LwM2MServerBootstrap.class); TransportProtos.SessionInfoProto sessionInfo = helper.getValidateSessionInfo(store.getMsg(), sessionUUiD.getMostSignificantBits(), sessionUUiD.getLeastSignificantBits());
UUID sessionUUiD = UUID.randomUUID(); context.getTransportService().registerAsyncSession(sessionInfo, new LwM2mSessionMsgListener(null, sessionInfo));
TransportProtos.SessionInfoProto sessionInfo = helper.getValidateSessionInfo(store.getMsg(), sessionUUiD.getMostSignificantBits(), sessionUUiD.getLeastSignificantBits()); if (this.getValidatedSecurityMode(lwM2MBootstrapConfig.bootstrapServer, profileServerBootstrap, lwM2MBootstrapConfig.lwm2mServer, profileLwm2mServer)) {
context.getTransportService().registerAsyncSession(sessionInfo, new LwM2mSessionMsgListener(null, sessionInfo)); lwM2MBootstrapConfig.bootstrapServer = new LwM2MServerBootstrap(lwM2MBootstrapConfig.bootstrapServer, profileServerBootstrap);
if (this.getValidatedSecurityMode(lwM2MBootstrapConfig.bootstrapServer, profileServerBootstrap, lwM2MBootstrapConfig.lwm2mServer, profileLwm2mServer)) { lwM2MBootstrapConfig.lwm2mServer = new LwM2MServerBootstrap(lwM2MBootstrapConfig.lwm2mServer, profileLwm2mServer);
lwM2MBootstrapConfig.bootstrapServer = new LwM2MServerBootstrap(lwM2MBootstrapConfig.bootstrapServer, profileServerBootstrap); String logMsg = String.format("%s: getParametersBootstrap: %s Access connect client with bootstrap server.", LOG_LW2M_INFO, store.getEndpoint());
lwM2MBootstrapConfig.lwm2mServer = new LwM2MServerBootstrap(lwM2MBootstrapConfig.lwm2mServer, profileLwm2mServer); helper.sendParametersOnThingsboardTelemetry(helper.getKvStringtoThingsboard(LOG_LW2M_TELEMETRY, logMsg), sessionInfo);
String logMsg = String.format("%s: getParametersBootstrap: %s Access connect client with bootstrap server.", LOG_LW2M_INFO, store.getEndpoint()); return lwM2MBootstrapConfig;
helper.sendParametersOnThingsboardTelemetry(helper.getKvStringtoThingsboard(LOG_LW2M_TELEMETRY, logMsg), sessionInfo); } else {
return lwM2MBootstrapConfig; log.error(" [{}] Different values SecurityMode between of client and profile.", store.getEndpoint());
} else { log.error("{} getParametersBootstrap: [{}] Different values SecurityMode between of client and profile.", LOG_LW2M_ERROR, store.getEndpoint());
log.error(" [{}] Different values SecurityMode between of client and profile.", store.getEndpoint()); String logMsg = String.format("%s: getParametersBootstrap: %s Different values SecurityMode between of client and profile.", LOG_LW2M_ERROR, store.getEndpoint());
log.error("{} getParametersBootstrap: [{}] Different values SecurityMode between of client and profile.", LOG_LW2M_ERROR, store.getEndpoint()); helper.sendParametersOnThingsboardTelemetry(helper.getKvStringtoThingsboard(LOG_LW2M_TELEMETRY, logMsg), sessionInfo);
String logMsg = String.format("%s: getParametersBootstrap: %s Different values SecurityMode between of client and profile.", LOG_LW2M_ERROR, store.getEndpoint()); return null;
helper.sendParametersOnThingsboardTelemetry(helper.getKvStringtoThingsboard(LOG_LW2M_TELEMETRY, logMsg), sessionInfo);
return null;
}
} }
} catch (JsonProcessingException e) {
log.error("Unable to decode Json or Certificate for [{}] [{}]", store.getEndpoint(), e.getMessage());
return null;
} }
log.error("Unable to decode Json or Certificate for [{}]", store.getEndpoint()); log.error("Unable to decode Json or Certificate for [{}]", store.getEndpoint());
return null; return null;
} }

317
common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/DefaultLwM2MUplinkMsgHandler.java

@ -15,10 +15,8 @@
*/ */
package org.thingsboard.server.transport.lwm2m.server; package org.thingsboard.server.transport.lwm2m.server;
import com.fasterxml.jackson.core.type.TypeReference;
import com.google.gson.Gson; import com.google.gson.Gson;
import com.google.gson.GsonBuilder; import com.google.gson.GsonBuilder;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement; import com.google.gson.JsonElement;
import com.google.gson.JsonObject; import com.google.gson.JsonObject;
import com.google.gson.reflect.TypeToken; import com.google.gson.reflect.TypeToken;
@ -36,15 +34,16 @@ import org.eclipse.leshan.core.response.ReadResponse;
import org.eclipse.leshan.server.registration.Registration; import org.eclipse.leshan.server.registration.Registration;
import org.springframework.context.annotation.Lazy; import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.thingsboard.common.util.JacksonUtil;
import org.thingsboard.common.util.ThingsBoardExecutors; import org.thingsboard.common.util.ThingsBoardExecutors;
import org.thingsboard.server.cache.ota.OtaPackageDataCache; import org.thingsboard.server.cache.ota.OtaPackageDataCache;
import org.thingsboard.server.common.data.Device; import org.thingsboard.server.common.data.Device;
import org.thingsboard.server.common.data.DeviceProfile; import org.thingsboard.server.common.data.DeviceProfile;
import org.thingsboard.server.common.data.device.data.lwm2m.ObjectAttributes;
import org.thingsboard.server.common.data.device.profile.Lwm2mDeviceProfileTransportConfiguration;
import org.thingsboard.server.common.data.id.OtaPackageId;
import org.thingsboard.server.common.data.ota.OtaPackageKey; import org.thingsboard.server.common.data.ota.OtaPackageKey;
import org.thingsboard.server.common.data.ota.OtaPackageType; import org.thingsboard.server.common.data.ota.OtaPackageType;
import org.thingsboard.server.common.data.ota.OtaPackageUtil; import org.thingsboard.server.common.data.ota.OtaPackageUtil;
import org.thingsboard.server.common.data.id.OtaPackageId;
import org.thingsboard.server.common.transport.TransportService; import org.thingsboard.server.common.transport.TransportService;
import org.thingsboard.server.common.transport.TransportServiceCallback; import org.thingsboard.server.common.transport.TransportServiceCallback;
import org.thingsboard.server.common.transport.adaptor.AdaptorException; import org.thingsboard.server.common.transport.adaptor.AdaptorException;
@ -61,12 +60,11 @@ import org.thingsboard.server.transport.lwm2m.server.client.LwM2MClientState;
import org.thingsboard.server.transport.lwm2m.server.client.LwM2MClientStateException; import org.thingsboard.server.transport.lwm2m.server.client.LwM2MClientStateException;
import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient; import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient;
import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClientContext; import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClientContext;
import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClientProfile;
import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClientRpcRequest; import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClientRpcRequest;
import org.thingsboard.server.transport.lwm2m.server.client.LwM2mFwSwUpdate; import org.thingsboard.server.transport.lwm2m.server.client.LwM2mFwSwUpdate;
import org.thingsboard.server.transport.lwm2m.server.client.ParametersAnalyzeResult;
import org.thingsboard.server.transport.lwm2m.server.client.ResourceValue; import org.thingsboard.server.transport.lwm2m.server.client.ResourceValue;
import org.thingsboard.server.transport.lwm2m.server.client.ResultsAddKeyValueProto; import org.thingsboard.server.transport.lwm2m.server.client.ResultsAddKeyValueProto;
import org.thingsboard.server.transport.lwm2m.server.client.ResultsAnalyzerParameters;
import org.thingsboard.server.transport.lwm2m.server.store.TbLwM2MDtlsSessionStore; import org.thingsboard.server.transport.lwm2m.server.store.TbLwM2MDtlsSessionStore;
import org.thingsboard.server.transport.lwm2m.utils.LwM2mValueConverterImpl; import org.thingsboard.server.transport.lwm2m.utils.LwM2mValueConverterImpl;
@ -82,16 +80,14 @@ import java.util.Random;
import java.util.Set; import java.util.Set;
import java.util.UUID; import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.ExecutorService; import java.util.concurrent.ExecutorService;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import static org.eclipse.californium.core.coap.CoAP.ResponseCode.BAD_REQUEST; import static org.eclipse.californium.core.coap.CoAP.ResponseCode.BAD_REQUEST;
import static org.eclipse.leshan.core.attributes.Attribute.OBJECT_VERSION; import static org.thingsboard.server.common.data.lwm2m.LwM2mConstants.LWM2M_SEPARATOR_PATH;
import static org.thingsboard.server.common.data.ota.OtaPackageUpdateStatus.FAILED; import static org.thingsboard.server.common.data.ota.OtaPackageUpdateStatus.FAILED;
import static org.thingsboard.server.common.data.ota.OtaPackageUpdateStatus.INITIATED; import static org.thingsboard.server.common.data.ota.OtaPackageUpdateStatus.INITIATED;
import static org.thingsboard.server.common.data.lwm2m.LwM2mConstants.LWM2M_SEPARATOR_PATH;
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportServerHelper.getValueFromKvProto; import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportServerHelper.getValueFromKvProto;
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.DEVICE_ATTRIBUTES_REQUEST; import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.DEVICE_ATTRIBUTES_REQUEST;
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.FW_5_ID; import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.FW_5_ID;
@ -102,18 +98,15 @@ import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.L
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LOG_LW2M_TELEMETRY; import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LOG_LW2M_TELEMETRY;
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LOG_LW2M_VALUE; import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LOG_LW2M_VALUE;
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LOG_LW2M_WARN; import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LOG_LW2M_WARN;
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LwM2mTypeOper.DISCOVER;
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LwM2mTypeOper.OBSERVE; import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LwM2mTypeOper.OBSERVE;
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LwM2mTypeOper.OBSERVE_CANCEL; import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LwM2mTypeOper.OBSERVE_CANCEL;
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LwM2mTypeOper.OBSERVE_CANCEL_ALL; import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LwM2mTypeOper.OBSERVE_CANCEL_ALL;
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LwM2mTypeOper.READ; import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LwM2mTypeOper.READ;
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LwM2mTypeOper.WRITE_ATTRIBUTES;
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LwM2mTypeOper.WRITE_REPLACE; import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LwM2mTypeOper.WRITE_REPLACE;
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.SW_ID; import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.SW_ID;
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.convertJsonArrayToSet;
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.convertOtaUpdateValueToString; import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.convertOtaUpdateValueToString;
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.convertPathFromIdVerToObjectId;
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.convertPathFromObjectIdToIdVer; import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.convertPathFromObjectIdToIdVer;
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.fromVersionedIdToObjectId;
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.getAckCallback; import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.getAckCallback;
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.isFwSwWords; import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.isFwSwWords;
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.setValidTypeOper; import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.setValidTypeOper;
@ -467,7 +460,7 @@ public class DefaultLwM2MUplinkMsgHandler implements LwM2mUplinkMsgHandler {
try { try {
LwM2mClient client = clientContext.getClientBySessionInfo(sessionInfo); LwM2mClient client = clientContext.getClientBySessionInfo(sessionInfo);
Registration registration = client.getRegistration(); Registration registration = client.getRegistration();
if(registration != null) { if (registration != null) {
lwm2mClientRpcRequest = new LwM2mClientRpcRequest(lwM2mTypeOper, bodyParams, toDeviceRpcRequestMsg.getRequestId(), sessionInfo, registration, this); lwm2mClientRpcRequest = new LwM2mClientRpcRequest(lwM2mTypeOper, bodyParams, toDeviceRpcRequestMsg.getRequestId(), sessionInfo, registration, this);
if (lwm2mClientRpcRequest.getErrorMsg() != null) { if (lwm2mClientRpcRequest.getErrorMsg() != null) {
lwm2mClientRpcRequest.setResponseCode(BAD_REQUEST.name()); lwm2mClientRpcRequest.setResponseCode(BAD_REQUEST.name());
@ -595,20 +588,72 @@ public class DefaultLwM2MUplinkMsgHandler implements LwM2mUplinkMsgHandler {
* @param lwM2MClient - object with All parameters off client * @param lwM2MClient - object with All parameters off client
*/ */
private void initClientTelemetry(LwM2mClient lwM2MClient) { private void initClientTelemetry(LwM2mClient lwM2MClient) {
LwM2mClientProfile profile = clientContext.getProfile(lwM2MClient.getProfileId()); Lwm2mDeviceProfileTransportConfiguration profile = clientContext.getProfile(lwM2MClient.getProfileId());
Set<String> supportedObjects = clientContext.getSupportedIdVerInClient(lwM2MClient); Set<String> supportedObjects = clientContext.getSupportedIdVerInClient(lwM2MClient);
if (supportedObjects != null && supportedObjects.size() > 0) { if (supportedObjects != null && supportedObjects.size() > 0) {
if (LwM2mTransportUtil.LwM2MClientStrategy.CLIENT_STRATEGY_2.code == profile.getClientStrategy()) { if (LwM2mTransportUtil.LwM2MClientStrategy.CLIENT_STRATEGY_2.code == profile.getClientLwM2mSettings().getClientOnlyObserveAfterConnect()) {
// #2 // #2
lwM2MClient.getPendingReadRequests().addAll(supportedObjects); lwM2MClient.getPendingReadRequests().addAll(supportedObjects);
supportedObjects.forEach(path -> lwM2mTransportRequest.sendAllRequest(lwM2MClient, path, READ, supportedObjects.forEach(path -> lwM2mTransportRequest.sendAllRequest(lwM2MClient, path, READ,
null, this.config.getTimeout(), null)); null, this.config.getTimeout(), null));
} }
// #1 // #1
this.initReadAttrTelemetryObserveToClient(lwM2MClient, profile, READ, supportedObjects); this.sendReadRequests(lwM2MClient, profile, supportedObjects);
this.initReadAttrTelemetryObserveToClient(lwM2MClient, profile, OBSERVE, supportedObjects); this.sendObserveRequests(lwM2MClient, profile, supportedObjects);
this.initReadAttrTelemetryObserveToClient(lwM2MClient, profile, WRITE_ATTRIBUTES, supportedObjects); this.sendWriteAttributeRequests(lwM2MClient, profile, supportedObjects);
this.initReadAttrTelemetryObserveToClient(lwM2MClient, profile, DISCOVER, supportedObjects); // Removed. Used only for debug.
// this.sendDiscoverRequests(lwM2MClient, profile, supportedObjects);
}
}
private void sendReadRequests(LwM2mClient lwM2MClient, Lwm2mDeviceProfileTransportConfiguration profile, Set<String> supportedObjects) {
Set<String> targetIds = new HashSet<>(profile.getObserveAttr().getAttribute());
targetIds.addAll(profile.getObserveAttr().getTelemetry());
targetIds = targetIds.stream().filter(target -> isSupportedTargetId(supportedObjects, target)).collect(Collectors.toSet());
lwM2MClient.getPendingReadRequests().addAll(targetIds);
targetIds.forEach(targetId -> lwM2mTransportRequest.sendReadRequest(lwM2MClient, targetId, this.config.getTimeout()));
}
private void sendObserveRequests(LwM2mClient lwM2MClient, Lwm2mDeviceProfileTransportConfiguration profile, Set<String> supportedObjects) {
Set<String> targetIds = profile.getObserveAttr().getObserve();
targetIds = targetIds.stream().filter(target -> isSupportedTargetId(supportedObjects, target)).collect(Collectors.toSet());
// TODO: why do we need to put observe into pending read requests?
// lwM2MClient.getPendingReadRequests().addAll(targetIds);
targetIds.forEach(targetId -> lwM2mTransportRequest.sendObserveRequest(lwM2MClient, targetId, this.config.getTimeout()));
}
private void sendWriteAttributeRequests(LwM2mClient lwM2MClient, Lwm2mDeviceProfileTransportConfiguration profile, Set<String> supportedObjects) {
Map<String, ObjectAttributes> attributesMap = profile.getObserveAttr().getAttributeLwm2m();
attributesMap = attributesMap.entrySet().stream().filter(target -> isSupportedTargetId(supportedObjects, target.getKey())).collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
// TODO: why do we need to put observe into pending read requests?
// lwM2MClient.getPendingReadRequests().addAll(targetIds);
attributesMap.forEach((targetId, params) -> lwM2mTransportRequest.sendWriteAttributesRequest(lwM2MClient, targetId, params, this.config.getTimeout()));
}
private void sendDiscoverRequests(LwM2mClient lwM2MClient, Lwm2mDeviceProfileTransportConfiguration profile, Set<String> supportedObjects) {
Set<String> targetIds = profile.getObserveAttr().getAttributeLwm2m().keySet();
targetIds = targetIds.stream().filter(target -> isSupportedTargetId(supportedObjects, target)).collect(Collectors.toSet());
// TODO: why do we need to put observe into pending read requests?
// lwM2MClient.getPendingReadRequests().addAll(targetIds);
targetIds.forEach(targetId -> lwM2mTransportRequest.sendDiscoverRequest(lwM2MClient, targetId, this.config.getTimeout()));
}
private void sendRequestsToClient(LwM2mClient lwM2MClient, LwM2mTypeOper operationType, Set<String> supportedObjectIds, Set<String> desiredObjectIds, ConcurrentHashMap<String, ObjectAttributes> params) {
if (desiredObjectIds != null && !desiredObjectIds.isEmpty()) {
Set<String> targetObjectIds = desiredObjectIds.stream().filter(target -> isSupportedTargetId(supportedObjectIds, target)
).collect(Collectors.toUnmodifiableSet());
if (!targetObjectIds.isEmpty()) {
//TODO: remove this side effect?
lwM2MClient.getPendingReadRequests().addAll(targetObjectIds);
targetObjectIds.forEach(target -> {
Object additionalParams = params != null ? params.get(target) : null;
lwM2mTransportRequest.sendAllRequest(lwM2MClient, target, operationType, additionalParams, this.config.getTimeout(), null);
});
if (OBSERVE.equals(operationType)) {
lwM2MClient.initReadValue(this, null);
}
}
} }
} }
@ -618,7 +663,7 @@ public class DefaultLwM2MUplinkMsgHandler implements LwM2mUplinkMsgHandler {
* @param pathIdVer - * @param pathIdVer -
*/ */
private void updateObjectResourceValue(Registration registration, LwM2mObject lwM2mObject, String pathIdVer) { private void updateObjectResourceValue(Registration registration, LwM2mObject lwM2mObject, String pathIdVer) {
LwM2mPath pathIds = new LwM2mPath(convertPathFromIdVerToObjectId(pathIdVer)); LwM2mPath pathIds = new LwM2mPath(fromVersionedIdToObjectId(pathIdVer));
lwM2mObject.getInstances().forEach((instanceId, instance) -> { lwM2mObject.getInstances().forEach((instanceId, instance) -> {
String pathInstance = pathIds.toString() + "/" + instanceId; String pathInstance = pathIds.toString() + "/" + instanceId;
this.updateObjectInstanceResourceValue(registration, instance, pathInstance); this.updateObjectInstanceResourceValue(registration, instance, pathInstance);
@ -631,7 +676,7 @@ public class DefaultLwM2MUplinkMsgHandler implements LwM2mUplinkMsgHandler {
* @param pathIdVer - * @param pathIdVer -
*/ */
private void updateObjectInstanceResourceValue(Registration registration, LwM2mObjectInstance lwM2mObjectInstance, String pathIdVer) { private void updateObjectInstanceResourceValue(Registration registration, LwM2mObjectInstance lwM2mObjectInstance, String pathIdVer) {
LwM2mPath pathIds = new LwM2mPath(convertPathFromIdVerToObjectId(pathIdVer)); LwM2mPath pathIds = new LwM2mPath(fromVersionedIdToObjectId(pathIdVer));
lwM2mObjectInstance.getResources().forEach((resourceId, resource) -> { lwM2mObjectInstance.getResources().forEach((resourceId, resource) -> {
String pathRez = pathIds.toString() + "/" + resourceId; String pathRez = pathIds.toString() + "/" + resourceId;
this.updateResourcesValue(registration, resource, pathRez); this.updateResourcesValue(registration, resource, pathRez);
@ -668,9 +713,7 @@ public class DefaultLwM2MUplinkMsgHandler implements LwM2mUplinkMsgHandler {
log.warn("93) path: [{}] value: [{}]", path, lwM2mResource.getValue()); log.warn("93) path: [{}] value: [{}]", path, lwM2mResource.getValue());
fwUpdate.updateStateOta(this, lwM2mTransportRequest, registration, path, ((Long) lwM2mResource.getValue()).intValue()); fwUpdate.updateStateOta(this, lwM2mTransportRequest, registration, path, ((Long) lwM2mResource.getValue()).intValue());
} }
Set<String> paths = new HashSet<>(); this.updateAttrTelemetry(registration, Collections.singleton(path));
paths.add(path);
this.updateAttrTelemetry(registration, paths);
} else { } else {
log.error("Fail update Resource [{}]", lwM2mResource); log.error("Fail update Resource [{}]", lwM2mResource);
} }
@ -703,47 +746,6 @@ public class DefaultLwM2MUplinkMsgHandler implements LwM2mUplinkMsgHandler {
} }
} }
private void initReadAttrTelemetryObserveToClient(LwM2mClient lwM2MClient, LwM2mClientProfile lwM2MClientProfile, LwM2mTypeOper typeOper, Set<String> supportedObjects) {
Set<String> result = null;
ConcurrentHashMap<String, Object> params = null;
if (READ.equals(typeOper)) {
result = JacksonUtil.fromString(lwM2MClientProfile.getPostAttributeProfile().toString(),
new TypeReference<>() {
});
result.addAll(JacksonUtil.fromString(lwM2MClientProfile.getPostTelemetryProfile().toString(),
new TypeReference<>() {
}));
} else if (OBSERVE.equals(typeOper)) {
result = JacksonUtil.fromString(lwM2MClientProfile.getPostObserveProfile().toString(),
new TypeReference<>() {
});
} else if (DISCOVER.equals(typeOper)) {
result = this.getPathForWriteAttributes(lwM2MClientProfile.getPostAttributeLwm2mProfile()).keySet();
} else if (WRITE_ATTRIBUTES.equals(typeOper)) {
params = this.getPathForWriteAttributes(lwM2MClientProfile.getPostAttributeLwm2mProfile());
result = params.keySet();
}
sendRequestsToClient(lwM2MClient, typeOper, supportedObjects, result, params);
}
private void sendRequestsToClient(LwM2mClient lwM2MClient, LwM2mTypeOper operationType, Set<String> supportedObjectIds, Set<String> desiredObjectIds, ConcurrentHashMap<String, Object> params) {
if (desiredObjectIds != null && !desiredObjectIds.isEmpty()) {
Set<String> targetObjectIds = desiredObjectIds.stream().filter(target -> isSupportedTargetId(supportedObjectIds, target)
).collect(Collectors.toUnmodifiableSet());
if (!targetObjectIds.isEmpty()) {
//TODO: remove this side effect?
lwM2MClient.getPendingReadRequests().addAll(targetObjectIds);
targetObjectIds.forEach(target -> {
Object additionalParams = params != null ? params.get(target) : null;
lwM2mTransportRequest.sendAllRequest(lwM2MClient, target, operationType, additionalParams, this.config.getTimeout(), null);
});
if (OBSERVE.equals(operationType)) {
lwM2MClient.initReadValue(this, null);
}
}
}
}
private boolean isSupportedTargetId(Set<String> supportedIds, String targetId) { private boolean isSupportedTargetId(Set<String> supportedIds, String targetId) {
String[] targetIdParts = targetId.split(LWM2M_SEPARATOR_PATH); String[] targetIdParts = targetId.split(LWM2M_SEPARATOR_PATH);
if (targetIdParts.length <= 1) { if (targetIdParts.length <= 1) {
@ -781,20 +783,20 @@ public class DefaultLwM2MUplinkMsgHandler implements LwM2mUplinkMsgHandler {
private ResultsAddKeyValueProto getParametersFromProfile(Registration registration, Set<String> path) { private ResultsAddKeyValueProto getParametersFromProfile(Registration registration, Set<String> path) {
if (path != null && path.size() > 0) { if (path != null && path.size() > 0) {
ResultsAddKeyValueProto results = new ResultsAddKeyValueProto(); ResultsAddKeyValueProto results = new ResultsAddKeyValueProto();
LwM2mClientProfile lwM2MClientProfile = clientContext.getProfile(registration); var profile = clientContext.getProfile(registration);
List<TransportProtos.KeyValueProto> resultAttributes = new ArrayList<>(); List<TransportProtos.KeyValueProto> resultAttributes = new ArrayList<>();
lwM2MClientProfile.getPostAttributeProfile().forEach(pathIdVer -> { profile.getObserveAttr().getAttribute().forEach(pathIdVer -> {
if (path.contains(pathIdVer.getAsString())) { if (path.contains(pathIdVer)) {
TransportProtos.KeyValueProto kvAttr = this.getKvToThingsboard(pathIdVer.getAsString(), registration); TransportProtos.KeyValueProto kvAttr = this.getKvToThingsboard(pathIdVer, registration);
if (kvAttr != null) { if (kvAttr != null) {
resultAttributes.add(kvAttr); resultAttributes.add(kvAttr);
} }
} }
}); });
List<TransportProtos.KeyValueProto> resultTelemetries = new ArrayList<>(); List<TransportProtos.KeyValueProto> resultTelemetries = new ArrayList<>();
lwM2MClientProfile.getPostTelemetryProfile().forEach(pathIdVer -> { profile.getObserveAttr().getTelemetry().forEach(pathIdVer -> {
if (path.contains(pathIdVer.getAsString())) { if (path.contains(pathIdVer)) {
TransportProtos.KeyValueProto kvAttr = this.getKvToThingsboard(pathIdVer.getAsString(), registration); TransportProtos.KeyValueProto kvAttr = this.getKvToThingsboard(pathIdVer, registration);
if (kvAttr != null) { if (kvAttr != null) {
resultTelemetries.add(kvAttr); resultTelemetries.add(kvAttr);
} }
@ -813,12 +815,12 @@ public class DefaultLwM2MUplinkMsgHandler implements LwM2mUplinkMsgHandler {
private TransportProtos.KeyValueProto getKvToThingsboard(String pathIdVer, Registration registration) { private TransportProtos.KeyValueProto getKvToThingsboard(String pathIdVer, Registration registration) {
LwM2mClient lwM2MClient = this.clientContext.getClientByEndpoint(registration.getEndpoint()); LwM2mClient lwM2MClient = this.clientContext.getClientByEndpoint(registration.getEndpoint());
JsonObject names = clientContext.getProfiles().get(lwM2MClient.getProfileId()).getPostKeyNameProfile(); Map<String, String> names = clientContext.getProfile(lwM2MClient.getProfileId()).getObserveAttr().getKeyName();
if (names != null && names.has(pathIdVer)) { if (names != null && names.containsKey(pathIdVer)) {
String resourceName = names.get(pathIdVer).getAsString(); String resourceName = names.get(pathIdVer);
if (resourceName != null && !resourceName.isEmpty()) { if (resourceName != null && !resourceName.isEmpty()) {
try { try {
LwM2mResource resourceValue = lwM2MClient != null ? getResourceValueFromLwM2MClient(lwM2MClient, pathIdVer) : null; LwM2mResource resourceValue = getResourceValueFromLwM2MClient(lwM2MClient, pathIdVer);
if (resourceValue != null) { if (resourceValue != null) {
ResourceModel.Type currentType = resourceValue.getType(); ResourceModel.Type currentType = resourceValue.getType();
ResourceModel.Type expectedType = this.helper.getResourceModelTypeEqualsKvProtoValueType(currentType, pathIdVer); ResourceModel.Type expectedType = this.helper.getResourceModelTypeEqualsKvProtoValueType(currentType, pathIdVer);
@ -830,14 +832,14 @@ public class DefaultLwM2MUplinkMsgHandler implements LwM2mUplinkMsgHandler {
ResourceModel.Type finalCurrentType = currentType; ResourceModel.Type finalCurrentType = currentType;
resourceValue.getInstances().forEach((k, v) -> { resourceValue.getInstances().forEach((k, v) -> {
Object val = this.converter.convertValue(v, finalCurrentType, expectedType, Object val = this.converter.convertValue(v, finalCurrentType, expectedType,
new LwM2mPath(convertPathFromIdVerToObjectId(pathIdVer))); new LwM2mPath(fromVersionedIdToObjectId(pathIdVer)));
JsonElement element = gson.toJsonTree(val, val.getClass()); JsonElement element = gson.toJsonTree(val, val.getClass());
((JsonObject) finalvalueKvProto).add(String.valueOf(k), element); ((JsonObject) finalvalueKvProto).add(String.valueOf(k), element);
}); });
valueKvProto = gson.toJson(valueKvProto); valueKvProto = gson.toJson(valueKvProto);
} else { } else {
valueKvProto = this.converter.convertValue(resourceValue.getValue(), currentType, expectedType, valueKvProto = this.converter.convertValue(resourceValue.getValue(), currentType, expectedType,
new LwM2mPath(convertPathFromIdVerToObjectId(pathIdVer))); new LwM2mPath(fromVersionedIdToObjectId(pathIdVer)));
} }
LwM2mOtaConvert lwM2mOtaConvert = convertOtaUpdateValueToString(pathIdVer, valueKvProto, currentType); LwM2mOtaConvert lwM2mOtaConvert = convertOtaUpdateValueToString(pathIdVer, valueKvProto, currentType);
valueKvProto = lwM2mOtaConvert.getValue(); valueKvProto = lwM2mOtaConvert.getValue();
@ -864,7 +866,7 @@ public class DefaultLwM2MUplinkMsgHandler implements LwM2mUplinkMsgHandler {
ResourceModel.Type currentType = resourceValue.getType(); ResourceModel.Type currentType = resourceValue.getType();
ResourceModel.Type expectedType = this.helper.getResourceModelTypeEqualsKvProtoValueType(currentType, pathIdVer); ResourceModel.Type expectedType = this.helper.getResourceModelTypeEqualsKvProtoValueType(currentType, pathIdVer);
return this.converter.convertValue(resourceValue.getValue(), currentType, expectedType, return this.converter.convertValue(resourceValue.getValue(), currentType, expectedType,
new LwM2mPath(convertPathFromIdVerToObjectId(pathIdVer))); new LwM2mPath(fromVersionedIdToObjectId(pathIdVer)));
} else { } else {
return null; return null;
} }
@ -879,7 +881,7 @@ public class DefaultLwM2MUplinkMsgHandler implements LwM2mUplinkMsgHandler {
LwM2mResource lwm2mResourceValue = null; LwM2mResource lwm2mResourceValue = null;
ResourceValue resourceValue = lwM2MClient.getResources().get(path); ResourceValue resourceValue = lwM2MClient.getResources().get(path);
if (resourceValue != null) { if (resourceValue != null) {
if (new LwM2mPath(convertPathFromIdVerToObjectId(path)).isResource()) { if (new LwM2mPath(fromVersionedIdToObjectId(path)).isResource()) {
lwm2mResourceValue = lwM2MClient.getResources().get(path).getLwM2mResource(); lwm2mResourceValue = lwM2MClient.getResources().get(path).getLwM2mResource();
} }
} }
@ -929,53 +931,42 @@ public class DefaultLwM2MUplinkMsgHandler implements LwM2mUplinkMsgHandler {
* @param clients - * @param clients -
* @param deviceProfile - * @param deviceProfile -
*/ */
//TODO: review and optimize the logic to minimize number of the requests to device.
private void onDeviceProfileUpdate(List<LwM2mClient> clients, DeviceProfile deviceProfile) { private void onDeviceProfileUpdate(List<LwM2mClient> clients, DeviceProfile deviceProfile) {
LwM2mClientProfile lwM2MClientProfileOld = clientContext.getProfiles().get(deviceProfile.getUuidId()).clone(); var oldProfile = clientContext.getProfile(deviceProfile.getUuidId());
if (clientContext.profileUpdate(deviceProfile) != null) { if (clientContext.profileUpdate(deviceProfile) != null) {
// #1 // #1
JsonArray attributeOld = lwM2MClientProfileOld.getPostAttributeProfile(); Set<String> attributeSetOld = oldProfile.getObserveAttr().getAttribute();
Set<String> attributeSetOld = convertJsonArrayToSet(attributeOld); Set<String> telemetrySetOld = oldProfile.getObserveAttr().getTelemetry();
JsonArray telemetryOld = lwM2MClientProfileOld.getPostTelemetryProfile(); Set<String> observeOld = oldProfile.getObserveAttr().getObserve();
Set<String> telemetrySetOld = convertJsonArrayToSet(telemetryOld); Map<String, String> keyNameOld = oldProfile.getObserveAttr().getKeyName();
JsonArray observeOld = lwM2MClientProfileOld.getPostObserveProfile(); Map<String, ObjectAttributes> attributeLwm2mOld = oldProfile.getObserveAttr().getAttributeLwm2m();
JsonObject keyNameOld = lwM2MClientProfileOld.getPostKeyNameProfile();
JsonObject attributeLwm2mOld = lwM2MClientProfileOld.getPostAttributeLwm2mProfile(); var newProfile = clientContext.getProfile(deviceProfile.getUuidId());
Set<String> attributeSetNew = newProfile.getObserveAttr().getAttribute();
LwM2mClientProfile lwM2MClientProfileNew = clientContext.getProfiles().get(deviceProfile.getUuidId()).clone(); Set<String> telemetrySetNew = newProfile.getObserveAttr().getTelemetry();
JsonArray attributeNew = lwM2MClientProfileNew.getPostAttributeProfile(); Set<String> observeNew = newProfile.getObserveAttr().getObserve();
Set<String> attributeSetNew = convertJsonArrayToSet(attributeNew); Map<String, String> keyNameNew = newProfile.getObserveAttr().getKeyName();
JsonArray telemetryNew = lwM2MClientProfileNew.getPostTelemetryProfile(); Map<String, ObjectAttributes> attributeLwm2mNew = newProfile.getObserveAttr().getAttributeLwm2m();
Set<String> telemetrySetNew = convertJsonArrayToSet(telemetryNew);
JsonArray observeNew = lwM2MClientProfileNew.getPostObserveProfile();
JsonObject keyNameNew = lwM2MClientProfileNew.getPostKeyNameProfile();
JsonObject attributeLwm2mNew = lwM2MClientProfileNew.getPostAttributeLwm2mProfile();
// #3 // #3
ResultsAnalyzerParameters sendAttrToThingsboard = new ResultsAnalyzerParameters(); ParametersAnalyzeResult diff = new ParametersAnalyzeResult();
// #3.1 // #3.1
if (!attributeOld.equals(attributeNew)) { if (!attributeSetOld.equals(attributeSetNew)) {
ResultsAnalyzerParameters postAttributeAnalyzer = this.getAnalyzerParameters(new Gson().fromJson(attributeOld, ParametersAnalyzeResult postAttributeAnalyzer = this.getAnalyzerParameters(attributeSetOld, attributeSetNew);
new TypeToken<Set<String>>() { diff.getPathPostParametersAdd().addAll(postAttributeAnalyzer.getPathPostParametersAdd());
}.getType()), attributeSetNew); diff.getPathPostParametersDel().addAll(postAttributeAnalyzer.getPathPostParametersDel());
sendAttrToThingsboard.getPathPostParametersAdd().addAll(postAttributeAnalyzer.getPathPostParametersAdd());
sendAttrToThingsboard.getPathPostParametersDel().addAll(postAttributeAnalyzer.getPathPostParametersDel());
} }
// #3.2 // #3.2
if (!telemetryOld.equals(telemetryNew)) { if (!telemetrySetOld.equals(telemetrySetNew)) {
ResultsAnalyzerParameters postTelemetryAnalyzer = this.getAnalyzerParameters(new Gson().fromJson(telemetryOld, ParametersAnalyzeResult postTelemetryAnalyzer = this.getAnalyzerParameters(telemetrySetOld, telemetrySetNew);
new TypeToken<Set<String>>() { diff.getPathPostParametersAdd().addAll(postTelemetryAnalyzer.getPathPostParametersAdd());
}.getType()), telemetrySetNew); diff.getPathPostParametersDel().addAll(postTelemetryAnalyzer.getPathPostParametersDel());
sendAttrToThingsboard.getPathPostParametersAdd().addAll(postTelemetryAnalyzer.getPathPostParametersAdd());
sendAttrToThingsboard.getPathPostParametersDel().addAll(postTelemetryAnalyzer.getPathPostParametersDel());
} }
// #3.3 // #3.3
if (!keyNameOld.equals(keyNameNew)) { if (!keyNameOld.equals(keyNameNew)) {
ResultsAnalyzerParameters keyNameChange = this.getAnalyzerKeyName(new Gson().fromJson(keyNameOld.toString(), ParametersAnalyzeResult keyNameChange = this.getAnalyzerKeyName(keyNameOld, keyNameNew);
new TypeToken<ConcurrentHashMap<String, String>>() { diff.getPathPostParametersAdd().addAll(keyNameChange.getPathPostParametersAdd());
}.getType()),
new Gson().fromJson(keyNameNew.toString(), new TypeToken<ConcurrentHashMap<String, String>>() {
}.getType()));
sendAttrToThingsboard.getPathPostParametersAdd().addAll(keyNameChange.getPathPostParametersAdd());
} }
// #3.4, #6 // #3.4, #6
@ -984,32 +975,28 @@ public class DefaultLwM2MUplinkMsgHandler implements LwM2mUplinkMsgHandler {
} }
// #4.1 add // #4.1 add
if (sendAttrToThingsboard.getPathPostParametersAdd().size() > 0) { if (diff.getPathPostParametersAdd().size() > 0) {
// update value in Resources // update value in Resources
clients.forEach(client -> { clients.forEach(client -> {
this.readObserveFromProfile(client, sendAttrToThingsboard.getPathPostParametersAdd(), READ); this.readObserveFromProfile(client, diff.getPathPostParametersAdd(), READ);
}); });
} }
// #4.2 del // #4.2 del
if (sendAttrToThingsboard.getPathPostParametersDel().size() > 0) { if (diff.getPathPostParametersDel().size() > 0) {
ResultsAnalyzerParameters sendAttrToThingsboardDel = this.getAnalyzerParameters(sendAttrToThingsboard.getPathPostParametersAdd(), sendAttrToThingsboard.getPathPostParametersDel()); ParametersAnalyzeResult sendAttrToThingsboardDel = this.getAnalyzerParameters(diff.getPathPostParametersAdd(), diff.getPathPostParametersDel());
sendAttrToThingsboard.setPathPostParametersDel(sendAttrToThingsboardDel.getPathPostParametersDel()); diff.setPathPostParametersDel(sendAttrToThingsboardDel.getPathPostParametersDel());
} }
// #5.1 // #5.1
if (!observeOld.equals(observeNew)) { if (!observeOld.equals(observeNew)) {
Set<String> observeSetOld = new Gson().fromJson(observeOld, new TypeToken<Set<String>>() {
}.getType());
Set<String> observeSetNew = new Gson().fromJson(observeNew, new TypeToken<Set<String>>() {
}.getType());
//#5.2 add //#5.2 add
// path Attr/Telemetry includes newObserve // path Attr/Telemetry includes newObserve
attributeSetOld.addAll(telemetrySetOld); attributeSetOld.addAll(telemetrySetOld);
ResultsAnalyzerParameters sendObserveToClientOld = this.getAnalyzerParametersIn(attributeSetOld, observeSetOld); // add observe ParametersAnalyzeResult sendObserveToClientOld = this.getAnalyzerParametersIn(attributeSetOld, observeOld); // add observe
attributeSetNew.addAll(telemetrySetNew); attributeSetNew.addAll(telemetrySetNew);
ResultsAnalyzerParameters sendObserveToClientNew = this.getAnalyzerParametersIn(attributeSetNew, observeSetNew); // add observe ParametersAnalyzeResult sendObserveToClientNew = this.getAnalyzerParametersIn(attributeSetNew, observeNew); // add observe
// does not include oldObserve // does not include oldObserve
ResultsAnalyzerParameters postObserveAnalyzer = this.getAnalyzerParameters(sendObserveToClientOld.getPathPostParametersAdd(), sendObserveToClientNew.getPathPostParametersAdd()); ParametersAnalyzeResult postObserveAnalyzer = this.getAnalyzerParameters(sendObserveToClientOld.getPathPostParametersAdd(), sendObserveToClientNew.getPathPostParametersAdd());
// send Request observe to Client // send Request observe to Client
clients.forEach(client -> { clients.forEach(client -> {
Registration registration = client.getRegistration(); Registration registration = client.getRegistration();
@ -1033,10 +1020,10 @@ public class DefaultLwM2MUplinkMsgHandler implements LwM2mUplinkMsgHandler {
* @param parametersNew - * @param parametersNew -
* @return ResultsAnalyzerParameters: add && new * @return ResultsAnalyzerParameters: add && new
*/ */
private ResultsAnalyzerParameters getAnalyzerParameters(Set<String> parametersOld, Set<String> parametersNew) { private ParametersAnalyzeResult getAnalyzerParameters(Set<String> parametersOld, Set<String> parametersNew) {
ResultsAnalyzerParameters analyzerParameters = null; ParametersAnalyzeResult analyzerParameters = null;
if (!parametersOld.equals(parametersNew)) { if (!parametersOld.equals(parametersNew)) {
analyzerParameters = new ResultsAnalyzerParameters(); analyzerParameters = new ParametersAnalyzeResult();
analyzerParameters.setPathPostParametersAdd(parametersNew analyzerParameters.setPathPostParametersAdd(parametersNew
.stream().filter(p -> !parametersOld.contains(p)).collect(Collectors.toSet())); .stream().filter(p -> !parametersOld.contains(p)).collect(Collectors.toSet()));
analyzerParameters.setPathPostParametersDel(parametersOld analyzerParameters.setPathPostParametersDel(parametersOld
@ -1045,8 +1032,8 @@ public class DefaultLwM2MUplinkMsgHandler implements LwM2mUplinkMsgHandler {
return analyzerParameters; return analyzerParameters;
} }
private ResultsAnalyzerParameters getAnalyzerParametersIn(Set<String> parametersObserve, Set<String> parameters) { private ParametersAnalyzeResult getAnalyzerParametersIn(Set<String> parametersObserve, Set<String> parameters) {
ResultsAnalyzerParameters analyzerParameters = new ResultsAnalyzerParameters(); ParametersAnalyzeResult analyzerParameters = new ParametersAnalyzeResult();
analyzerParameters.setPathPostParametersAdd(parametersObserve analyzerParameters.setPathPostParametersAdd(parametersObserve
.stream().filter(parameters::contains).collect(Collectors.toSet())); .stream().filter(parameters::contains).collect(Collectors.toSet()));
return analyzerParameters; return analyzerParameters;
@ -1060,7 +1047,7 @@ public class DefaultLwM2MUplinkMsgHandler implements LwM2mUplinkMsgHandler {
*/ */
private void readObserveFromProfile(LwM2mClient client, Set<String> targets, LwM2mTypeOper typeOper) { private void readObserveFromProfile(LwM2mClient client, Set<String> targets, LwM2mTypeOper typeOper) {
targets.forEach(target -> { targets.forEach(target -> {
LwM2mPath pathIds = new LwM2mPath(convertPathFromIdVerToObjectId(target)); LwM2mPath pathIds = new LwM2mPath(fromVersionedIdToObjectId(target));
if (pathIds.isResource()) { if (pathIds.isResource()) {
if (READ.equals(typeOper)) { if (READ.equals(typeOper)) {
lwM2mTransportRequest.sendAllRequest(client, target, typeOper, lwM2mTransportRequest.sendAllRequest(client, target, typeOper,
@ -1073,8 +1060,8 @@ public class DefaultLwM2MUplinkMsgHandler implements LwM2mUplinkMsgHandler {
}); });
} }
private ResultsAnalyzerParameters getAnalyzerKeyName(ConcurrentHashMap<String, String> keyNameOld, ConcurrentHashMap<String, String> keyNameNew) { private ParametersAnalyzeResult getAnalyzerKeyName(Map<String, String> keyNameOld, Map<String, String> keyNameNew) {
ResultsAnalyzerParameters analyzerParameters = new ResultsAnalyzerParameters(); ParametersAnalyzeResult analyzerParameters = new ParametersAnalyzeResult();
Set<String> paths = keyNameNew.entrySet() Set<String> paths = keyNameNew.entrySet()
.stream() .stream()
.filter(e -> !e.getValue().equals(keyNameOld.get(e.getKey()))) .filter(e -> !e.getValue().equals(keyNameOld.get(e.getKey())))
@ -1084,23 +1071,12 @@ public class DefaultLwM2MUplinkMsgHandler implements LwM2mUplinkMsgHandler {
} }
/** /**
* #3.4, #6
* #6
* #6.1 - send update WriteAttribute * #6.1 - send update WriteAttribute
* #6.2 - send empty WriteAttribute * #6.2 - send empty WriteAttribute
* *
* @param attributeLwm2mOld -
* @param attributeLwm2mNew -
* @return
*/ */
private void getAnalyzerAttributeLwm2m(List<LwM2mClient> clients, JsonObject attributeLwm2mOld, JsonObject attributeLwm2mNew) { private void getAnalyzerAttributeLwm2m(List<LwM2mClient> clients, Map<String, ObjectAttributes> lwm2mAttributesOld, Map<String, ObjectAttributes> lwm2mAttributesNew) {
ResultsAnalyzerParameters analyzerParameters = new ResultsAnalyzerParameters(); ParametersAnalyzeResult analyzerParameters = new ParametersAnalyzeResult();
ConcurrentHashMap<String, Object> lwm2mAttributesOld = new Gson().fromJson(attributeLwm2mOld.toString(),
new TypeToken<ConcurrentHashMap<String, Object>>() {
}.getType());
ConcurrentHashMap<String, Object> lwm2mAttributesNew = new Gson().fromJson(attributeLwm2mNew.toString(),
new TypeToken<ConcurrentHashMap<String, Object>>() {
}.getType());
Set<String> pathOld = lwm2mAttributesOld.keySet(); Set<String> pathOld = lwm2mAttributesOld.keySet();
Set<String> pathNew = lwm2mAttributesNew.keySet(); Set<String> pathNew = lwm2mAttributesNew.keySet();
analyzerParameters.setPathPostParametersAdd(pathNew analyzerParameters.setPathPostParametersAdd(pathNew
@ -1108,7 +1084,7 @@ public class DefaultLwM2MUplinkMsgHandler implements LwM2mUplinkMsgHandler {
analyzerParameters.setPathPostParametersDel(pathOld analyzerParameters.setPathPostParametersDel(pathOld
.stream().filter(p -> !pathNew.contains(p)).collect(Collectors.toSet())); .stream().filter(p -> !pathNew.contains(p)).collect(Collectors.toSet()));
Set<String> pathCommon = pathNew Set<String> pathCommon = pathNew
.stream().filter(p -> pathOld.contains(p)).collect(Collectors.toSet()); .stream().filter(pathOld::contains).collect(Collectors.toSet());
Set<String> pathCommonChange = pathCommon Set<String> pathCommonChange = pathCommon
.stream().filter(p -> !lwm2mAttributesOld.get(p).equals(lwm2mAttributesNew.get(p))).collect(Collectors.toSet()); .stream().filter(p -> !lwm2mAttributesOld.get(p).equals(lwm2mAttributesNew.get(p))).collect(Collectors.toSet());
analyzerParameters.getPathPostParametersAdd().addAll(pathCommonChange); analyzerParameters.getPathPostParametersAdd().addAll(pathCommonChange);
@ -1120,30 +1096,21 @@ public class DefaultLwM2MUplinkMsgHandler implements LwM2mUplinkMsgHandler {
Set<String> pathSend = analyzerParameters.getPathPostParametersAdd().stream().filter(target -> clientObjects.contains("/" + target.split(LWM2M_SEPARATOR_PATH)[1])) Set<String> pathSend = analyzerParameters.getPathPostParametersAdd().stream().filter(target -> clientObjects.contains("/" + target.split(LWM2M_SEPARATOR_PATH)[1]))
.collect(Collectors.toUnmodifiableSet()); .collect(Collectors.toUnmodifiableSet());
if (!pathSend.isEmpty()) { if (!pathSend.isEmpty()) {
ConcurrentHashMap<String, Object> finalParams = lwm2mAttributesNew; pathSend.forEach(target -> lwM2mTransportRequest.sendWriteAttributesRequest(client, target, lwm2mAttributesNew.get(target), this.config.getTimeout()));
pathSend.forEach(target -> lwM2mTransportRequest.sendAllRequest(client, target, WRITE_ATTRIBUTES,
finalParams.get(target), this.config.getTimeout(), null));
} }
}); });
} }
// #6.2 // #6.2
if (analyzerParameters.getPathPostParametersDel().size() > 0) { if (analyzerParameters.getPathPostParametersDel().size() > 0) {
clients.forEach(client -> { clients.forEach(client -> {
Registration registration = client.getRegistration();
Set<String> clientObjects = clientContext.getSupportedIdVerInClient(client); Set<String> clientObjects = clientContext.getSupportedIdVerInClient(client);
Set<String> pathSend = analyzerParameters.getPathPostParametersDel().stream().filter(target -> clientObjects.contains("/" + target.split(LWM2M_SEPARATOR_PATH)[1])) Set<String> pathSend = analyzerParameters.getPathPostParametersDel().stream().filter(target -> clientObjects.contains("/" + target.split(LWM2M_SEPARATOR_PATH)[1]))
.collect(Collectors.toUnmodifiableSet()); .collect(Collectors.toUnmodifiableSet());
if (!pathSend.isEmpty()) { if (!pathSend.isEmpty()) {
pathSend.forEach(target -> { pathSend.forEach(target -> lwM2mTransportRequest.sendWriteAttributesRequest(client, target, new ObjectAttributes(), this.config.getTimeout()));
Map<String, Object> params = (Map<String, Object>) lwm2mAttributesOld.get(target);
params.clear();
params.put(OBJECT_VERSION, "");
lwM2mTransportRequest.sendAllRequest(client, target, WRITE_ATTRIBUTES, params, this.config.getTimeout(), null);
});
} }
}); });
} }
} }
private void cancelObserveFromProfile(LwM2mClient lwM2mClient, Set<String> paramAnallyzer) { private void cancelObserveFromProfile(LwM2mClient lwM2mClient, Set<String> paramAnallyzer) {
@ -1183,10 +1150,10 @@ public class DefaultLwM2MUplinkMsgHandler implements LwM2mUplinkMsgHandler {
* @return - * @return -
*/ */
public String getPresentPathIntoProfile(TransportProtos.SessionInfoProto sessionInfo, String name) { public String getPresentPathIntoProfile(TransportProtos.SessionInfoProto sessionInfo, String name) {
LwM2mClientProfile profile = clientContext.getProfile(new UUID(sessionInfo.getDeviceProfileIdMSB(), sessionInfo.getDeviceProfileIdLSB())); var profile = clientContext.getProfile(new UUID(sessionInfo.getDeviceProfileIdMSB(), sessionInfo.getDeviceProfileIdLSB()));
LwM2mClient lwM2mClient = clientContext.getClientBySessionInfo(sessionInfo); LwM2mClient lwM2mClient = clientContext.getClientBySessionInfo(sessionInfo);
return profile.getPostKeyNameProfile().getAsJsonObject().entrySet().stream() return profile.getObserveAttr().getKeyName().entrySet().stream()
.filter(e -> e.getValue().getAsString().equals(name) && validateResourceInModel(lwM2mClient, e.getKey(), false)).findFirst().map(Map.Entry::getKey) .filter(e -> e.getValue().equals(name) && validateResourceInModel(lwM2mClient, e.getKey(), false)).findFirst().map(Map.Entry::getKey)
.orElse(null); .orElse(null);
} }
@ -1292,7 +1259,7 @@ public class DefaultLwM2MUplinkMsgHandler implements LwM2mUplinkMsgHandler {
SessionInfoProto sessionInfo = this.getSessionInfo(lwM2MClient); SessionInfoProto sessionInfo = this.getSessionInfo(lwM2MClient);
if (sessionInfo != null) { if (sessionInfo != null) {
//#1.1 //#1.1
ConcurrentMap<String, String> keyNamesMap = this.getNamesFromProfileForSharedAttributes(lwM2MClient); Map<String, String> keyNamesMap = this.getNamesFromProfileForSharedAttributes(lwM2MClient);
if (keyNamesMap.values().size() > 0) { if (keyNamesMap.values().size() > 0) {
try { try {
//#1.2 //#1.2
@ -1401,25 +1368,15 @@ public class DefaultLwM2MUplinkMsgHandler implements LwM2mUplinkMsgHandler {
.build(); .build();
} }
/** private Map<String, String> getNamesFromProfileForSharedAttributes(LwM2mClient lwM2MClient) {
* !!! sharedAttr === profileAttr !!! Lwm2mDeviceProfileTransportConfiguration profile = clientContext.getProfile(lwM2MClient.getProfileId());
* Get names or keyNames from profile: resources IsWritable return profile.getObserveAttr().getKeyName();
*
* @param lwM2MClient -
* @return ArrayList keyNames from profile profileAttr && IsWritable
*/
private ConcurrentMap<String, String> getNamesFromProfileForSharedAttributes(LwM2mClient lwM2MClient) {
LwM2mClientProfile profile = clientContext.getProfile(lwM2MClient.getProfileId());
return new Gson().fromJson(profile.getPostKeyNameProfile().toString(),
new TypeToken<ConcurrentHashMap<String, String>>() {
}.getType());
} }
private boolean validateResourceInModel(LwM2mClient lwM2mClient, String pathIdVer, boolean isWritableNotOptional) { private boolean validateResourceInModel(LwM2mClient lwM2mClient, String pathIdVer, boolean isWritableNotOptional) {
ResourceModel resourceModel = lwM2mClient.getResourceModel(pathIdVer, this.config ResourceModel resourceModel = lwM2mClient.getResourceModel(pathIdVer, this.config
.getModelProvider()); .getModelProvider());
Integer objectId = new LwM2mPath(convertPathFromIdVerToObjectId(pathIdVer)).getObjectId(); Integer objectId = new LwM2mPath(fromVersionedIdToObjectId(pathIdVer)).getObjectId();
String objectVer = validateObjectVerFromKey(pathIdVer); String objectVer = validateObjectVerFromKey(pathIdVer);
return resourceModel != null && (isWritableNotOptional ? return resourceModel != null && (isWritableNotOptional ?
objectId != null && objectVer != null && objectVer.equals(lwM2mClient.getRegistration().getSupportedVersion(objectId)) && resourceModel.operations.isWritable() : objectId != null && objectVer != null && objectVer.equals(lwM2mClient.getRegistration().getSupportedVersion(objectId)) && resourceModel.operations.isWritable() :

130
common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mTransportRequest.java

@ -20,6 +20,8 @@ import lombok.extern.slf4j.Slf4j;
import org.eclipse.californium.core.coap.CoAP; import org.eclipse.californium.core.coap.CoAP;
import org.eclipse.californium.core.coap.Response; import org.eclipse.californium.core.coap.Response;
import org.eclipse.leshan.core.Link; import org.eclipse.leshan.core.Link;
import org.eclipse.leshan.core.attributes.Attribute;
import org.eclipse.leshan.core.attributes.AttributeSet;
import org.eclipse.leshan.core.model.ResourceModel; import org.eclipse.leshan.core.model.ResourceModel;
import org.eclipse.leshan.core.node.LwM2mNode; import org.eclipse.leshan.core.node.LwM2mNode;
import org.eclipse.leshan.core.node.LwM2mObject; import org.eclipse.leshan.core.node.LwM2mObject;
@ -51,6 +53,8 @@ import org.eclipse.leshan.core.util.Hex;
import org.eclipse.leshan.core.util.NamedThreadFactory; import org.eclipse.leshan.core.util.NamedThreadFactory;
import org.eclipse.leshan.server.registration.Registration; import org.eclipse.leshan.server.registration.Registration;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.thingsboard.server.common.data.StringUtils;
import org.thingsboard.server.common.data.device.data.lwm2m.ObjectAttributes;
import org.thingsboard.server.queue.util.TbLwM2mTransportComponent; import org.thingsboard.server.queue.util.TbLwM2mTransportComponent;
import org.thingsboard.server.transport.lwm2m.config.LwM2MTransportServerConfig; import org.thingsboard.server.transport.lwm2m.config.LwM2MTransportServerConfig;
import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient; import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient;
@ -62,15 +66,26 @@ import javax.annotation.PostConstruct;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collection; import java.util.Collection;
import java.util.Date; import java.util.Date;
import java.util.LinkedList;
import java.util.List;
import java.util.Set; import java.util.Set;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutorService; import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors; import java.util.concurrent.Executors;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import static org.eclipse.californium.core.coap.CoAP.ResponseCode.CONTENT; import static org.eclipse.californium.core.coap.CoAP.ResponseCode.CONTENT;
import static org.eclipse.leshan.core.ResponseCode.BAD_REQUEST; import static org.eclipse.leshan.core.ResponseCode.BAD_REQUEST;
import static org.eclipse.leshan.core.ResponseCode.NOT_FOUND; import static org.eclipse.leshan.core.ResponseCode.NOT_FOUND;
import static org.eclipse.leshan.core.attributes.Attribute.DIMENSION;
import static org.eclipse.leshan.core.attributes.Attribute.GREATER_THAN;
import static org.eclipse.leshan.core.attributes.Attribute.LESSER_THAN;
import static org.eclipse.leshan.core.attributes.Attribute.MAXIMUM_PERIOD;
import static org.eclipse.leshan.core.attributes.Attribute.MINIMUM_PERIOD;
import static org.eclipse.leshan.core.attributes.Attribute.OBJECT_VERSION;
import static org.eclipse.leshan.core.attributes.Attribute.STEP;
import static org.thingsboard.server.common.data.ota.OtaPackageUpdateStatus.DOWNLOADED; import static org.thingsboard.server.common.data.ota.OtaPackageUpdateStatus.DOWNLOADED;
import static org.thingsboard.server.common.data.ota.OtaPackageUpdateStatus.FAILED; import static org.thingsboard.server.common.data.ota.OtaPackageUpdateStatus.FAILED;
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportServerHelper.getContentFormatByResourceModelType; import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportServerHelper.getContentFormatByResourceModelType;
@ -91,7 +106,7 @@ import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.L
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.RESPONSE_REQUEST_CHANNEL; import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.RESPONSE_REQUEST_CHANNEL;
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.SW_INSTALL_ID; import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.SW_INSTALL_ID;
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.SW_PACKAGE_ID; import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.SW_PACKAGE_ID;
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.convertPathFromIdVerToObjectId; import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.fromVersionedIdToObjectId;
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.convertPathFromObjectIdToIdVer; import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.convertPathFromObjectIdToIdVer;
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.createWriteAttributeRequest; import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.createWriteAttributeRequest;
@ -116,33 +131,105 @@ public class LwM2mTransportRequest {
new NamedThreadFactory(String.format("LwM2M %s channel response after request", RESPONSE_REQUEST_CHANNEL))); new NamedThreadFactory(String.format("LwM2M %s channel response after request", RESPONSE_REQUEST_CHANNEL)));
} }
public void sendReadRequest(LwM2mClient lwM2MClient, String targetId, Long timeout) {
sendReadRequest(lwM2MClient, targetId, lwM2MClient.getDefaultContentFormat(), timeout);
}
public void sendReadRequest(LwM2mClient lwM2MClient, String targetId, ContentFormat contentFormat, Long timeout) {
String objectId = fromVersionedIdToObjectId(targetId);
if (objectId != null && lwM2MClient.isValidObjectVersion(targetId)) {
sendRequest(lwM2MClient, new ReadRequest(contentFormat, objectId), timeout);
}
}
public void sendObserveRequest(LwM2mClient lwM2MClient, String targetId, Long timeout) {
sendObserveRequest(lwM2MClient, targetId, lwM2MClient.getDefaultContentFormat(), timeout);
}
public void sendObserveRequest(LwM2mClient lwM2MClient, String targetId, ContentFormat contentFormat, Long timeout) {
String objectId = fromVersionedIdToObjectId(targetId);
if (objectId != null && lwM2MClient.isValidObjectVersion(targetId)) {
LwM2mPath resultIds = new LwM2mPath(objectId);
Set<Observation> observations = context.getServer().getObservationService().getObservations(lwM2MClient.getRegistration());
if (observations.stream().noneMatch(observation -> observation.getPath().equals(resultIds))) {
ObserveRequest request;
if (resultIds.isResource()) {
request = new ObserveRequest(contentFormat, resultIds.getObjectId(), resultIds.getObjectInstanceId(), resultIds.getResourceId());
} else if (resultIds.isObjectInstance()) {
request = new ObserveRequest(contentFormat, resultIds.getObjectId(), resultIds.getObjectInstanceId());
} else {
request = new ObserveRequest(contentFormat, resultIds.getObjectId());
}
log.info("[{}] Send observation: {}.", lwM2MClient.getEndpoint(), targetId);
sendRequest(lwM2MClient, request, timeout);
}
}
}
public void sendDiscoverRequest(LwM2mClient lwM2MClient, String targetId, Long timeout) {
String objectId = fromVersionedIdToObjectId(targetId);
if (objectId != null && lwM2MClient.isValidObjectVersion(targetId)) {
sendRequest(lwM2MClient, new DiscoverRequest(objectId), timeout);
}
}
public void sendWriteAttributesRequest(LwM2mClient lwM2MClient, String targetId, ObjectAttributes params, Long timeout) {
String objectId = fromVersionedIdToObjectId(targetId);
if (objectId != null && lwM2MClient.isValidObjectVersion(targetId) && params != null) {
List<Attribute> attributes = new LinkedList<>();
// Dimension and Object version are read only attributes.
// addAttribute(attributes, DIMENSION, params.getDim(), dim -> dim >= 0 && dim <= 255);
// addAttribute(attributes, OBJECT_VERSION, params.getVer(), StringUtils::isNotEmpty, Function.identity());
addAttribute(attributes, MAXIMUM_PERIOD, params.getPmax());
addAttribute(attributes, MINIMUM_PERIOD, params.getPmin());
addAttribute(attributes, GREATER_THAN, params.getGt());
addAttribute(attributes, LESSER_THAN, params.getLt());
addAttribute(attributes, STEP, params.getSt());
AttributeSet attributeSet = new AttributeSet(attributes);
sendRequest(lwM2MClient, new WriteAttributesRequest(objectId, attributeSet), timeout);
}
}
private <T> void addAttribute(List<Attribute> attributes, String attributeName, T value) {
addAttribute(attributes, attributeName, value, null, null);
}
private <T> void addAttribute(List<Attribute> attributes, String attributeName, T value, Function<T, ?> converter) {
addAttribute(attributes, attributeName, value, null, converter);
}
private <T> void addAttribute(List<Attribute> attributes, String attributeName, T value, Predicate<T> filter, Function<T, ?> converter) {
if (value != null && ((filter == null) || filter.test(value))) {
attributes.add(new Attribute(attributeName, converter != null ? converter.apply(value) : value));
}
}
public void sendAllRequest(LwM2mClient lwM2MClient, String targetIdVer, LwM2mTypeOper typeOper, Object params, long timeoutInMs, LwM2mClientRpcRequest lwm2mClientRpcRequest) { public void sendAllRequest(LwM2mClient lwM2MClient, String targetIdVer, LwM2mTypeOper typeOper, Object params, long timeoutInMs, LwM2mClientRpcRequest lwm2mClientRpcRequest) {
sendAllRequest(lwM2MClient, targetIdVer, typeOper, lwM2MClient.getDefaultContentFormat(), params, timeoutInMs, lwm2mClientRpcRequest); sendAllRequest(lwM2MClient, targetIdVer, typeOper, lwM2MClient.getDefaultContentFormat(), params, timeoutInMs, lwm2mClientRpcRequest);
} }
public void sendAllRequest(LwM2mClient lwM2MClient, String targetIdVer, LwM2mTypeOper typeOper, public void sendAllRequest(LwM2mClient lwM2MClient, String targetIdVer, LwM2mTypeOper typeOper,
ContentFormat contentFormat, Object params, long timeoutInMs, LwM2mClientRpcRequest lwm2mClientRpcRequest) { ContentFormat contentFormat, Object params, long timeoutInMs, LwM2mClientRpcRequest lwm2mClientRpcRequest) {
Registration registration = lwM2MClient.getRegistration(); Registration registration = lwM2MClient.getRegistration();
try { try {
String target = convertPathFromIdVerToObjectId(targetIdVer); String target = fromVersionedIdToObjectId(targetIdVer);
if(contentFormat == null){ if (contentFormat == null) {
contentFormat = ContentFormat.DEFAULT; contentFormat = ContentFormat.DEFAULT;
} }
LwM2mPath resultIds = target != null ? new LwM2mPath(target) : null; LwM2mPath resultIds = target != null ? new LwM2mPath(target) : null;
if (!OBSERVE_CANCEL.name().equals(typeOper.name()) && resultIds != null && registration != null && resultIds.getObjectId() >= 0 && lwM2MClient != null) { if (!OBSERVE_CANCEL.name().equals(typeOper.name()) && resultIds != null && registration != null && resultIds.getObjectId() >= 0) {
if (lwM2MClient.isValidObjectVersion(targetIdVer)) { if (lwM2MClient.isValidObjectVersion(targetIdVer)) {
timeoutInMs = timeoutInMs > 0 ? timeoutInMs : DEFAULT_TIMEOUT; timeoutInMs = timeoutInMs > 0 ? timeoutInMs : DEFAULT_TIMEOUT;
SimpleDownlinkRequest request = createRequest(registration, lwM2MClient, typeOper, contentFormat, target, SimpleDownlinkRequest request = createRequest(registration, lwM2MClient, typeOper, contentFormat, target,
targetIdVer, resultIds, params, lwm2mClientRpcRequest); targetIdVer, resultIds, params, lwm2mClientRpcRequest);
if (request != null) { if (request != null) {
try { try {
this.sendRequest(registration, lwM2MClient, request, timeoutInMs, lwm2mClientRpcRequest); this.sendRequest(lwM2MClient, request, timeoutInMs, lwm2mClientRpcRequest);
} catch (ClientSleepingException e) { } catch (ClientSleepingException e) {
SimpleDownlinkRequest finalRequest = request; SimpleDownlinkRequest finalRequest = request;
long finalTimeoutInMs = timeoutInMs; long finalTimeoutInMs = timeoutInMs;
LwM2mClientRpcRequest finalRpcRequest = lwm2mClientRpcRequest; LwM2mClientRpcRequest finalRpcRequest = lwm2mClientRpcRequest;
lwM2MClient.getQueuedRequests().add(() -> sendRequest(registration, lwM2MClient, finalRequest, finalTimeoutInMs, finalRpcRequest)); lwM2MClient.getQueuedRequests().add(() -> sendRequest(lwM2MClient, finalRequest, finalTimeoutInMs, finalRpcRequest));
} catch (Exception e) { } catch (Exception e) {
log.error("[{}] [{}] [{}] Failed to send downlink.", registration.getEndpoint(), targetIdVer, typeOper.name(), e); log.error("[{}] [{}] [{}] Failed to send downlink.", registration.getEndpoint(), targetIdVer, typeOper.name(), e);
} }
@ -222,8 +309,8 @@ public class LwM2mTransportRequest {
} }
private SimpleDownlinkRequest createRequest(Registration registration, LwM2mClient lwM2MClient, LwM2mTypeOper typeOper, private SimpleDownlinkRequest createRequest(Registration registration, LwM2mClient lwM2MClient, LwM2mTypeOper typeOper,
ContentFormat contentFormat, String target, String targetIdVer, ContentFormat contentFormat, String target, String targetIdVer,
LwM2mPath resultIds, Object params, LwM2mClientRpcRequest rpcRequest) { LwM2mPath resultIds, Object params, LwM2mClientRpcRequest rpcRequest) {
SimpleDownlinkRequest request = null; SimpleDownlinkRequest request = null;
switch (typeOper) { switch (typeOper) {
case READ: case READ:
@ -320,15 +407,18 @@ public class LwM2mTransportRequest {
return request; return request;
} }
/** private void sendRequest(LwM2mClient lwM2MClient, SimpleDownlinkRequest request, long timeoutInMs) {
* @param registration - try {
* @param request - sendRequest(lwM2MClient, request, timeoutInMs, null);
* @param timeoutInMs - } catch (ClientSleepingException e) {
*/ //TODO: this may cause infinite loop / memory leak.
lwM2MClient.getQueuedRequests().add(() -> sendRequest(lwM2MClient, request, timeoutInMs, null));
}
}
@SuppressWarnings({"error sendRequest"}) @SuppressWarnings({"error sendRequest"})
private void sendRequest(Registration registration, LwM2mClient lwM2MClient, SimpleDownlinkRequest request, private void sendRequest(LwM2mClient lwM2MClient, SimpleDownlinkRequest request, long timeoutInMs, LwM2mClientRpcRequest rpcRequest) {
long timeoutInMs, LwM2mClientRpcRequest rpcRequest) { Registration registration = lwM2MClient.getRegistration();
context.getServer().send(registration, request, timeoutInMs, (ResponseCallback<?>) response -> { context.getServer().send(registration, request, timeoutInMs, (ResponseCallback<?>) response -> {
if (!lwM2MClient.isInit()) { if (!lwM2MClient.isInit()) {
@ -455,8 +545,8 @@ public class LwM2mTransportRequest {
/** /**
* processing a response from a client * processing a response from a client
* *
* @param path - * @param path -
* @param response - * @param response -
*/ */
private void sendResponse(LwM2mClient lwM2mClient, String path, LwM2mResponse response, private void sendResponse(LwM2mClient lwM2mClient, String path, LwM2mResponse response,
SimpleDownlinkRequest request, LwM2mClientRpcRequest rpcRequest) { SimpleDownlinkRequest request, LwM2mClientRpcRequest rpcRequest) {
@ -550,8 +640,7 @@ public class LwM2mTransportRequest {
if (rpcRequest != null) { if (rpcRequest != null) {
rpcRequest.setInfoMsg(msg); rpcRequest.setInfoMsg(msg);
} }
} } else if (rpcRequest != null) {
else if (rpcRequest != null) {
handler.sentRpcResponse(rpcRequest, response.getCode().getName(), msg, LOG_LW2M_INFO); handler.sentRpcResponse(rpcRequest, response.getCode().getName(), msg, LOG_LW2M_INFO);
} }
} }
@ -610,4 +699,5 @@ public class LwM2mTransportRequest {
handler.sentRpcResponse(rpcRequest, CONTENT.name(), null, LOG_LW2M_INFO); handler.sentRpcResponse(rpcRequest, CONTENT.name(), null, LOG_LW2M_INFO);
} }
} }
} }

167
common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mTransportUtil.java

@ -16,13 +16,9 @@
package org.thingsboard.server.transport.lwm2m.server; package org.thingsboard.server.transport.lwm2m.server;
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.collect.Sets;
import com.google.gson.Gson;
import com.google.gson.JsonArray;
import com.google.gson.JsonObject; import com.google.gson.JsonObject;
import com.google.gson.JsonParser; import com.google.gson.JsonParser;
import com.google.gson.JsonSyntaxException; import com.google.gson.JsonSyntaxException;
import com.google.gson.reflect.TypeToken;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.eclipse.leshan.core.attributes.Attribute; import org.eclipse.leshan.core.attributes.Attribute;
@ -42,17 +38,17 @@ import org.eclipse.leshan.core.util.Hex;
import org.eclipse.leshan.server.registration.Registration; import org.eclipse.leshan.server.registration.Registration;
import org.nustaq.serialization.FSTConfiguration; import org.nustaq.serialization.FSTConfiguration;
import org.thingsboard.server.common.data.DeviceProfile; import org.thingsboard.server.common.data.DeviceProfile;
import org.thingsboard.server.common.data.DeviceTransportType;
import org.thingsboard.server.common.data.device.data.lwm2m.BootstrapConfiguration;
import org.thingsboard.server.common.data.device.profile.DeviceProfileTransportConfiguration;
import org.thingsboard.server.common.data.device.profile.Lwm2mDeviceProfileTransportConfiguration; import org.thingsboard.server.common.data.device.profile.Lwm2mDeviceProfileTransportConfiguration;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.ota.OtaPackageKey; import org.thingsboard.server.common.data.ota.OtaPackageKey;
import org.thingsboard.server.common.data.ota.OtaPackageType; import org.thingsboard.server.common.data.ota.OtaPackageType;
import org.thingsboard.server.common.data.ota.OtaPackageUpdateStatus; import org.thingsboard.server.common.data.ota.OtaPackageUpdateStatus;
import org.thingsboard.server.common.data.ota.OtaPackageUtil; import org.thingsboard.server.common.data.ota.OtaPackageUtil;
import org.thingsboard.server.common.transport.TransportServiceCallback; import org.thingsboard.server.common.transport.TransportServiceCallback;
import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient; import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient;
import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClientProfile;
import java.io.IOException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.Date; import java.util.Date;
@ -60,7 +56,6 @@ import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Optional; import java.util.Optional;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import static org.eclipse.leshan.core.attributes.Attribute.DIMENSION; import static org.eclipse.leshan.core.attributes.Attribute.DIMENSION;
@ -379,7 +374,7 @@ public class LwM2mTransportUtil {
switch (updateResultFw) { switch (updateResultFw) {
case INITIAL: case INITIAL:
return equalsFwSateToFirmwareUpdateStatus(stateFw); return equalsFwSateToFirmwareUpdateStatus(stateFw);
case UPDATE_SUCCESSFULLY: case UPDATE_SUCCESSFULLY:
return UPDATED; return UPDATED;
case NOT_ENOUGH: case NOT_ENOUGH:
case OUT_OFF_MEMORY: case OUT_OFF_MEMORY:
@ -399,7 +394,7 @@ public class LwM2mTransportUtil {
switch (updateResultFw) { switch (updateResultFw) {
case INITIAL: case INITIAL:
return VERIFIED; return VERIFIED;
case UPDATE_SUCCESSFULLY: case UPDATE_SUCCESSFULLY:
return UPDATED; return UPDATED;
case NOT_ENOUGH: case NOT_ENOUGH:
case OUT_OFF_MEMORY: case OUT_OFF_MEMORY:
@ -695,26 +690,23 @@ public class LwM2mTransportUtil {
} }
} }
public static LwM2mOtaConvert convertOtaUpdateValueToString (String pathIdVer, Object value, ResourceModel.Type currentType) { public static LwM2mOtaConvert convertOtaUpdateValueToString(String pathIdVer, Object value, ResourceModel.Type currentType) {
String path = convertPathFromIdVerToObjectId(pathIdVer); String path = fromVersionedIdToObjectId(pathIdVer);
LwM2mOtaConvert lwM2mOtaConvert = new LwM2mOtaConvert(); LwM2mOtaConvert lwM2mOtaConvert = new LwM2mOtaConvert();
if (path != null) { if (path != null) {
if (FW_STATE_ID.equals(path)) { if (FW_STATE_ID.equals(path)) {
lwM2mOtaConvert.setCurrentType(STRING); lwM2mOtaConvert.setCurrentType(STRING);
lwM2mOtaConvert.setValue(StateFw.fromStateFwByCode(((Long) value).intValue()).type); lwM2mOtaConvert.setValue(StateFw.fromStateFwByCode(((Long) value).intValue()).type);
return lwM2mOtaConvert; return lwM2mOtaConvert;
} } else if (FW_RESULT_ID.equals(path)) {
else if (FW_RESULT_ID.equals(path)) {
lwM2mOtaConvert.setCurrentType(STRING); lwM2mOtaConvert.setCurrentType(STRING);
lwM2mOtaConvert.setValue(UpdateResultFw.fromUpdateResultFwByCode(((Long) value).intValue()).type); lwM2mOtaConvert.setValue(UpdateResultFw.fromUpdateResultFwByCode(((Long) value).intValue()).type);
return lwM2mOtaConvert; return lwM2mOtaConvert;
} } else if (SW_UPDATE_STATE_ID.equals(path)) {
else if (SW_UPDATE_STATE_ID.equals(path)) {
lwM2mOtaConvert.setCurrentType(STRING); lwM2mOtaConvert.setCurrentType(STRING);
lwM2mOtaConvert.setValue(UpdateStateSw.fromUpdateStateSwByCode(((Long) value).intValue()).type); lwM2mOtaConvert.setValue(UpdateStateSw.fromUpdateStateSwByCode(((Long) value).intValue()).type);
return lwM2mOtaConvert; return lwM2mOtaConvert;
} } else if (SW_RESULT_ID.equals(path)) {
else if (SW_RESULT_ID.equals(path)) {
lwM2mOtaConvert.setCurrentType(STRING); lwM2mOtaConvert.setCurrentType(STRING);
lwM2mOtaConvert.setValue(UpdateResultSw.fromUpdateResultSwByCode(((Long) value).intValue()).type); lwM2mOtaConvert.setValue(UpdateResultSw.fromUpdateResultSwByCode(((Long) value).intValue()).type);
return lwM2mOtaConvert; return lwM2mOtaConvert;
@ -738,113 +730,32 @@ public class LwM2mTransportUtil {
return null; return null;
} }
// public static LwM2mClientProfile getNewProfileParameters(JsonObject profilesConfigData, TenantId tenantId) {
public static LwM2mClientProfile getNewProfileParameters(JsonObject profilesConfigData, TenantId tenantId) { // LwM2mClientProfile lwM2MClientProfile = new LwM2mClientProfile();
LwM2mClientProfile lwM2MClientProfile = new LwM2mClientProfile(); // lwM2MClientProfile.setTenantId(tenantId);
lwM2MClientProfile.setTenantId(tenantId); // lwM2MClientProfile.setPostClientLwM2mSettings(profilesConfigData.get(CLIENT_LWM2M_SETTINGS).getAsJsonObject());
lwM2MClientProfile.setPostClientLwM2mSettings(profilesConfigData.get(CLIENT_LWM2M_SETTINGS).getAsJsonObject()); // lwM2MClientProfile.setPostKeyNameProfile(profilesConfigData.get(OBSERVE_ATTRIBUTE_TELEMETRY).getAsJsonObject().get(KEY_NAME).getAsJsonObject());
lwM2MClientProfile.setPostKeyNameProfile(profilesConfigData.get(OBSERVE_ATTRIBUTE_TELEMETRY).getAsJsonObject().get(KEY_NAME).getAsJsonObject()); // lwM2MClientProfile.setPostAttributeProfile(profilesConfigData.get(OBSERVE_ATTRIBUTE_TELEMETRY).getAsJsonObject().get(ATTRIBUTE).getAsJsonArray());
lwM2MClientProfile.setPostAttributeProfile(profilesConfigData.get(OBSERVE_ATTRIBUTE_TELEMETRY).getAsJsonObject().get(ATTRIBUTE).getAsJsonArray()); // lwM2MClientProfile.setPostTelemetryProfile(profilesConfigData.get(OBSERVE_ATTRIBUTE_TELEMETRY).getAsJsonObject().get(TELEMETRY).getAsJsonArray());
lwM2MClientProfile.setPostTelemetryProfile(profilesConfigData.get(OBSERVE_ATTRIBUTE_TELEMETRY).getAsJsonObject().get(TELEMETRY).getAsJsonArray()); // lwM2MClientProfile.setPostObserveProfile(profilesConfigData.get(OBSERVE_ATTRIBUTE_TELEMETRY).getAsJsonObject().get(OBSERVE_LWM2M).getAsJsonArray());
lwM2MClientProfile.setPostObserveProfile(profilesConfigData.get(OBSERVE_ATTRIBUTE_TELEMETRY).getAsJsonObject().get(OBSERVE_LWM2M).getAsJsonArray()); // lwM2MClientProfile.setPostAttributeLwm2mProfile(profilesConfigData.get(OBSERVE_ATTRIBUTE_TELEMETRY).getAsJsonObject().get(ATTRIBUTE_LWM2M).getAsJsonObject());
lwM2MClientProfile.setPostAttributeLwm2mProfile(profilesConfigData.get(OBSERVE_ATTRIBUTE_TELEMETRY).getAsJsonObject().get(ATTRIBUTE_LWM2M).getAsJsonObject()); // return lwM2MClientProfile;
return lwM2MClientProfile; // }
}
public static Lwm2mDeviceProfileTransportConfiguration toLwM2MClientProfile(DeviceProfile deviceProfile) {
/** DeviceProfileTransportConfiguration transportConfiguration = deviceProfile.getProfileData().getTransportConfiguration();
* @return deviceProfileBody with Observe&Attribute&Telemetry From Thingsboard if (transportConfiguration.getType().equals(DeviceTransportType.LWM2M)) {
* Example: return (Lwm2mDeviceProfileTransportConfiguration) transportConfiguration;
* property: {"clientLwM2mSettings": { } else {
* clientUpdateValueAfterConnect: false; log.warn("[{}] Received profile with invalid transport configuration: {}", deviceProfile.getId(), deviceProfile.getProfileData().getTransportConfiguration());
* } throw new IllegalArgumentException("Received profile with invalid transport configuration: " + transportConfiguration.getType());
* property: "observeAttr" }
* {"keyName": {
* "/3/0/1": "modelNumber",
* "/3/0/0": "manufacturer",
* "/3/0/2": "serialNumber"
* },
* "attribute":["/2/0/1","/3/0/9"],
* "telemetry":["/1/0/1","/2/0/1","/6/0/1"],
* "observe":["/2/0","/2/0/0","/4/0/2"]}
* "attributeLwm2m": {"/3_1.0": {"ver": "currentTimeTest11"},
* "/3_1.0/0": {"gt": 17},
* "/3_1.0/0/9": {"pmax": 45}, "/3_1.2": {ver": "3_1.2"}}
*/
//TODO: refactor this to valid jackson code instead of parsing manually.
public static LwM2mClientProfile toLwM2MClientProfile(DeviceProfile deviceProfile) {
// if (((Lwm2mDeviceProfileTransportConfiguration) deviceProfile.getProfileData().getTransportConfiguration()).getProperties().size() > 0) {
// Object profile = ((Lwm2mDeviceProfileTransportConfiguration) deviceProfile.getProfileData().getTransportConfiguration()).getProperties();
// try {
// ObjectMapper mapper = new ObjectMapper();
// String profileStr = mapper.writeValueAsString(profile);
// JsonObject profileJson = (profileStr != null) ? validateJson(profileStr) : null;
// return getValidateCredentialsBodyFromThingsboard(profileJson) ? LwM2mTransportUtil.getNewProfileParameters(profileJson, deviceProfile.getTenantId()) : null;
// } catch (IOException e) {
// log.error("", e);
// }
// }
return null;
}
public static JsonObject getBootstrapParametersFromThingsboard(DeviceProfile deviceProfile) {
// if (deviceProfile != null && ((Lwm2mDeviceProfileTransportConfiguration) deviceProfile.getProfileData().getTransportConfiguration()).getProperties().size() > 0) {
// Object bootstrap = ((Lwm2mDeviceProfileTransportConfiguration) deviceProfile.getProfileData().getTransportConfiguration()).getProperties();
// try {
// ObjectMapper mapper = new ObjectMapper();
// String bootstrapStr = mapper.writeValueAsString(bootstrap);
// JsonObject objectMsg = (bootstrapStr != null) ? validateJson(bootstrapStr) : null;
// return (getValidateBootstrapProfileFromThingsboard(objectMsg)) ? objectMsg.get(BOOTSTRAP).getAsJsonObject() : null;
// } catch (IOException e) {
// log.error("", e);
// }
// }
return null;
}
private static boolean getValidateCredentialsBodyFromThingsboard(JsonObject objectMsg) {
return (objectMsg != null &&
!objectMsg.isJsonNull() &&
objectMsg.has(CLIENT_LWM2M_SETTINGS) &&
!objectMsg.get(CLIENT_LWM2M_SETTINGS).isJsonNull() &&
objectMsg.get(CLIENT_LWM2M_SETTINGS).isJsonObject() &&
objectMsg.has(OBSERVE_ATTRIBUTE_TELEMETRY) &&
!objectMsg.get(OBSERVE_ATTRIBUTE_TELEMETRY).isJsonNull() &&
objectMsg.get(OBSERVE_ATTRIBUTE_TELEMETRY).isJsonObject() &&
objectMsg.get(OBSERVE_ATTRIBUTE_TELEMETRY).getAsJsonObject().has(KEY_NAME) &&
!objectMsg.get(OBSERVE_ATTRIBUTE_TELEMETRY).getAsJsonObject().get(KEY_NAME).isJsonNull() &&
objectMsg.get(OBSERVE_ATTRIBUTE_TELEMETRY).getAsJsonObject().get(KEY_NAME).isJsonObject() &&
objectMsg.get(OBSERVE_ATTRIBUTE_TELEMETRY).getAsJsonObject().has(ATTRIBUTE) &&
!objectMsg.get(OBSERVE_ATTRIBUTE_TELEMETRY).getAsJsonObject().get(ATTRIBUTE).isJsonNull() &&
objectMsg.get(OBSERVE_ATTRIBUTE_TELEMETRY).getAsJsonObject().get(ATTRIBUTE).isJsonArray() &&
objectMsg.get(OBSERVE_ATTRIBUTE_TELEMETRY).getAsJsonObject().has(TELEMETRY) &&
!objectMsg.get(OBSERVE_ATTRIBUTE_TELEMETRY).getAsJsonObject().get(TELEMETRY).isJsonNull() &&
objectMsg.get(OBSERVE_ATTRIBUTE_TELEMETRY).getAsJsonObject().get(TELEMETRY).isJsonArray() &&
objectMsg.get(OBSERVE_ATTRIBUTE_TELEMETRY).getAsJsonObject().has(OBSERVE_LWM2M) &&
!objectMsg.get(OBSERVE_ATTRIBUTE_TELEMETRY).getAsJsonObject().get(OBSERVE_LWM2M).isJsonNull() &&
objectMsg.get(OBSERVE_ATTRIBUTE_TELEMETRY).getAsJsonObject().get(OBSERVE_LWM2M).isJsonArray() &&
objectMsg.get(OBSERVE_ATTRIBUTE_TELEMETRY).getAsJsonObject().has(ATTRIBUTE_LWM2M) &&
!objectMsg.get(OBSERVE_ATTRIBUTE_TELEMETRY).getAsJsonObject().get(ATTRIBUTE_LWM2M).isJsonNull() &&
objectMsg.get(OBSERVE_ATTRIBUTE_TELEMETRY).getAsJsonObject().get(ATTRIBUTE_LWM2M).isJsonObject());
} }
private static boolean getValidateBootstrapProfileFromThingsboard(JsonObject objectMsg) { public static BootstrapConfiguration getBootstrapParametersFromThingsboard(DeviceProfile deviceProfile) {
return (objectMsg != null && return toLwM2MClientProfile(deviceProfile).getBootstrap();
!objectMsg.isJsonNull() &&
objectMsg.has(BOOTSTRAP) &&
objectMsg.get(BOOTSTRAP).isJsonObject() &&
!objectMsg.get(BOOTSTRAP).isJsonNull() &&
objectMsg.get(BOOTSTRAP).getAsJsonObject().has(SERVERS) &&
!objectMsg.get(BOOTSTRAP).getAsJsonObject().get(SERVERS).isJsonNull() &&
objectMsg.get(BOOTSTRAP).getAsJsonObject().get(SERVERS).isJsonObject() &&
objectMsg.get(BOOTSTRAP).getAsJsonObject().has(BOOTSTRAP_SERVER) &&
!objectMsg.get(BOOTSTRAP).getAsJsonObject().get(BOOTSTRAP_SERVER).isJsonNull() &&
objectMsg.get(BOOTSTRAP).getAsJsonObject().get(BOOTSTRAP_SERVER).isJsonObject() &&
objectMsg.get(BOOTSTRAP).getAsJsonObject().has(LWM2M_SERVER) &&
!objectMsg.get(BOOTSTRAP).getAsJsonObject().get(LWM2M_SERVER).isJsonNull() &&
objectMsg.get(BOOTSTRAP).getAsJsonObject().get(LWM2M_SERVER).isJsonObject());
} }
public static JsonObject validateJson(String jsonStr) { public static JsonObject validateJson(String jsonStr) {
JsonObject object = null; JsonObject object = null;
if (jsonStr != null && !jsonStr.isEmpty()) { if (jsonStr != null && !jsonStr.isEmpty()) {
@ -901,8 +812,11 @@ public class LwM2mTransportUtil {
}; };
} }
public static String convertPathFromIdVerToObjectId(String pathIdVer) { public static String fromVersionedIdToObjectId(String pathIdVer) {
try { try {
if(pathIdVer == null) {
return null;
}
String[] keyArray = pathIdVer.split(LWM2M_SEPARATOR_PATH); String[] keyArray = pathIdVer.split(LWM2M_SEPARATOR_PATH);
if (keyArray.length > 1 && keyArray[1].split(LWM2M_SEPARATOR_KEY).length == 2) { if (keyArray.length > 1 && keyArray[1].split(LWM2M_SEPARATOR_KEY).length == 2) {
keyArray[1] = keyArray[1].split(LWM2M_SEPARATOR_KEY)[0]; keyArray[1] = keyArray[1].split(LWM2M_SEPARATOR_KEY)[0];
@ -911,7 +825,8 @@ public class LwM2mTransportUtil {
return pathIdVer; return pathIdVer;
} }
} catch (Exception e) { } catch (Exception e) {
return null; log.warn("Issue converting path with version [{}] to path without version: ", pathIdVer, e);
throw new RuntimeException(e);
} }
} }
@ -1025,12 +940,6 @@ public class LwM2mTransportUtil {
return attributeLists.toArray(Attribute[]::new); return attributeLists.toArray(Attribute[]::new);
} }
public static Set<String> convertJsonArrayToSet(JsonArray jsonArray) {
List<String> attributeListOld = new Gson().fromJson(jsonArray, new TypeToken<List<String>>() {
}.getType());
return Sets.newConcurrentHashSet(attributeListOld);
}
public static ResourceModel.Type equalsResourceTypeGetSimpleName(Object value) { public static ResourceModel.Type equalsResourceTypeGetSimpleName(Object value) {
switch (value.getClass().getSimpleName()) { switch (value.getClass().getSimpleName()) {
case "Double": case "Double":

2
common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mVersionedModelProvider.java

@ -72,7 +72,7 @@ public class LwM2mVersionedModelProvider implements LwM2mModelProvider {
public DynamicModel(Registration registration) { public DynamicModel(Registration registration) {
this.registration = registration; this.registration = registration;
this.tenantId = lwM2mClientContext.getProfile(registration).getTenantId(); this.tenantId = lwM2mClientContext.getClientByEndpoint(registration.getEndpoint()).getTenantId();
} }
@Override @Override

49
common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClient.java

@ -32,6 +32,7 @@ import org.eclipse.leshan.server.registration.Registration;
import org.eclipse.leshan.server.security.SecurityInfo; import org.eclipse.leshan.server.security.SecurityInfo;
import org.thingsboard.server.common.data.Device; import org.thingsboard.server.common.data.Device;
import org.thingsboard.server.common.data.DeviceProfile; import org.thingsboard.server.common.data.DeviceProfile;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.ota.OtaPackageType; import org.thingsboard.server.common.data.ota.OtaPackageType;
import org.thingsboard.server.common.transport.auth.ValidateDeviceCredentialsResponse; import org.thingsboard.server.common.transport.auth.ValidateDeviceCredentialsResponse;
import org.thingsboard.server.gen.transport.TransportProtos.SessionInfoProto; import org.thingsboard.server.gen.transport.TransportProtos.SessionInfoProto;
@ -58,7 +59,7 @@ import static org.eclipse.leshan.core.model.ResourceModel.Type.OPAQUE;
import static org.eclipse.leshan.core.model.ResourceModel.Type.STRING; import static org.eclipse.leshan.core.model.ResourceModel.Type.STRING;
import static org.thingsboard.server.common.data.lwm2m.LwM2mConstants.LWM2M_SEPARATOR_PATH; import static org.thingsboard.server.common.data.lwm2m.LwM2mConstants.LWM2M_SEPARATOR_PATH;
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.TRANSPORT_DEFAULT_LWM2M_VERSION; import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.TRANSPORT_DEFAULT_LWM2M_VERSION;
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.convertPathFromIdVerToObjectId; import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.fromVersionedIdToObjectId;
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.convertPathFromObjectIdToIdVer; import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.convertPathFromObjectIdToIdVer;
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.equalsResourceTypeGetSimpleName; import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.equalsResourceTypeGetSimpleName;
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.getVerFromPathIdVerOrId; import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.getVerFromPathIdVerOrId;
@ -92,6 +93,8 @@ public class LwM2mClient implements Cloneable {
@Getter @Getter
private SecurityInfo securityInfo; private SecurityInfo securityInfo;
@Getter @Getter
private TenantId tenantId;
@Getter
private UUID deviceId; private UUID deviceId;
@Getter @Getter
private SessionInfoProto session; private SessionInfoProto session;
@ -127,19 +130,17 @@ public class LwM2mClient implements Cloneable {
this.state = LwM2MClientState.CREATED; this.state = LwM2MClientState.CREATED;
} }
public void init(String identity, SecurityInfo securityInfo, ValidateDeviceCredentialsResponse credentials, UUID profileId, UUID sessionId) { public void init(String identity, SecurityInfo securityInfo, ValidateDeviceCredentialsResponse credentials, UUID sessionId) {
this.identity = identity; this.identity = identity;
this.securityInfo = securityInfo; this.securityInfo = securityInfo;
this.credentials = credentials; this.credentials = credentials;
this.profileId = profileId;
this.init = false; this.init = false;
if (this.credentials != null && this.credentials.hasDeviceInfo()) { this.session = createSession(nodeId, sessionId, credentials);
this.session = createSession(nodeId, sessionId, credentials); this.tenantId = new TenantId(new UUID(session.getTenantIdMSB(), session.getTenantIdLSB()));
this.deviceId = new UUID(session.getDeviceIdMSB(), session.getDeviceIdLSB()); this.deviceId = new UUID(session.getDeviceIdMSB(), session.getDeviceIdLSB());
this.profileId = new UUID(session.getDeviceProfileIdMSB(), session.getDeviceProfileIdLSB()); this.profileId = new UUID(session.getDeviceProfileIdMSB(), session.getDeviceProfileIdLSB());
this.deviceName = session.getDeviceName(); this.deviceName = session.getDeviceName();
this.deviceProfileName = session.getDeviceType(); this.deviceProfileName = session.getDeviceType();
}
} }
public void lock() { public void lock() {
@ -198,7 +199,7 @@ public class LwM2mClient implements Cloneable {
this.resources.get(pathRezIdVer).setLwM2mResource(rez); this.resources.get(pathRezIdVer).setLwM2mResource(rez);
return true; return true;
} else { } else {
LwM2mPath pathIds = new LwM2mPath(convertPathFromIdVerToObjectId(pathRezIdVer)); LwM2mPath pathIds = new LwM2mPath(fromVersionedIdToObjectId(pathRezIdVer));
ResourceModel resourceModel = modelProvider.getObjectModel(registration).getResourceModel(pathIds.getObjectId(), pathIds.getResourceId()); ResourceModel resourceModel = modelProvider.getObjectModel(registration).getResourceModel(pathIds.getObjectId(), pathIds.getResourceId());
if (resourceModel != null) { if (resourceModel != null) {
this.resources.put(pathRezIdVer, new ResourceValue(rez, resourceModel)); this.resources.put(pathRezIdVer, new ResourceValue(rez, resourceModel));
@ -226,7 +227,7 @@ public class LwM2mClient implements Cloneable {
} }
public String getRezIdByResourceNameAndObjectInstanceId(String resourceName, String pathObjectInstanceIdVer, LwM2mModelProvider modelProvider) { public String getRezIdByResourceNameAndObjectInstanceId(String resourceName, String pathObjectInstanceIdVer, LwM2mModelProvider modelProvider) {
LwM2mPath pathIds = new LwM2mPath(convertPathFromIdVerToObjectId(pathObjectInstanceIdVer)); LwM2mPath pathIds = new LwM2mPath(fromVersionedIdToObjectId(pathObjectInstanceIdVer));
if (pathIds.isObjectInstance()) { if (pathIds.isObjectInstance()) {
Set<Integer> rezIds = modelProvider.getObjectModel(registration) Set<Integer> rezIds = modelProvider.getObjectModel(registration)
.getObjectModel(pathIds.getObjectId()).resources.entrySet() .getObjectModel(pathIds.getObjectId()).resources.entrySet()
@ -240,7 +241,7 @@ public class LwM2mClient implements Cloneable {
} }
public ResourceModel getResourceModel(String pathIdVer, LwM2mModelProvider modelProvider) { public ResourceModel getResourceModel(String pathIdVer, LwM2mModelProvider modelProvider) {
LwM2mPath pathIds = new LwM2mPath(convertPathFromIdVerToObjectId(pathIdVer)); LwM2mPath pathIds = new LwM2mPath(fromVersionedIdToObjectId(pathIdVer));
String verSupportedObject = registration.getSupportedObject().get(pathIds.getObjectId()); String verSupportedObject = registration.getSupportedObject().get(pathIds.getObjectId());
String verRez = getVerFromPathIdVerOrId(pathIdVer); String verRez = getVerFromPathIdVerOrId(pathIdVer);
return verRez == null || verRez.equals(verSupportedObject) ? modelProvider.getObjectModel(registration) return verRez == null || verRez.equals(verSupportedObject) ? modelProvider.getObjectModel(registration)
@ -248,7 +249,7 @@ public class LwM2mClient implements Cloneable {
} }
public ObjectModel getObjectModel(String pathIdVer, LwM2mModelProvider modelProvider) { public ObjectModel getObjectModel(String pathIdVer, LwM2mModelProvider modelProvider) {
LwM2mPath pathIds = new LwM2mPath(convertPathFromIdVerToObjectId(pathIdVer)); LwM2mPath pathIds = new LwM2mPath(fromVersionedIdToObjectId(pathIdVer));
String verSupportedObject = registration.getSupportedObject().get(pathIds.getObjectId()); String verSupportedObject = registration.getSupportedObject().get(pathIds.getObjectId());
String verRez = getVerFromPathIdVerOrId(pathIdVer); String verRez = getVerFromPathIdVerOrId(pathIdVer);
return verRez == null || verRez.equals(verSupportedObject) ? modelProvider.getObjectModel(registration) return verRez == null || verRez.equals(verSupportedObject) ? modelProvider.getObjectModel(registration)
@ -290,13 +291,13 @@ public class LwM2mClient implements Cloneable {
} else { } else {
return String.format("LwM2mSingleResource [id=%s, value=%s, type=%s]", lwM2mResource.getId(), return String.format("LwM2mSingleResource [id=%s, value=%s, type=%s]", lwM2mResource.getId(),
converter.convertValue(lwM2mResource.getValue(), converter.convertValue(lwM2mResource.getValue(),
OPAQUE, STRING, new LwM2mPath(convertPathFromIdVerToObjectId(pathIdVer))), lwM2mResource.getType().name()); OPAQUE, STRING, new LwM2mPath(fromVersionedIdToObjectId(pathIdVer))), lwM2mResource.getType().name());
} }
} }
public Collection<LwM2mResource> getNewResourceForInstance(String pathRezIdVer, Object params, LwM2mModelProvider modelProvider, public Collection<LwM2mResource> getNewResourceForInstance(String pathRezIdVer, Object params, LwM2mModelProvider modelProvider,
LwM2mValueConverterImpl converter) { LwM2mValueConverterImpl converter) {
LwM2mPath pathIds = new LwM2mPath(convertPathFromIdVerToObjectId(pathRezIdVer)); LwM2mPath pathIds = new LwM2mPath(fromVersionedIdToObjectId(pathRezIdVer));
Collection<LwM2mResource> resources = ConcurrentHashMap.newKeySet(); Collection<LwM2mResource> resources = ConcurrentHashMap.newKeySet();
Map<Integer, ResourceModel> resourceModels = modelProvider.getObjectModel(registration) Map<Integer, ResourceModel> resourceModels = modelProvider.getObjectModel(registration)
.getObjectModel(pathIds.getObjectId()).resources; .getObjectModel(pathIds.getObjectId()).resources;
@ -312,7 +313,7 @@ public class LwM2mClient implements Cloneable {
public Collection<LwM2mResource> getNewResourcesForInstance(String pathRezIdVer, Object params, LwM2mModelProvider modelProvider, public Collection<LwM2mResource> getNewResourcesForInstance(String pathRezIdVer, Object params, LwM2mModelProvider modelProvider,
LwM2mValueConverterImpl converter) { LwM2mValueConverterImpl converter) {
LwM2mPath pathIds = new LwM2mPath(convertPathFromIdVerToObjectId(pathRezIdVer)); LwM2mPath pathIds = new LwM2mPath(fromVersionedIdToObjectId(pathRezIdVer));
Collection<LwM2mResource> resources = ConcurrentHashMap.newKeySet(); Collection<LwM2mResource> resources = ConcurrentHashMap.newKeySet();
Map<Integer, ResourceModel> resourceModels = modelProvider.getObjectModel(registration) Map<Integer, ResourceModel> resourceModels = modelProvider.getObjectModel(registration)
.getObjectModel(pathIds.getObjectId()).resources; .getObjectModel(pathIds.getObjectId()).resources;
@ -328,7 +329,7 @@ public class LwM2mClient implements Cloneable {
} }
public boolean isValidObjectVersion(String path) { public boolean isValidObjectVersion(String path) {
LwM2mPath pathIds = new LwM2mPath(convertPathFromIdVerToObjectId(path)); LwM2mPath pathIds = new LwM2mPath(fromVersionedIdToObjectId(path));
String verSupportedObject = registration.getSupportedObject().get(pathIds.getObjectId()); String verSupportedObject = registration.getSupportedObject().get(pathIds.getObjectId());
String verRez = getVerFromPathIdVerOrId(path); String verRez = getVerFromPathIdVerOrId(path);
return verRez == null ? TRANSPORT_DEFAULT_LWM2M_VERSION.equals(verSupportedObject) : verRez.equals(verSupportedObject); return verRez == null ? TRANSPORT_DEFAULT_LWM2M_VERSION.equals(verSupportedObject) : verRez.equals(verSupportedObject);
@ -341,7 +342,7 @@ public class LwM2mClient implements Cloneable {
public void deleteResources(String pathIdVer, LwM2mModelProvider modelProvider) { public void deleteResources(String pathIdVer, LwM2mModelProvider modelProvider) {
Set<String> key = getKeysEqualsIdVer(pathIdVer); Set<String> key = getKeysEqualsIdVer(pathIdVer);
key.forEach(pathRez -> { key.forEach(pathRez -> {
LwM2mPath pathIds = new LwM2mPath(convertPathFromIdVerToObjectId(pathRez)); LwM2mPath pathIds = new LwM2mPath(fromVersionedIdToObjectId(pathRez));
ResourceModel resourceModel = modelProvider.getObjectModel(registration).getResourceModel(pathIds.getObjectId(), pathIds.getResourceId()); ResourceModel resourceModel = modelProvider.getObjectModel(registration).getResourceModel(pathIds.getObjectId(), pathIds.getResourceId());
if (resourceModel != null) { if (resourceModel != null) {
this.resources.get(pathRez).setResourceModel(resourceModel); this.resources.get(pathRez).setResourceModel(resourceModel);
@ -361,7 +362,7 @@ public class LwM2mClient implements Cloneable {
} }
private void saveResourceModel(String pathRez, LwM2mModelProvider modelProvider) { private void saveResourceModel(String pathRez, LwM2mModelProvider modelProvider) {
LwM2mPath pathIds = new LwM2mPath(convertPathFromIdVerToObjectId(pathRez)); LwM2mPath pathIds = new LwM2mPath(fromVersionedIdToObjectId(pathRez));
ResourceModel resourceModel = modelProvider.getObjectModel(registration).getResourceModel(pathIds.getObjectId(), pathIds.getResourceId()); ResourceModel resourceModel = modelProvider.getObjectModel(registration).getResourceModel(pathIds.getObjectId(), pathIds.getResourceId());
this.resources.get(pathRez).setResourceModel(resourceModel); this.resources.get(pathRez).setResourceModel(resourceModel);
} }
@ -395,16 +396,16 @@ public class LwM2mClient implements Cloneable {
public LwM2mFwSwUpdate getFwUpdate (LwM2mClientContext clientContext) { public LwM2mFwSwUpdate getFwUpdate (LwM2mClientContext clientContext) {
if (this.fwUpdate == null) { if (this.fwUpdate == null) {
LwM2mClientProfile lwM2mClientProfile = clientContext.getProfile(this.getProfileId()); var profile = clientContext.getProfile(this.getProfileId());
this.fwUpdate = new LwM2mFwSwUpdate(this, OtaPackageType.FIRMWARE, lwM2mClientProfile.getFwUpdateStrategy()); this.fwUpdate = new LwM2mFwSwUpdate(this, OtaPackageType.FIRMWARE, profile.getClientLwM2mSettings().getFwUpdateStrategy());
} }
return this.fwUpdate; return this.fwUpdate;
} }
public LwM2mFwSwUpdate getSwUpdate (LwM2mClientContext clientContext) { public LwM2mFwSwUpdate getSwUpdate (LwM2mClientContext clientContext) {
if (this.swUpdate == null) { if (this.swUpdate == null) {
LwM2mClientProfile lwM2mClientProfile = clientContext.getProfile(this.getProfileId()); var profile = clientContext.getProfile(this.getProfileId());
this.swUpdate = new LwM2mFwSwUpdate(this, OtaPackageType.SOFTWARE, lwM2mClientProfile.getSwUpdateStrategy()); this.swUpdate = new LwM2mFwSwUpdate(this, OtaPackageType.SOFTWARE, profile.getClientLwM2mSettings().getSwUpdateStrategy());
} }
return this.fwUpdate; return this.fwUpdate;
} }

14
common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClientContext.java

@ -17,11 +17,12 @@ package org.thingsboard.server.transport.lwm2m.server.client;
import org.eclipse.leshan.server.registration.Registration; import org.eclipse.leshan.server.registration.Registration;
import org.thingsboard.server.common.data.DeviceProfile; import org.thingsboard.server.common.data.DeviceProfile;
import org.thingsboard.server.common.data.device.profile.Lwm2mDeviceProfileTransportConfiguration;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.transport.auth.ValidateDeviceCredentialsResponse; import org.thingsboard.server.common.transport.auth.ValidateDeviceCredentialsResponse;
import org.thingsboard.server.gen.transport.TransportProtos; import org.thingsboard.server.gen.transport.TransportProtos;
import java.util.Collection; import java.util.Collection;
import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.UUID; import java.util.UUID;
@ -41,15 +42,12 @@ public interface LwM2mClientContext {
Collection<LwM2mClient> getLwM2mClients(); Collection<LwM2mClient> getLwM2mClients();
Map<UUID, LwM2mClientProfile> getProfiles(); //TODO: replace UUID with DeviceProfileId
Lwm2mDeviceProfileTransportConfiguration getProfile(UUID profileUuId);
LwM2mClientProfile getProfile(UUID profileUuId); Lwm2mDeviceProfileTransportConfiguration getProfile(Registration registration);
LwM2mClientProfile getProfile(Registration registration); Lwm2mDeviceProfileTransportConfiguration profileUpdate(DeviceProfile deviceProfile);
Map<UUID, LwM2mClientProfile> setProfiles(Map<UUID, LwM2mClientProfile> profiles);
LwM2mClientProfile profileUpdate(DeviceProfile deviceProfile);
Set<String> getSupportedIdVerInClient(LwM2mClient registration); Set<String> getSupportedIdVerInClient(LwM2mClient registration);

40
common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClientContextImpl.java

@ -21,6 +21,7 @@ import org.eclipse.leshan.core.node.LwM2mPath;
import org.eclipse.leshan.server.registration.Registration; import org.eclipse.leshan.server.registration.Registration;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.thingsboard.server.common.data.DeviceProfile; import org.thingsboard.server.common.data.DeviceProfile;
import org.thingsboard.server.common.data.device.profile.Lwm2mDeviceProfileTransportConfiguration;
import org.thingsboard.server.common.transport.auth.ValidateDeviceCredentialsResponse; import org.thingsboard.server.common.transport.auth.ValidateDeviceCredentialsResponse;
import org.thingsboard.server.gen.transport.TransportProtos; import org.thingsboard.server.gen.transport.TransportProtos;
import org.thingsboard.server.queue.util.TbLwM2mTransportComponent; import org.thingsboard.server.queue.util.TbLwM2mTransportComponent;
@ -50,7 +51,7 @@ public class LwM2mClientContextImpl implements LwM2mClientContext {
private final TbEditableSecurityStore securityStore; private final TbEditableSecurityStore securityStore;
private final Map<String, LwM2mClient> lwM2mClientsByEndpoint = new ConcurrentHashMap<>(); private final Map<String, LwM2mClient> lwM2mClientsByEndpoint = new ConcurrentHashMap<>();
private final Map<String, LwM2mClient> lwM2mClientsByRegistrationId = new ConcurrentHashMap<>(); private final Map<String, LwM2mClient> lwM2mClientsByRegistrationId = new ConcurrentHashMap<>();
private Map<UUID, LwM2mClientProfile> profiles = new ConcurrentHashMap<>(); private final Map<UUID, Lwm2mDeviceProfileTransportConfiguration> profiles = new ConcurrentHashMap<>();
@Override @Override
public LwM2mClient getClientByEndpoint(String endpoint) { public LwM2mClient getClientByEndpoint(String endpoint) {
@ -67,11 +68,11 @@ public class LwM2mClientContextImpl implements LwM2mClientContext {
TbLwM2MSecurityInfo securityInfo = securityStore.getTbLwM2MSecurityInfoByEndpoint(lwM2MClient.getEndpoint()); TbLwM2MSecurityInfo securityInfo = securityStore.getTbLwM2MSecurityInfoByEndpoint(lwM2MClient.getEndpoint());
if (securityInfo.getSecurityMode() != null) { if (securityInfo.getSecurityMode() != null) {
if (securityInfo.getDeviceProfile() != null) { if (securityInfo.getDeviceProfile() != null) {
UUID profileUuid = profileUpdate(securityInfo.getDeviceProfile()) != null ? securityInfo.getDeviceProfile().getUuidId() : null; profileUpdate(securityInfo.getDeviceProfile());
if (securityInfo.getSecurityInfo() != null) { if (securityInfo.getSecurityInfo() != null) {
lwM2MClient.init(securityInfo.getSecurityInfo().getIdentity(), securityInfo.getSecurityInfo(), securityInfo.getMsg(), profileUuid, UUID.randomUUID()); lwM2MClient.init(securityInfo.getSecurityInfo().getIdentity(), securityInfo.getSecurityInfo(), securityInfo.getMsg(), UUID.randomUUID());
} else if (NO_SEC.equals(securityInfo.getSecurityMode())) { } else if (NO_SEC.equals(securityInfo.getSecurityMode())) {
lwM2MClient.init(null, null, securityInfo.getMsg(), profileUuid, UUID.randomUUID()); lwM2MClient.init(null, null, securityInfo.getMsg(), UUID.randomUUID());
} else { } else {
throw new RuntimeException(String.format("Registration failed: device %s not found.", lwM2MClient.getEndpoint())); throw new RuntimeException(String.format("Registration failed: device %s not found.", lwM2MClient.getEndpoint()));
} }
@ -157,7 +158,7 @@ public class LwM2mClientContextImpl implements LwM2mClientContext {
@Override @Override
public void registerClient(Registration registration, ValidateDeviceCredentialsResponse credentials) { public void registerClient(Registration registration, ValidateDeviceCredentialsResponse credentials) {
LwM2mClient client = getClientByEndpoint(registration.getEndpoint()); LwM2mClient client = getClientByEndpoint(registration.getEndpoint());
client.init(null, null, credentials, credentials.getDeviceProfile().getUuidId(), UUID.randomUUID()); client.init(null, null, credentials, UUID.randomUUID());
lwM2mClientsByRegistrationId.put(registration.getId(), client); lwM2mClientsByRegistrationId.put(registration.getId(), client);
profileUpdate(credentials.getDeviceProfile()); profileUpdate(credentials.getDeviceProfile());
} }
@ -168,35 +169,20 @@ public class LwM2mClientContextImpl implements LwM2mClientContext {
} }
@Override @Override
public Map<UUID, LwM2mClientProfile> getProfiles() { public Lwm2mDeviceProfileTransportConfiguration getProfile(UUID profileId) {
return profiles;
}
@Override
public LwM2mClientProfile getProfile(UUID profileId) {
return profiles.get(profileId); return profiles.get(profileId);
} }
@Override @Override
public LwM2mClientProfile getProfile(Registration registration) { public Lwm2mDeviceProfileTransportConfiguration getProfile(Registration registration) {
return this.getProfiles().get(getClientByEndpoint(registration.getEndpoint()).getProfileId()); return profiles.get(getClientByEndpoint(registration.getEndpoint()).getProfileId());
} }
@Override @Override
public Map<UUID, LwM2mClientProfile> setProfiles(Map<UUID, LwM2mClientProfile> profiles) { public Lwm2mDeviceProfileTransportConfiguration profileUpdate(DeviceProfile deviceProfile) {
return this.profiles = profiles; Lwm2mDeviceProfileTransportConfiguration lwM2MClientProfile = LwM2mTransportUtil.toLwM2MClientProfile(deviceProfile);
} profiles.put(deviceProfile.getUuidId(), lwM2MClientProfile);
return lwM2MClientProfile;
@Override
public LwM2mClientProfile profileUpdate(DeviceProfile deviceProfile) {
LwM2mClientProfile lwM2MClientProfile = deviceProfile != null ?
LwM2mTransportUtil.toLwM2MClientProfile(deviceProfile) : null;
if (lwM2MClientProfile != null) {
profiles.put(deviceProfile.getUuidId(), lwM2MClientProfile);
return lwM2MClientProfile;
} else {
return null;
}
} }
@Override @Override

113
common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClientProfile.java

@ -1,113 +0,0 @@
/**
* Copyright © 2016-2021 The Thingsboard Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.transport.lwm2m.server.client;
import com.google.gson.Gson;
import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
import lombok.Data;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LwM2MClientStrategy;
import org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LwM2MFirmwareUpdateStrategy;
import org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LwM2MSoftwareUpdateStrategy;
@Data
public class LwM2mClientProfile {
private final String clientStrategyStr = "clientStrategy";
private final String fwUpdateStrategyStr = "fwUpdateStrategy";
private final String swUpdateStrategyStr = "swUpdateStrategy";
private TenantId tenantId;
/**
* "clientLwM2mSettings": {
* "fwUpdateStrategy": "1",
* "swUpdateStrategy": "1",
* "clientStrategy": "1"
* }
**/
private JsonObject postClientLwM2mSettings;
/**
* {"keyName": {
* "/3_1.0/0/1": "modelNumber",
* "/3_1.0/0/0": "manufacturer",
* "/3_1.0/0/2": "serialNumber"
* }
**/
private JsonObject postKeyNameProfile;
/**
* [ "/3_1.0/0/0", "/3_1.0/0/1"]
*/
private JsonArray postAttributeProfile;
/**
* [ "/3_1.0/0/0", "/3_1.0/0/2"]
*/
private JsonArray postTelemetryProfile;
/**
* [ "/3_1.0/0", "/3_1.0/0/1, "/3_1.0/0/2"]
*/
private JsonArray postObserveProfile;
/**
* "attributeLwm2m": {"/3_1.0": {"ver": "currentTimeTest11"},
* "/3_1.0/0": {"gt": 17},
* "/3_1.0/0/9": {"pmax": 45}, "/3_1.2": {ver": "3_1.2"}}
*/
private JsonObject postAttributeLwm2mProfile;
public LwM2mClientProfile clone() {
LwM2mClientProfile lwM2mClientProfile = new LwM2mClientProfile();
lwM2mClientProfile.postClientLwM2mSettings = this.deepCopy(this.postClientLwM2mSettings, JsonObject.class);
lwM2mClientProfile.postKeyNameProfile = this.deepCopy(this.postKeyNameProfile, JsonObject.class);
lwM2mClientProfile.postAttributeProfile = this.deepCopy(this.postAttributeProfile, JsonArray.class);
lwM2mClientProfile.postTelemetryProfile = this.deepCopy(this.postTelemetryProfile, JsonArray.class);
lwM2mClientProfile.postObserveProfile = this.deepCopy(this.postObserveProfile, JsonArray.class);
lwM2mClientProfile.postAttributeLwm2mProfile = this.deepCopy(this.postAttributeLwm2mProfile, JsonObject.class);
return lwM2mClientProfile;
}
private <T> T deepCopy(T elements, Class<T> type) {
try {
Gson gson = new Gson();
return gson.fromJson(gson.toJson(elements), type);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
public int getClientStrategy() {
return this.postClientLwM2mSettings.getAsJsonObject().has(this.clientStrategyStr) ?
Integer.parseInt(this.postClientLwM2mSettings.getAsJsonObject().get(this.clientStrategyStr).getAsString()) :
LwM2MClientStrategy.CLIENT_STRATEGY_1.code;
}
public int getFwUpdateStrategy() {
return this.postClientLwM2mSettings.getAsJsonObject().has(this.fwUpdateStrategyStr) ?
Integer.parseInt(this.postClientLwM2mSettings.getAsJsonObject().get(this.fwUpdateStrategyStr).getAsString()) :
LwM2MFirmwareUpdateStrategy.OBJ_5_BINARY.code;
}
public int getSwUpdateStrategy() {
return this.postClientLwM2mSettings.getAsJsonObject().has(this.swUpdateStrategyStr) ?
Integer.parseInt(this.postClientLwM2mSettings.getAsJsonObject().get(this.swUpdateStrategyStr).getAsString()) :
LwM2MSoftwareUpdateStrategy.BINARY.code;
}
}

10
common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClientRpcRequest.java

@ -52,7 +52,7 @@ import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.S
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.START_JSON_KEY; import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.START_JSON_KEY;
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.TARGET_ID_VER_KEY; import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.TARGET_ID_VER_KEY;
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.VALUE_KEY; import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.VALUE_KEY;
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.convertPathFromIdVerToObjectId; import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.fromVersionedIdToObjectId;
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.validPathIdVer; import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.validPathIdVer;
@Slf4j @Slf4j
@ -152,8 +152,8 @@ public class LwM2mClientRpcRequest {
else if (this.getTargetIdVer() != null else if (this.getTargetIdVer() != null
&& (EXECUTE == this.getTypeOper() && (EXECUTE == this.getTypeOper()
|| WRITE_REPLACE == this.getTypeOper()) || WRITE_REPLACE == this.getTypeOper())
&& !(new LwM2mPath(Objects.requireNonNull(convertPathFromIdVerToObjectId(this.getTargetIdVer()))).isResource() && !(new LwM2mPath(Objects.requireNonNull(fromVersionedIdToObjectId(this.getTargetIdVer()))).isResource()
|| new LwM2mPath(Objects.requireNonNull(convertPathFromIdVerToObjectId(this.getTargetIdVer()))).isResourceInstance())) { || new LwM2mPath(Objects.requireNonNull(fromVersionedIdToObjectId(this.getTargetIdVer()))).isResourceInstance())) {
this.setErrorMsg("Invalid parameter " + TARGET_ID_VER_KEY this.setErrorMsg("Invalid parameter " + TARGET_ID_VER_KEY
+ ". Only Resource or ResourceInstance can be this operation"); + ". Only Resource or ResourceInstance can be this operation");
} }
@ -247,7 +247,7 @@ public class LwM2mClientRpcRequest {
private ConcurrentHashMap<String, Object> convertParamsToResourceId(ConcurrentHashMap<String, Object> params, private ConcurrentHashMap<String, Object> convertParamsToResourceId(ConcurrentHashMap<String, Object> params,
DefaultLwM2MUplinkMsgHandler serviceImpl) { DefaultLwM2MUplinkMsgHandler serviceImpl) {
Map<String, Object> paramsIdVer = new ConcurrentHashMap<>(); Map<String, Object> paramsIdVer = new ConcurrentHashMap<>();
LwM2mPath targetId = new LwM2mPath(Objects.requireNonNull(convertPathFromIdVerToObjectId(this.targetIdVer))); LwM2mPath targetId = new LwM2mPath(Objects.requireNonNull(fromVersionedIdToObjectId(this.targetIdVer)));
if (targetId.isObjectInstance()) { if (targetId.isObjectInstance()) {
params.forEach((k, v) -> { params.forEach((k, v) -> {
try { try {
@ -256,7 +256,7 @@ public class LwM2mClientRpcRequest {
} catch (NumberFormatException e) { } catch (NumberFormatException e) {
String targetIdVer = serviceImpl.getPresentPathIntoProfile(sessionInfo, k); String targetIdVer = serviceImpl.getPresentPathIntoProfile(sessionInfo, k);
if (targetIdVer != null) { if (targetIdVer != null) {
LwM2mPath lwM2mPath = new LwM2mPath(Objects.requireNonNull(convertPathFromIdVerToObjectId(targetIdVer))); LwM2mPath lwM2mPath = new LwM2mPath(Objects.requireNonNull(fromVersionedIdToObjectId(targetIdVer)));
paramsIdVer.put(String.valueOf(lwM2mPath.getResourceId()), v); paramsIdVer.put(String.valueOf(lwM2mPath.getResourceId()), v);
} }
/** WRITE_UPDATE*/ /** WRITE_UPDATE*/

4
common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/ResultsAnalyzerParameters.java → common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/ParametersAnalyzeResult.java

@ -21,11 +21,11 @@ import java.util.Set;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
@Data @Data
public class ResultsAnalyzerParameters { public class ParametersAnalyzeResult {
Set<String> pathPostParametersAdd; Set<String> pathPostParametersAdd;
Set<String> pathPostParametersDel; Set<String> pathPostParametersDel;
public ResultsAnalyzerParameters() { public ParametersAnalyzeResult() {
this.pathPostParametersAdd = ConcurrentHashMap.newKeySet(); this.pathPostParametersAdd = ConcurrentHashMap.newKeySet();
this.pathPostParametersDel = ConcurrentHashMap.newKeySet(); this.pathPostParametersDel = ConcurrentHashMap.newKeySet();
} }
Loading…
Cancel
Save