diff --git a/application/src/main/java/org/thingsboard/server/controller/BaseController.java b/application/src/main/java/org/thingsboard/server/controller/BaseController.java index 64100363e4..7e8e3800f7 100644 --- a/application/src/main/java/org/thingsboard/server/controller/BaseController.java +++ b/application/src/main/java/org/thingsboard/server/controller/BaseController.java @@ -126,7 +126,6 @@ import org.thingsboard.server.service.component.ComponentDiscoveryService; import org.thingsboard.server.service.edge.EdgeLicenseService; import org.thingsboard.server.service.edge.EdgeNotificationService; import org.thingsboard.server.service.edge.rpc.EdgeRpcService; -import org.thingsboard.server.service.lwm2m.LwM2MServiceImpl; import org.thingsboard.server.service.ota.OtaPackageStateService; import org.thingsboard.server.service.profile.TbDeviceProfileCache; import org.thingsboard.server.service.resource.TbResourceService; @@ -185,9 +184,6 @@ public abstract class BaseController { @Autowired protected DeviceProfileService deviceProfileService; - @Autowired - protected LwM2MServiceImpl lwM2MService; - @Autowired protected AssetService assetService; diff --git a/application/src/main/java/org/thingsboard/server/controller/Lwm2mController.java b/application/src/main/java/org/thingsboard/server/controller/Lwm2mController.java index fb71d4ea91..12cc60c4e2 100644 --- a/application/src/main/java/org/thingsboard/server/controller/Lwm2mController.java +++ b/application/src/main/java/org/thingsboard/server/controller/Lwm2mController.java @@ -17,6 +17,7 @@ package org.thingsboard.server.controller; import com.fasterxml.jackson.databind.ObjectMapper; import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestBody; @@ -31,6 +32,7 @@ import org.thingsboard.server.common.data.exception.ThingsboardException; import org.thingsboard.server.common.data.lwm2m.ServerSecurityConfig; import org.thingsboard.server.common.data.security.DeviceCredentials; import org.thingsboard.server.queue.util.TbCoreComponent; +import org.thingsboard.server.service.lwm2m.LwM2MServiceImpl; import org.thingsboard.server.service.security.permission.Resource; import java.util.Map; @@ -41,6 +43,9 @@ import java.util.Map; @RequestMapping("/api") public class Lwm2mController extends BaseController { + @Autowired + protected LwM2MServiceImpl lwM2MService; + @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") @RequestMapping(value = "/lwm2m/deviceProfile/bootstrap/{isBootstrapServer}", method = RequestMethod.GET) @ResponseBody diff --git a/application/src/main/resources/thingsboard.yml b/application/src/main/resources/thingsboard.yml index 95ba839792..61df401a94 100644 --- a/application/src/main/resources/thingsboard.yml +++ b/application/src/main/resources/thingsboard.yml @@ -693,6 +693,8 @@ transport: ota_pool_size: "${LWM2M_OTA_POOL_SIZE:10}" clean_period_in_sec: "${LWM2M_CLEAN_PERIOD_IN_SEC:2}" log_max_length: "${LWM2M_LOG_MAX_LENGTH:1024}" + psm_activity_timer: "${LWM2M_PSM_ACTIVITY_TIMER:10000}" + paging_transmission_window: "${LWM2M_PAGING_TRANSMISSION_WINDOW:10000}" # Use redis for Security and Registration stores redis.enabled: "${LWM2M_REDIS_ENABLED:false}" snmp: diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/client/FwLwM2MDevice.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/client/FwLwM2MDevice.java index e95f3d4841..cc097c869d 100644 --- a/application/src/test/java/org/thingsboard/server/transport/lwm2m/client/FwLwM2MDevice.java +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/client/FwLwM2MDevice.java @@ -83,7 +83,7 @@ public class FwLwM2MDevice extends BaseInstanceEnabler implements Destroyable { @Override public WriteResponse write(ServerIdentity identity, boolean replace, int resourceId, LwM2mResource value) { - log.warn("Write on Device resource /{}/{}/{}", getModel().id, getId(), resourceId); + log.info("Write on Device resource /{}/{}/{}", getModel().id, getId(), resourceId); switch (resourceId) { case 0: diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/client/SwLwM2MDevice.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/client/SwLwM2MDevice.java index dc6ad348a3..4b1e02a68d 100644 --- a/application/src/test/java/org/thingsboard/server/transport/lwm2m/client/SwLwM2MDevice.java +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/client/SwLwM2MDevice.java @@ -83,7 +83,7 @@ public class SwLwM2MDevice extends BaseInstanceEnabler implements Destroyable { @Override public WriteResponse write(ServerIdentity identity, boolean replace, int resourceId, LwM2mResource value) { - log.warn("Write on Device resource /{}/{}/{}", getModel().id, getId(), resourceId); + log.info("Write on Device resource /{}/{}/{}", getModel().id, getId(), resourceId); switch (resourceId) { case 2: diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/security/DeviceCredentials.java b/common/data/src/main/java/org/thingsboard/server/common/data/security/DeviceCredentials.java index 4ccf07f2b0..74adcdd06a 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/security/DeviceCredentials.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/security/DeviceCredentials.java @@ -15,9 +15,6 @@ */ package org.thingsboard.server.common.data.security; -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.ObjectMapper; import lombok.EqualsAndHashCode; import org.thingsboard.server.common.data.BaseData; import org.thingsboard.server.common.data.id.DeviceCredentialsId; diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2MBootstrapConfig.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2MBootstrapConfig.java index ab96228600..f2ba39dcfa 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2MBootstrapConfig.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2MBootstrapConfig.java @@ -17,6 +17,8 @@ package org.thingsboard.server.transport.lwm2m.bootstrap.secure; import com.fasterxml.jackson.annotation.JsonIgnore; import lombok.Data; +import lombok.Getter; +import lombok.Setter; import org.eclipse.leshan.core.SecurityMode; import org.eclipse.leshan.core.request.BindingMode; import org.eclipse.leshan.core.util.Hex; @@ -41,7 +43,9 @@ public class LwM2MBootstrapConfig implements Serializable { * notifIfDisabled: boolean, * binding: string * */ - LwM2MBootstrapServers servers; + @Getter + @Setter + private LwM2MBootstrapServers servers; /** -bootstrapServer, lwm2mServer * interface ServerSecurityConfig @@ -56,9 +60,13 @@ public class LwM2MBootstrapConfig implements Serializable { * serverId?: number, * bootstrapServerAccountTimeout: number * */ - LwM2MServerBootstrap bootstrapServer; + @Getter + @Setter + private LwM2MServerBootstrap bootstrapServer; - LwM2MServerBootstrap lwm2mServer; + @Getter + @Setter + private LwM2MServerBootstrap lwm2mServer; @JsonIgnore public BootstrapConfig getLwM2MBootstrapConfig() { diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2MBootstrapSecurityStore.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2MBootstrapSecurityStore.java index c59f7467a9..bf5f40f055 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2MBootstrapSecurityStore.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2MBootstrapSecurityStore.java @@ -43,11 +43,11 @@ import java.util.Map; import java.util.UUID; import java.util.concurrent.ConcurrentHashMap; +import static org.thingsboard.server.transport.lwm2m.server.uplink.LwM2mTypeServer.BOOTSTRAP; import static org.thingsboard.server.transport.lwm2m.utils.LwM2mTransportUtil.LOG_LWM2M_ERROR; import static org.thingsboard.server.transport.lwm2m.utils.LwM2mTransportUtil.LOG_LWM2M_INFO; import static org.thingsboard.server.transport.lwm2m.utils.LwM2mTransportUtil.LOG_LWM2M_TELEMETRY; import static org.thingsboard.server.transport.lwm2m.utils.LwM2mTransportUtil.getBootstrapParametersFromThingsboard; -import static org.thingsboard.server.transport.lwm2m.server.uplink.LwM2mTypeServer.BOOTSTRAP; @Slf4j @Service("LwM2MBootstrapSecurityStore") @@ -86,10 +86,10 @@ public class LwM2MBootstrapSecurityStore implements BootstrapSecurityStore { bootstrapConfigStore.add(endPoint, bsConfigNew); } catch (InvalidConfigurationException e) { if (e.getMessage().contains("Psk identity") && e.getMessage().contains("already used for this bootstrap server")) { - log.trace("", e); + log.trace("Invalid Bootstrap Configuration", e); } else { - log.error("", e); + log.error("Invalid Bootstrap Configuration", e); } } return store.getSecurityInfo() == null ? null : Collections.singletonList(store.getSecurityInfo()).iterator(); @@ -109,7 +109,7 @@ public class LwM2MBootstrapSecurityStore implements BootstrapSecurityStore { try { bootstrapConfigStore.add(store.getEndpoint(), bsConfig); } catch (InvalidConfigurationException e) { - log.error("", e); + log.error("Invalid Bootstrap Configuration", e); } return store.getSecurityInfo(); } @@ -158,11 +158,11 @@ public class LwM2MBootstrapSecurityStore implements BootstrapSecurityStore { LwM2MBootstrapConfig lwM2MBootstrapConfig = store.getBootstrapCredentialConfig(); if (lwM2MBootstrapConfig != null) { BootstrapConfiguration bootstrapObject = getBootstrapParametersFromThingsboard(store.getDeviceProfile()); - lwM2MBootstrapConfig.servers = JacksonUtil.fromString(JacksonUtil.toString(bootstrapObject.getServers()), LwM2MBootstrapServers.class); - LwM2MServerBootstrap profileServerBootstrap = JacksonUtil.fromString(JacksonUtil.toString(bootstrapObject.getBootstrapServer()), LwM2MServerBootstrap.class); - if (SecurityMode.NO_SEC != profileServerBootstrap.getSecurityMode() && profileServerBootstrap != null) { - profileServerBootstrap.setSecurityHost( profileServerBootstrap.getHost()); - profileServerBootstrap.setSecurityPort( profileServerBootstrap.getPort()); + lwM2MBootstrapConfig.setServers(JacksonUtil.fromString(JacksonUtil.toString(bootstrapObject.getServers()), LwM2MBootstrapServers.class)); + LwM2MServerBootstrap bootstrapServerProfile = JacksonUtil.fromString(JacksonUtil.toString(bootstrapObject.getBootstrapServer()), LwM2MServerBootstrap.class); + if (SecurityMode.NO_SEC != bootstrapServerProfile.getSecurityMode() && bootstrapServerProfile != null) { + bootstrapServerProfile.setSecurityHost( bootstrapServerProfile.getHost()); + bootstrapServerProfile.setSecurityPort( bootstrapServerProfile.getPort()); } LwM2MServerBootstrap profileLwm2mServer = JacksonUtil.fromString(JacksonUtil.toString(bootstrapObject.getLwm2mServer()), LwM2MServerBootstrap.class); if (SecurityMode.NO_SEC != profileLwm2mServer.getSecurityMode() && profileLwm2mServer != null) { @@ -173,9 +173,9 @@ public class LwM2MBootstrapSecurityStore implements BootstrapSecurityStore { TransportProtos.SessionInfoProto sessionInfo = helper.getValidateSessionInfo(store.getMsg(), sessionUUiD.getMostSignificantBits(), sessionUUiD.getLeastSignificantBits()); bsSessions.put(store.getEndpoint(), sessionInfo); context.getTransportService().registerAsyncSession(sessionInfo, new LwM2mSessionMsgListener(null, null, null, sessionInfo, context.getTransportService())); - if (this.getValidatedSecurityMode(lwM2MBootstrapConfig.bootstrapServer, profileServerBootstrap, lwM2MBootstrapConfig.lwm2mServer, profileLwm2mServer)) { - lwM2MBootstrapConfig.bootstrapServer = new LwM2MServerBootstrap(lwM2MBootstrapConfig.bootstrapServer, profileServerBootstrap); - lwM2MBootstrapConfig.lwm2mServer = new LwM2MServerBootstrap(lwM2MBootstrapConfig.lwm2mServer, profileLwm2mServer); + if (this.getValidatedSecurityMode(lwM2MBootstrapConfig.getBootstrapServer(), bootstrapServerProfile, lwM2MBootstrapConfig.getLwm2mServer(), profileLwm2mServer)) { + lwM2MBootstrapConfig.setBootstrapServer(new LwM2MServerBootstrap(lwM2MBootstrapConfig.getBootstrapServer(), bootstrapServerProfile)); + lwM2MBootstrapConfig.setLwm2mServer(new LwM2MServerBootstrap(lwM2MBootstrapConfig.getLwm2mServer(), profileLwm2mServer)); String logMsg = String.format("%s: getParametersBootstrap: %s Access connect client with bootstrap server.", LOG_LWM2M_INFO, store.getEndpoint()); helper.sendParametersOnThingsboardTelemetry(helper.getKvStringtoThingsboard(LOG_LWM2M_TELEMETRY, logMsg), sessionInfo); return lwM2MBootstrapConfig; @@ -187,7 +187,6 @@ public class LwM2MBootstrapSecurityStore implements BootstrapSecurityStore { return null; } } - log.error("Unable to decode Json or Certificate for [{}]", store.getEndpoint()); return null; } @@ -197,13 +196,13 @@ public class LwM2MBootstrapSecurityStore implements BootstrapSecurityStore { * and (lwm2mServer in credential and lwm2mServer in profile * * @param bootstrapFromCredential - Bootstrap -> Security of bootstrapServer in credential - * @param profileServerBootstrap - Bootstrap -> Security of bootstrapServer in profile + * @param bootstrapServerProfile - Bootstrap -> Security of bootstrapServer in profile * @param lwm2mFromCredential - Bootstrap -> Security of lwm2mServer in credential * @param profileLwm2mServer - Bootstrap -> Security of lwm2mServer in profile * @return false if not sync between SecurityMode of Bootstrap credential and profile */ - private boolean getValidatedSecurityMode(LwM2MServerBootstrap bootstrapFromCredential, LwM2MServerBootstrap profileServerBootstrap, LwM2MServerBootstrap lwm2mFromCredential, LwM2MServerBootstrap profileLwm2mServer) { - return (bootstrapFromCredential.getSecurityMode().equals(profileServerBootstrap.getSecurityMode()) && + private boolean getValidatedSecurityMode(LwM2MServerBootstrap bootstrapFromCredential, LwM2MServerBootstrap bootstrapServerProfile, LwM2MServerBootstrap lwm2mFromCredential, LwM2MServerBootstrap profileLwm2mServer) { + return (bootstrapFromCredential.getSecurityMode().equals(bootstrapServerProfile.getSecurityMode()) && lwm2mFromCredential.getSecurityMode().equals(profileLwm2mServer.getSecurityMode())); } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2mDefaultBootstrapSessionManager.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2mDefaultBootstrapSessionManager.java index da5e8db695..4ad8a95108 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2mDefaultBootstrapSessionManager.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2mDefaultBootstrapSessionManager.java @@ -200,21 +200,20 @@ public class LwM2mDefaultBootstrapSessionManager extends DefaultBootstrapSession public BootstrapPolicy onRequestFailure(BootstrapSession bsSession, BootstrapDownlinkRequest request, Throwable cause) { this.sendLogs (bsSession.getEndpoint(), - String.format("%s: %s %s failed because of %s for %s : %s", LOG_LWM2M_INFO, - request.getClass().getSimpleName(), request.getPath().toString(), cause.toString(), bsSession.toString(), request.toString())); + String.format("%s: %s %s failed because of %s for %s : %s", LOG_LWM2M_INFO, request.getClass().getSimpleName(), + request.getPath().toString(), cause.toString(), bsSession.toString(), request.toString())); return BootstrapPolicy.failed(); } @Override public void end(BootstrapSession bsSession) { - this.sendLogs (bsSession.getEndpoint(), - String.format("%s: Bootstrap session finished : %s", LOG_LWM2M_INFO, bsSession.toString())); + this.sendLogs (bsSession.getEndpoint(), String.format("%s: Bootstrap session finished : %s", LOG_LWM2M_INFO, bsSession.toString())); } @Override public void failed(BootstrapSession bsSession, BootstrapFailureCause cause) { - this.sendLogs (bsSession.getEndpoint(), - String.format("%s: Bootstrap session failed by %s: %s", LOG_LWM2M_INFO, cause.toString(), bsSession.toString())); + this.sendLogs (bsSession.getEndpoint(), String.format("%s: Bootstrap session failed by %s: %s", LOG_LWM2M_INFO, + cause.toString(), bsSession.toString())); } private void sendLogs (String endpointName, String logMsg) { diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mOperationType.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mOperationType.java index 7ac959605a..ff0e431649 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mOperationType.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mOperationType.java @@ -50,16 +50,13 @@ public enum LwM2mOperationType { WRITE_COMPOSITE(14, "WriteComposite", false, true), WRITE_ATTRIBUTES(15, "WriteAttributes", true), DELETE(16, "Delete", true), - - // only for RPC - FW_UPDATE(17, "FirmwareUpdate", false), - // FW_READ_INFO(18, "FirmwareReadInfo", false), - SW_UPDATE(19, "SoftwareUpdate", false), - // SW_READ_INFO(20, "SoftwareReadInfo", false), - SW_UNINSTALL(21, "SoftwareUninstall", false), - CREATE(11, "Create", true); - - + CREATE(17, "Create", true); + // only for RPC - future +// FW_UPDATE(18, "FirmwareUpdate", false), +// FW_READ_INFO(19, "FirmwareReadInfo", false), +// SW_UPDATE(20, "SoftwareUpdate", false), +// SW_READ_INFO(21, "SoftwareReadInfo", false), +// SW_UNINSTALL(22, "SoftwareUninstall", false); @Getter diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mServerListener.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mServerListener.java index 8c8624fcf3..3ffc41c8ca 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mServerListener.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mServerListener.java @@ -98,7 +98,9 @@ public class LwM2mServerListener { @Override public void onError(Observation observation, Registration registration, Exception error) { - log.error("Unable to handle notification of [{}:{}] [{}]", observation.getRegistrationId(), observation.getPath(), error.getMessage()); + if (error != null) { + log.debug("Unable to handle notification of [{}:{}] [{}]", observation.getRegistrationId(), observation.getPath(), error.getMessage()); + } } @Override diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mTransportServerHelper.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mTransportServerHelper.java index 81278824e6..136f95dd35 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mTransportServerHelper.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mTransportServerHelper.java @@ -51,7 +51,7 @@ import static org.thingsboard.server.gen.transport.TransportProtos.KeyValueType. public class LwM2mTransportServerHelper { private final LwM2mTransportContext context; - private final static JsonParser JSON_PARSER = new JsonParser();; + private final static JsonParser JSON_PARSER = new JsonParser(); public void sendParametersOnThingsboardAttribute(List result, SessionInfoProto sessionInfo) { PostAttributeMsg.Builder request = PostAttributeMsg.newBuilder(); @@ -231,7 +231,11 @@ public class LwM2mTransportServerHelper { case STRING_V: return kv.getStringV(); case JSON_V: - return JSON_PARSER.parse(kv.getJsonV()); + try { + return JSON_PARSER.parse(kv.getJsonV()); + } catch (Exception e) { + return null; + } } return null; } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/attributes/DefaultLwM2MAttributesService.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/attributes/DefaultLwM2MAttributesService.java index dfe5146017..f7df2ee658 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/attributes/DefaultLwM2MAttributesService.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/attributes/DefaultLwM2MAttributesService.java @@ -40,7 +40,6 @@ import org.thingsboard.server.transport.lwm2m.server.downlink.LwM2mDownlinkMsgHa import org.thingsboard.server.transport.lwm2m.server.downlink.TbLwM2MWriteReplaceRequest; import org.thingsboard.server.transport.lwm2m.server.downlink.TbLwM2MWriteResponseCallback; import org.thingsboard.server.transport.lwm2m.server.log.LwM2MTelemetryLogService; -import org.thingsboard.server.transport.lwm2m.server.ota.DefaultLwM2MOtaUpdateService; import org.thingsboard.server.transport.lwm2m.server.ota.LwM2MOtaUpdateService; import org.thingsboard.server.transport.lwm2m.server.uplink.LwM2mUplinkMsgHandler; import org.thingsboard.server.transport.lwm2m.utils.LwM2mValueConverterImpl; @@ -225,7 +224,7 @@ public class DefaultLwM2MAttributesService implements LwM2MAttributesService { this.pushUpdateToClientIfNeeded(lwM2MClient, oldResourceValue, newValProto, pathIdVer, logFailedUpdateOfNonChangedValue, resourceModel.type); } else { pushUpdateMultiToClientIfNeeded(lwM2MClient, resourceModel, (JsonElement) newValProto, - (Map) oldResourceValue, pathIdVer); + (Map) oldResourceValue, pathIdVer, logFailedUpdateOfNonChangedValue); } }); } @@ -251,7 +250,7 @@ public class DefaultLwM2MAttributesService implements LwM2MAttributesService { } private void pushUpdateMultiToClientIfNeeded(LwM2mClient client, ResourceModel resourceModel, JsonElement newValProto, - Map valueOld, String versionedId) { + Map valueOld, String versionedId, boolean logFailedUpdateOfNonChangedValue) { Map newValues = convertMultiResourceValuesFromJson((JsonObject) newValProto, resourceModel.type, versionedId); if (newValues.size() > 0 && valueOld != null && valueOld.size() > 0) { valueOld.values().stream().forEach((v) -> { @@ -272,7 +271,7 @@ public class DefaultLwM2MAttributesService implements LwM2MAttributesService { if (newValues.size() > 0) { TbLwM2MWriteReplaceRequest request = TbLwM2MWriteReplaceRequest.builder().versionedId(versionedId).value(newValues).timeout(this.config.getTimeout()).build(); downlinkHandler.sendWriteReplaceRequest(client, request, new TbLwM2MWriteResponseCallback(uplinkHandler, logService, client, versionedId)); - } else { + } else if (logFailedUpdateOfNonChangedValue) { log.warn("Didn't update resource [{}] [{}]", versionedId, newValProto); String logMsg = String.format("%s: Didn't update resource versionedId - %s value - %s. Value is not changed", LOG_LWM2M_WARN, versionedId, newValProto); diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClient.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClient.java index 048bc046aa..33b1972fa9 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClient.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClient.java @@ -46,7 +46,6 @@ import java.io.Serializable; import java.util.Arrays; import java.util.Collection; import java.util.HashSet; -import java.util.LinkedHashMap; import java.util.Map; import java.util.Optional; import java.util.Set; @@ -106,7 +105,6 @@ public class LwM2mClient implements Serializable { @Getter private Long pagingTransmissionWindow; @Getter - @Setter private Long edrxCycle; @Getter private Registration registration; @@ -122,9 +120,9 @@ public class LwM2mClient implements Serializable { private boolean firstEdrxDownlink = true; @Getter - Set clientSupportContentFormats; + private Set clientSupportContentFormats; @Getter - ContentFormat defaultContentFormat; + private ContentFormat defaultContentFormat; @Getter private final AtomicInteger retryAttempts; @@ -327,15 +325,18 @@ public class LwM2mClient implements Serializable { Collection resources = ConcurrentHashMap.newKeySet(); Map resourceModels = modelProvider.getObjectModel(registration) .getObjectModel(pathIds.getObjectId()).resources; - if (params != null) { + if (params != null && params instanceof Map && ((Map) params).size() > 0) { resourceModels.forEach((resourceId, resourceModel) -> { if (((Map) params).containsKey(String.valueOf(resourceId))) { Object value = ((Map) params).get((String.valueOf(resourceId))); - LwM2mResource resource = null; + LwM2mResource resource; if (resourceModel.multiple) { - if (value instanceof LinkedHashMap) { - Map values = convertMultiResourceValuesFromRpcBody((LinkedHashMap) value, resourceModel.type, pathRezIdVer); + try { + Map values = convertMultiResourceValuesFromRpcBody(value, resourceModel.type, pathRezIdVer); resource = LwM2mMultipleResource.newResource(resourceId, (Map) values, resourceModel.type); + } catch (Exception e) { + throw new IllegalArgumentException("Resource id=" + resourceId + ", value = " + value + ", class = " + + value.getClass().getSimpleName() + "is bad. Value of Multi-Instance Resource must be in Json format!"); } } else { Object valueRez = value.getClass().getSimpleName().equals("Integer") ? ((Integer) value).longValue() : value; @@ -353,9 +354,12 @@ public class LwM2mClient implements Serializable { } }); } - else { + else if (params == null) { throw new IllegalArgumentException("The value of this resource must not be null."); } + else { + throw new IllegalArgumentException("The value of this resource must be in Map format and size > 0"); + } return resources; } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/AbstractTbLwM2MRequestCallback.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/AbstractTbLwM2MRequestCallback.java index c99a5ea2a1..830b7ee4ca 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/AbstractTbLwM2MRequestCallback.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/AbstractTbLwM2MRequestCallback.java @@ -19,7 +19,7 @@ import lombok.extern.slf4j.Slf4j; import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient; import org.thingsboard.server.transport.lwm2m.server.log.LwM2MTelemetryLogService; -import static org.thingsboard.server.transport.lwm2m.utils.LwM2mTransportUtil.LOG_LWM2M_WARN; +import static org.thingsboard.server.transport.lwm2m.utils.LwM2mTransportUtil.LOG_LWM2M_ERROR; @Slf4j public abstract class AbstractTbLwM2MRequestCallback implements DownlinkRequestCallback { @@ -35,12 +35,12 @@ public abstract class AbstractTbLwM2MRequestCallback implements DownlinkRe @Override public void onValidationError(String params, String msg) { log.trace("[{}] Request [{}] validation failed. Reason: {}", client.getEndpoint(), params, msg); - logService.log(client, String.format("[%s]: Request [%s] validation failed. Reason: %s", LOG_LWM2M_WARN, params, msg)); + logService.log(client, String.format("[%s]: Request [%s] validation failed. Reason: %s", LOG_LWM2M_ERROR, params, msg)); } @Override public void onError(String params, Exception e) { log.trace("[{}] Request [{}] processing failed", client.getEndpoint(), params, e); - logService.log(client, String.format("[%s]: Request [%s] processing failed. Reason: %s", LOG_LWM2M_WARN, params, e)); + logService.log(client, String.format("[%s]: Request [%s] processing failed. Reason: %s", LOG_LWM2M_ERROR, params, e)); } } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/DefaultLwM2mDownlinkMsgHandler.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/DefaultLwM2mDownlinkMsgHandler.java index 309d456663..bf475a6fb4 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/DefaultLwM2mDownlinkMsgHandler.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/DefaultLwM2mDownlinkMsgHandler.java @@ -19,7 +19,6 @@ import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.eclipse.leshan.core.Link; import org.eclipse.leshan.core.LwM2m; -import org.eclipse.leshan.core.ResponseCode; import org.eclipse.leshan.core.attributes.Attribute; import org.eclipse.leshan.core.attributes.AttributeSet; import org.eclipse.leshan.core.model.LwM2mModel; @@ -79,7 +78,6 @@ import javax.annotation.PreDestroy; import java.util.Arrays; import java.util.Collection; import java.util.Date; -import java.util.LinkedHashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; @@ -302,11 +300,13 @@ public class DefaultLwM2mDownlinkMsgHandler extends LwM2MExecutorAwareService im try { WriteRequest downlink = null; if (resourceModelWrite.multiple) { - if (request.getValue() instanceof Map && ((Map) request.getValue()).size() > 0) { + try { + Map value = convertMultiResourceValuesFromRpcBody(request.getValue(), resourceModelWrite.type, request.getObjectId()); downlink = new WriteRequest(contentFormat, resultIds.getObjectId(), resultIds.getObjectInstanceId(), resultIds.getResourceId(), - (Map) request.getValue(), resourceModelWrite.type); - } else { - callback.onValidationError(toString(request), "Resource value is: " + request.getValue().getClass().getSimpleName() + ". Value of Multi-Instance Resource must be in Json format!"); + value, resourceModelWrite.type); + } catch (Exception e) { + callback.onValidationError(toString(request), "Resource id=" + resultIds.toString() + ", value = " + request.getValue() + + ", class = " + request.getValue().getClass().getSimpleName() + "is bad. Value of Multi-Instance Resource must be in Json format!"); } } else { downlink = this.getWriteRequestSingleResource(resourceModelWrite.type, contentFormat, @@ -368,12 +368,12 @@ public class DefaultLwM2mDownlinkMsgHandler extends LwM2MExecutorAwareService im ResourceModel resourceModelWrite = client.getResourceModel(request.getVersionedId(), this.config.getModelProvider()); if (resourceModelWrite != null) { if (resourceModelWrite.multiple) { - if (request.getValue() instanceof Map && ((Map) request.getValue()).size() > 0) { - Map value = convertMultiResourceValuesFromRpcBody((LinkedHashMap) request.getValue(), resourceModelWrite.type, request.getObjectId()); + try { + Map value = convertMultiResourceValuesFromRpcBody(request.getValue(), resourceModelWrite.type, request.getObjectId()); downlink = new WriteRequest(WriteRequest.Mode.UPDATE, contentFormat, resultIds.getObjectId(), resultIds.getObjectInstanceId(), resultIds.getResourceId(), value, resourceModelWrite.type); - } else { - callback.onValidationError(toString(request), "Resource value is bad. Format: " + request.getValue().getClass().getSimpleName() + ". Value of Multi-Instance Resource must be in Json format!"); + } catch (Exception e1) { + callback.onValidationError(toString(request), "Resource id=" + resultIds.toString() + ", value = " + request.getValue() + ", class = " + request.getValue().getClass().getSimpleName() + "is bad. Value of Multi-Instance Resource must be in Json format!"); } } } else { diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/DefaultLwM2MRpcRequestHandler.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/DefaultLwM2MRpcRequestHandler.java index 3d032081ee..12ee3581ac 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/DefaultLwM2MRpcRequestHandler.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/DefaultLwM2MRpcRequestHandler.java @@ -169,8 +169,6 @@ public class DefaultLwM2MRpcRequestHandler implements LwM2MRpcRequestHandler { case DISCOVER_ALL: sendDiscoverAllRequest(client, rpcRequest); break; - case FW_UPDATE: - //TODO: implement and add break statement default: throw new IllegalArgumentException("Unsupported operation: " + operationType.name()); } @@ -257,11 +255,16 @@ public class DefaultLwM2MRpcRequestHandler implements LwM2MRpcRequestHandler { private void sendWriteReplaceRequest(LwM2mClient client, TransportProtos.ToDeviceRpcRequestMsg requestMsg, String versionedId) { RpcWriteReplaceRequest requestBody = JacksonUtil.fromString(requestMsg.getParams(), RpcWriteReplaceRequest.class); LwM2mPath path = new LwM2mPath(fromVersionedIdToObjectId(versionedId)); - if (path.isResource() && requestBody.getValue() instanceof LinkedHashMap) { + if (path.isResource()) { ResourceModel resourceModel = client.getResourceModel(versionedId, this.config.getModelProvider()); if (resourceModel != null && resourceModel.multiple) { - Map value = convertMultiResourceValuesFromRpcBody((LinkedHashMap) requestBody.getValue(), resourceModel.type, versionedId); - requestBody.setValue(value); + try { + Map value = convertMultiResourceValuesFromRpcBody(requestBody.getValue(), resourceModel.type, versionedId); + requestBody.setValue(value); + } catch (Exception e) { + throw new IllegalArgumentException("Resource id=" + versionedId + ", value = " + requestBody.getValue() + ", class = " + + requestBody.getValue().getClass().getSimpleName() + "is bad. Value of Multi-Instance Resource must be in Json format!"); + } } } TbLwM2MWriteReplaceRequest request = TbLwM2MWriteReplaceRequest.builder().versionedId(versionedId) diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/utils/LwM2mTransportUtil.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/utils/LwM2mTransportUtil.java index 69cee060ab..76e5ce4d91 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/utils/LwM2mTransportUtil.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/utils/LwM2mTransportUtil.java @@ -16,10 +16,7 @@ package org.thingsboard.server.transport.lwm2m.utils; import com.fasterxml.jackson.core.type.TypeReference; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.google.gson.Gson; import com.google.gson.JsonObject; -import com.google.gson.JsonParser; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.eclipse.leshan.core.attributes.Attribute; @@ -47,6 +44,7 @@ import org.thingsboard.server.common.data.device.profile.DeviceProfileTransportC import org.thingsboard.server.common.data.device.profile.Lwm2mDeviceProfileTransportConfiguration; import org.thingsboard.server.common.data.ota.OtaPackageKey; import org.thingsboard.server.common.data.ota.OtaPackageType; +import org.thingsboard.server.common.transport.util.JsonUtils; import org.thingsboard.server.transport.lwm2m.config.LwM2mVersion; import org.thingsboard.server.transport.lwm2m.server.LwM2mOtaConvert; import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient; @@ -57,18 +55,15 @@ import org.thingsboard.server.transport.lwm2m.server.ota.firmware.FirmwareUpdate import org.thingsboard.server.transport.lwm2m.server.ota.software.SoftwareUpdateResult; import org.thingsboard.server.transport.lwm2m.server.ota.software.SoftwareUpdateState; import org.thingsboard.server.transport.lwm2m.server.uplink.DefaultLwM2MUplinkMsgHandler; -import org.thingsboard.server.transport.lwm2m.utils.LwM2mValueConverterImpl; import java.util.ArrayList; import java.util.Arrays; import java.util.Date; import java.util.HashMap; -import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Optional; import java.util.Set; -import java.util.concurrent.ConcurrentHashMap; import static org.eclipse.leshan.core.attributes.Attribute.DIMENSION; import static org.eclipse.leshan.core.attributes.Attribute.GREATER_THAN; @@ -367,11 +362,9 @@ public class LwM2mTransportUtil { return String.format("%s %s", keyName, String.join(",", msgException)).trim(); } - public static Map convertMultiResourceValuesFromRpcBody(LinkedHashMap value, ResourceModel.Type type, String versionedId) { - Gson gson = new Gson(); - JsonParser JSON_PARSER = new JsonParser(); - String json = gson.toJson(value, LinkedHashMap.class); - return convertMultiResourceValuesFromJson((JsonObject) JSON_PARSER.parse(json), type, versionedId); + public static Map convertMultiResourceValuesFromRpcBody(Object value, ResourceModel.Type type, String versionedId) throws Exception { + String valueJsonStr = JsonUtils.riteValueAsString(value); + return convertMultiResourceValuesFromJson((JsonObject) JsonUtils.parse(valueJsonStr), type, versionedId); } public static Map convertMultiResourceValuesFromJson(JsonObject newValProto, ResourceModel.Type type, String versionedId) { diff --git a/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/util/JsonUtils.java b/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/util/JsonUtils.java index 29817ad350..82f7c2cf3a 100644 --- a/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/util/JsonUtils.java +++ b/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/util/JsonUtils.java @@ -15,15 +15,19 @@ */ package org.thingsboard.server.common.transport.util; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; import com.google.gson.JsonElement; import com.google.gson.JsonObject; import com.google.gson.JsonParser; import org.thingsboard.server.gen.transport.TransportProtos.KeyValueProto; + import java.util.List; public class JsonUtils { private static final JsonParser jsonParser = new JsonParser(); + private static final ObjectMapper json = new ObjectMapper(); public static JsonObject getJsonObject(List tsKv) { JsonObject json = new JsonObject(); @@ -52,4 +56,9 @@ public class JsonUtils { public static JsonElement parse(String params) { return jsonParser.parse(params); } + + public static String riteValueAsString (Object value) throws JsonProcessingException { + return json.writeValueAsString(value); + + } } diff --git a/transport/lwm2m/src/main/resources/tb-lwm2m-transport.yml b/transport/lwm2m/src/main/resources/tb-lwm2m-transport.yml index d398b676dd..3398d82234 100644 --- a/transport/lwm2m/src/main/resources/tb-lwm2m-transport.yml +++ b/transport/lwm2m/src/main/resources/tb-lwm2m-transport.yml @@ -97,10 +97,10 @@ transport: timeout: "${CLIENT_SIDE_RPC_TIMEOUT:60000}" # Enable/disable http/mqtt/coap transport protocols (has higher priority than certain protocol's 'enabled' property) api_enabled: "${TB_TRANSPORT_API_ENABLED:true}" - # Local LwM2M transport parameters log: enabled: "${TB_TRANSPORT_LOG_ENABLED:true}" max_length: "${TB_TRANSPORT_LOG_MAX_LENGTH:1024}" + # Local LwM2M transport parameters lwm2m: # Enable/disable lvm2m transport protocol. enabled: "${LWM2M_ENABLED:true}"