Browse Source

lwm2m: bootstrap new: update tests-2

pull/14084/head
nickAS21 12 months ago
parent
commit
ea8ab484df
  1. 17
      application/src/test/java/org/thingsboard/server/transport/lwm2m/AbstractLwM2MIntegrationTest.java
  2. 42
      application/src/test/java/org/thingsboard/server/transport/lwm2m/client/LwM2MTestClient.java
  3. 137
      common/data/src/main/java/org/thingsboard/server/common/data/device/credentials/lwm2m/Lwm2mServerIdentifier.java
  4. 22
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/store/LwM2MBootstrapConfigStoreTaskProvider.java
  5. 8
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/store/LwM2MConfigurationChecker.java
  6. 3
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/utils/LwM2MTransportUtil.java
  7. 13
      dao/src/main/java/org/thingsboard/server/dao/service/validator/DeviceProfileDataValidator.java
  8. 10
      dao/src/test/java/org/thingsboard/server/dao/service/validator/DeviceProfileDataValidatorTest.java
  9. 5
      ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-config-server.component.ts
  10. 2
      ui-ngx/src/assets/locale/locale.constant-en_US.json

17
application/src/test/java/org/thingsboard/server/transport/lwm2m/AbstractLwM2MIntegrationTest.java

@ -33,10 +33,12 @@ import org.eclipse.leshan.server.registration.Registration;
import org.junit.After; import org.junit.After;
import org.junit.Assert; import org.junit.Assert;
import org.junit.Before; import org.junit.Before;
import org.junit.jupiter.api.TestInstance;
import org.mockito.Mockito; import org.mockito.Mockito;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.mock.mockito.SpyBean; import org.springframework.boot.test.mock.mockito.SpyBean;
import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatus;
import org.springframework.test.annotation.DirtiesContext;
import org.springframework.test.context.TestPropertySource; import org.springframework.test.context.TestPropertySource;
import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.common.util.JacksonUtil;
import org.thingsboard.common.util.ThingsBoardExecutors; import org.thingsboard.common.util.ThingsBoardExecutors;
@ -120,11 +122,13 @@ import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.LwM2MProfil
import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.LwM2MProfileBootstrapConfigType.NONE; import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.LwM2MProfileBootstrapConfigType.NONE;
import static org.thingsboard.server.transport.lwm2m.ota.AbstractOtaLwM2MIntegrationTest.CLIENT_LWM2M_SETTINGS_19; import static org.thingsboard.server.transport.lwm2m.ota.AbstractOtaLwM2MIntegrationTest.CLIENT_LWM2M_SETTINGS_19;
@TestPropertySource(properties = {
"transport.lwm2m.enabled=true",
})
@Slf4j @Slf4j
@DaoSqlTest @DaoSqlTest
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
@DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_EACH_TEST_METHOD)
@TestPropertySource(properties = {
"transport.lwm2m.enabled=true"
})
public abstract class AbstractLwM2MIntegrationTest extends AbstractTransportIntegrationTest { public abstract class AbstractLwM2MIntegrationTest extends AbstractTransportIntegrationTest {
@SpyBean @SpyBean
@ -317,9 +321,16 @@ public abstract class AbstractLwM2MIntegrationTest extends AbstractTransportInte
@After @After
public void after() throws Exception { public void after() throws Exception {
this.clientDestroy(true); this.clientDestroy(true);
if (executor != null && !executor.isShutdown()) { if (executor != null && !executor.isShutdown()) {
executor.shutdownNow(); executor.shutdownNow();
if (!executor.awaitTermination(2, TimeUnit.SECONDS)) {
log.warn("⚠️ Executor did not terminate cleanly, forcing GC");
}
} }
Thread.sleep(300);
System.gc();
log.info("✅ Test teardown completed: {}", this.getClass().getSimpleName());
} }
private void init() throws Exception { private void init() throws Exception {

42
application/src/test/java/org/thingsboard/server/transport/lwm2m/client/LwM2MTestClient.java

@ -69,6 +69,7 @@ import org.thingsboard.server.transport.lwm2m.utils.LwM2mValueConverterImpl;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.lang.reflect.Field;
import java.net.InetSocketAddress; import java.net.InetSocketAddress;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
@ -153,29 +154,30 @@ public class LwM2MTestClient {
if (securityBs != null && security != null) { if (securityBs != null && security != null) {
// SECURITIES // SECURITIES
securityBs.setId(0); forceNullSecurityId(securityBs);
security.setId(1); forceNullSecurityId(security);
LwM2mInstanceEnabler[] instances = new LwM2mInstanceEnabler[]{securityBs, security}; LwM2mInstanceEnabler[] instances = new LwM2mInstanceEnabler[]{securityBs, security};
initializer.setInstancesForObject(SECURITY, instances); initializer.setInstancesForObject(SECURITY, instances);
log.warn("Security BS section: securityBsId [{}] Security Lwm2m section: securityLwm2mId [{}] ", securityBs.getId(), security.getId());
// SERVER // SERVER
Server lwm2mServer = new Server(shortServerId, TimeUnit.MINUTES.toSeconds(60)); Server lwm2mServer = new Server(shortServerId, TimeUnit.MINUTES.toSeconds(60));
lwm2mServer.setId(0);
instances = new LwM2mInstanceEnabler[]{lwm2mServer}; instances = new LwM2mInstanceEnabler[]{lwm2mServer};
initializer.setInstancesForObject(SERVER, instances); initializer.setInstancesForObject(SERVER, instances);
} else if (securityBs != null) { } else if (securityBs != null) {
// SECURITY // SECURITY
initializer.setClassForObject(SERVER, Server.class); ; forceNullSecurityId(securityBs);
initializer.setInstancesForObject(SECURITY, securityBs); initializer.setInstancesForObject(SECURITY, securityBs);
log.warn("Security section: securityBsId [{}] ", securityBs.getId()); // SERVER
initializer.setClassForObject(SERVER, Server.class);
log.warn("Security BS section: securityBsId [{}] ", securityBs.getId());
} else { } else {
// SECURITY // SECURITY
security.setId(0); forceNullSecurityId(security);
initializer.setInstancesForObject(SECURITY, security); initializer.setInstancesForObject(SECURITY, security);
// SERVER // SERVER
Server lwm2mServer = new Server(shortServerId, TimeUnit.MINUTES.toSeconds(60)); Server lwm2mServer = new Server(shortServerId, TimeUnit.MINUTES.toSeconds(60));
lwm2mServer.setId(0);
initializer.setInstancesForObject(SERVER, lwm2mServer); initializer.setInstancesForObject(SERVER, lwm2mServer);
log.warn("Security Lwm2m section: securityLwm2mId [{}] Server Lwm2m section: securityLwm2mId [{}] ", security.getId(), lwm2mServer.getId());
} }
initializer.setInstancesForObject(DEVICE, lwM2MDevice = new SimpleLwM2MDevice(executor, value3_0_9)); initializer.setInstancesForObject(DEVICE, lwM2MDevice = new SimpleLwM2MDevice(executor, value3_0_9));
@ -494,5 +496,29 @@ public class LwM2MTestClient {
LwM2mModel model = new StaticModel(models); LwM2mModel model = new StaticModel(models);
return new ObjectsInitializer(model); return new ObjectsInitializer(model);
} }
private void forceNullSecurityId(Security securityBs) {
if (securityBs == null) {
return;
}
try {
Field field = securityBs.getClass().getDeclaredField("id");
field.setAccessible(true);
field.set(securityBs, null);
log.info("[forceNullSecurityId] Set id=null for {}", securityBs);
} catch (NoSuchFieldException e) {
try {
// Якщо поле в батьківському класі (наприклад SecurityObjectInstance)
Field field = securityBs.getClass().getSuperclass().getDeclaredField("id");
field.setAccessible(true);
field.set(securityBs, null);
log.info("[forceNullSecurityId] Set id=null for {} (via superclass)", securityBs);
} catch (Exception ex) {
log.error("[forceNullSecurityId] Field 'id' not found for {}", securityBs.getClass(), ex);
}
} catch (Exception e) {
log.error("[forceNullSecurityId] Failed to set id=null for {}", securityBs.getClass(), e);
}
}
} }

137
common/data/src/main/java/org/thingsboard/server/common/data/device/credentials/lwm2m/Lwm2mServerIdentifier.java

@ -0,0 +1,137 @@
/**
* Copyright © 2016-2025 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.common.data.device.credentials.lwm2m;
/**
* Enum representing predefined LwM2M Short Server Identifiers.
* <p>
* See OMA Lightweight M2M Specification for details about the server identifier space.
*/
public enum Lwm2mServerIdentifier {
/**
* Bootstrap Short Server ID (0).
* Reserved for the Bootstrap Server — used exclusively during the bootstrap phase.
*/
BOOTSTRAP(0, "Bootstrap Short Server ID", true),
/**
* Primary LwM2M Server Short Server ID (1).
* Upper boundary for valid LwM2M Server Identifiers (1–65534).
*/
PRIMARY_LWM2M_SERVER(1, "LwM2M Server Short Server ID", false),
/**
* Maximum valid LwM2M Server ID (65534).
* Upper boundary for valid LwM2M Server Identifiers (1–65534).
*/
LWM2M_SERVER_MAX(65534, "LwM2M Server Short Server ID", false),
/**
* Not used for identifying an LwM2M Server (65535).
* Reserved sentinel value representing "no server associated" or "invalid ID".
* MUST NOT be assigned to any LwM2M Server according to OMA-TS-LightweightM2M-Core, §6.2.1.
* OMA LwM2M Core / v1.2: Server / Short Server ID): «MAX_ID 65535 is a reserved value and MUST NOT be used for identifying an Object»
*/
NOT_USED_IDENTIFYING_LWM2M_SERVER(65535, "Reserved sentinel value (no active server)", false);
private final int id;
private final String description;
private final boolean isBootstrap;
Lwm2mServerIdentifier(int id, String description, boolean isBootstrap) {
this.id = id;
this.description = description;
this.isBootstrap = isBootstrap;
}
/**
* @return the integer value of this Short Server ID.
*/
public int getId() {
return id;
}
/**
* @return a human-readable description of this Server ID.
*/
public String getDescription() {
return description;
}
/**
* @return true if this ID represents a Bootstrap Server.
*/
public boolean isBootstrap() {
return isBootstrap;
}
/**
* Checks whether a given numeric ID belongs to the Bootstrap Server (0).
* OMA Spec (LwM2M v1.0 / v1.1):
* Short Server ID Resource (Resource ID: 0)
* The Short Server ID identifies a Server Object Instance.
* The value 0 is reserved for the Bootstrap Server.
* A value between 1 and 65534 identifies a LwM2M Server.
* The value 65535 MUST NOT be used.
* @param id Short Server ID value.
* @return true if id == 0.
*/
public static boolean isBootstrap(int id) {
return id == BOOTSTRAP.id;
}
/**
* Checks whether a given ID represents a valid LwM2M Server (1–65534).
*
* @param id Short Server ID value.
* @return true if the ID belongs to a standard LwM2M Server.
*/
public static boolean isLwm2mServer(int id) {
return id >= PRIMARY_LWM2M_SERVER.id && id <= LWM2M_SERVER_MAX.id;
}
/**
* Checks whether the provided ID is within the valid LwM2M range [0–65535].
*
* @param id ID to check.
* @return true if valid, false otherwise.
*/
public static boolean isValid(int id) {
return id >= 0 && id <= 65535;
}
/**
* Returns a {@link Lwm2mServerIdentifier} instance matching the given ID.
*
* @param id numeric ID.
* @return corresponding enum constant.
* @throws IllegalArgumentException if no constant matches the given ID.
*/
public static Lwm2mServerIdentifier fromId(int id) {
for (Lwm2mServerIdentifier s : values()) {
if (s.id == id) {
return s;
}
}
throw new IllegalArgumentException("Unknown Lwm2mServerIdentifier: " + id);
}
@Override
public String toString() {
return name() + "(" + id + ") - " + description;
}
}

22
common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/store/LwM2MBootstrapConfigStoreTaskProvider.java

@ -48,9 +48,9 @@ import static org.eclipse.leshan.core.LwM2mId.ACCESS_CONTROL;
import static org.eclipse.leshan.core.LwM2mId.SECURITY; import static org.eclipse.leshan.core.LwM2mId.SECURITY;
import static org.eclipse.leshan.core.LwM2mId.SERVER; import static org.eclipse.leshan.core.LwM2mId.SERVER;
import static org.eclipse.leshan.server.bootstrap.BootstrapUtil.toWriteRequest; import static org.eclipse.leshan.server.bootstrap.BootstrapUtil.toWriteRequest;
import static org.thingsboard.server.transport.lwm2m.utils.LwM2MTransportUtil.BOOTSTRAP_DEFAULT_SHORT_ID_0; import static org.thingsboard.server.common.data.device.credentials.lwm2m.Lwm2mServerIdentifier.BOOTSTRAP;
import static org.thingsboard.server.transport.lwm2m.utils.LwM2MTransportUtil.LWM2M_DEFAULT_SHORT_ID_1; import static org.thingsboard.server.common.data.device.credentials.lwm2m.Lwm2mServerIdentifier.LWM2M_SERVER_MAX;
import static org.thingsboard.server.transport.lwm2m.utils.LwM2MTransportUtil.LWM2M_DEFAULT_SHORT_ID_65534; import static org.thingsboard.server.common.data.device.credentials.lwm2m.Lwm2mServerIdentifier.PRIMARY_LWM2M_SERVER;
@Slf4j @Slf4j
public class LwM2MBootstrapConfigStoreTaskProvider implements LwM2MBootstrapTaskProvider { public class LwM2MBootstrapConfigStoreTaskProvider implements LwM2MBootstrapTaskProvider {
@ -147,7 +147,7 @@ public class LwM2MBootstrapConfigStoreTaskProvider implements LwM2MBootstrapTask
log.error("Invalid lwm2mSecurityInstance [{}] by short server id [{}]", path.getObjectInstanceId(), lwm2mShortServerId); log.error("Invalid lwm2mSecurityInstance [{}] by short server id [{}]", path.getObjectInstanceId(), lwm2mShortServerId);
} }
} else { } else {
this.lwM2MBootstrapSessionClients.get(endpoint).getSecurityInstances().putIfAbsent(BOOTSTRAP_DEFAULT_SHORT_ID_0, path.getObjectInstanceId()); this.lwM2MBootstrapSessionClients.get(endpoint).getSecurityInstances().putIfAbsent(BOOTSTRAP.getId(), path.getObjectInstanceId());
} }
} else if (path.getObjectId() == 1) { } else if (path.getObjectId() == 1) {
if (link.getAttributes().get("ssid") != null) { if (link.getAttributes().get("ssid") != null) {
@ -192,7 +192,7 @@ public class LwM2MBootstrapConfigStoreTaskProvider implements LwM2MBootstrapTask
* SECURITY = 0; InstanceId = 0 * SECURITY = 0; InstanceId = 0
* SERVER = 1; InstanceId = 0 * SERVER = 1; InstanceId = 0
* 2) Both * 2) Both
* - Short Server ID == 0 or 65535 bs) * - Short Server ID == 0 bs)
* SECURITY = 0; InstanceId = 0 * SECURITY = 0; InstanceId = 0
* SERVER = 1; InstanceId = null * SERVER = 1; InstanceId = null
* - Short Server ID == 1 - 65534 lwm2m) * - Short Server ID == 1 - 65534 lwm2m)
@ -202,8 +202,8 @@ public class LwM2MBootstrapConfigStoreTaskProvider implements LwM2MBootstrapTask
public List<BootstrapDownlinkRequest<? extends LwM2mResponse>> toRequests(BootstrapConfig bootstrapConfigNew, public List<BootstrapDownlinkRequest<? extends LwM2mResponse>> toRequests(BootstrapConfig bootstrapConfigNew,
ContentFormat contentFormat, ContentFormat contentFormat,
String endpoint) { String endpoint) {
Integer bootstrapSecurityInstanceId = this.lwM2MBootstrapSessionClients.get(endpoint).getSecurityInstances().get(BOOTSTRAP_DEFAULT_SHORT_ID_0) == null ? Integer bootstrapSecurityInstanceId = this.lwM2MBootstrapSessionClients.get(endpoint).getSecurityInstances().get(BOOTSTRAP.getId()) == null ?
0 : this.lwM2MBootstrapSessionClients.get(endpoint).getSecurityInstances().get(BOOTSTRAP_DEFAULT_SHORT_ID_0); 0 : this.lwM2MBootstrapSessionClients.get(endpoint).getSecurityInstances().get(BOOTSTRAP.getId());
List<BootstrapDownlinkRequest<? extends LwM2mResponse>> requests = new ArrayList<>(); List<BootstrapDownlinkRequest<? extends LwM2mResponse>> requests = new ArrayList<>();
Set<String> pathsDelete = new HashSet<>(); Set<String> pathsDelete = new HashSet<>();
ConcurrentHashMap<String, BootstrapDownlinkRequest<? extends LwM2mResponse>> requestsWrite = new ConcurrentHashMap<>(); ConcurrentHashMap<String, BootstrapDownlinkRequest<? extends LwM2mResponse>> requestsWrite = new ConcurrentHashMap<>();
@ -214,7 +214,7 @@ public class LwM2MBootstrapConfigStoreTaskProvider implements LwM2MBootstrapTask
// bootstrap Security new - There can only be one instance of bootstrap at a time. // bootstrap Security new - There can only be one instance of bootstrap at a time.
/// bs: handle security only /// bs: handle security only
for (BootstrapConfig.ServerSecurity security : new TreeMap<>(bootstrapConfigNew.security).values()) { for (BootstrapConfig.ServerSecurity security : new TreeMap<>(bootstrapConfigNew.security).values()) {
if (security.bootstrapServer && security.serverId == BOOTSTRAP_DEFAULT_SHORT_ID_0) { if (security.bootstrapServer && security.serverId == BOOTSTRAP.getId()) {
// delete old bootstrap Security // delete old bootstrap Security
String path = "/" + SECURITY + "/" + bootstrapSecurityInstanceId; String path = "/" + SECURITY + "/" + bootstrapSecurityInstanceId;
pathsDelete.add(path); pathsDelete.add(path);
@ -231,7 +231,7 @@ public class LwM2MBootstrapConfigStoreTaskProvider implements LwM2MBootstrapTask
/// lwm2m server: handle security & server /// lwm2m server: handle security & server
//max Lwm2m Security instance old id if new //max Lwm2m Security instance old id if new
for (Integer shortId : this.lwM2MBootstrapSessionClients.get(endpoint).getSecurityInstances().keySet()) { for (Integer shortId : this.lwM2MBootstrapSessionClients.get(endpoint).getSecurityInstances().keySet()) {
if (shortId >= BOOTSTRAP_DEFAULT_SHORT_ID_0 && shortId <= LWM2M_DEFAULT_SHORT_ID_65534) { if (shortId >= BOOTSTRAP.getId() && shortId <= LWM2M_SERVER_MAX.getId()) {
lwm2mSecurityInstanceIdMax = this.lwM2MBootstrapSessionClients.get(endpoint).getSecurityInstances().get(shortId) > lwm2mSecurityInstanceIdMax = this.lwM2MBootstrapSessionClients.get(endpoint).getSecurityInstances().get(shortId) >
lwm2mSecurityInstanceIdMax ? this.lwM2MBootstrapSessionClients.get(endpoint).getSecurityInstances().get(shortId) : lwm2mSecurityInstanceIdMax ? this.lwM2MBootstrapSessionClients.get(endpoint).getSecurityInstances().get(shortId) :
lwm2mSecurityInstanceIdMax; lwm2mSecurityInstanceIdMax;
@ -239,7 +239,7 @@ public class LwM2MBootstrapConfigStoreTaskProvider implements LwM2MBootstrapTask
} }
//max Lwm2m Server instance old id if new //max Lwm2m Server instance old id if new
for (Integer shortId : this.lwM2MBootstrapSessionClients.get(endpoint).getServerInstances().keySet()) { for (Integer shortId : this.lwM2MBootstrapSessionClients.get(endpoint).getServerInstances().keySet()) {
if (shortId >= LWM2M_DEFAULT_SHORT_ID_1 && shortId <= LWM2M_DEFAULT_SHORT_ID_65534) { if (shortId >= PRIMARY_LWM2M_SERVER.getId() && shortId <= LWM2M_SERVER_MAX.getId()) {
lwm2mServerInstanceIdMax = this.lwM2MBootstrapSessionClients.get(endpoint).getServerInstances().get(shortId) > lwm2mServerInstanceIdMax = this.lwM2MBootstrapSessionClients.get(endpoint).getServerInstances().get(shortId) >
lwm2mServerInstanceIdMax ? this.lwM2MBootstrapSessionClients.get(endpoint).getServerInstances().get(shortId) : lwm2mServerInstanceIdMax ? this.lwM2MBootstrapSessionClients.get(endpoint).getServerInstances().get(shortId) :
lwm2mServerInstanceIdMax; lwm2mServerInstanceIdMax;
@ -297,7 +297,7 @@ public class LwM2MBootstrapConfigStoreTaskProvider implements LwM2MBootstrapTask
} }
private boolean validateLwm2mShortServerId(int id){ private boolean validateLwm2mShortServerId(int id){
return id >= LWM2M_DEFAULT_SHORT_ID_1 && id <= LWM2M_DEFAULT_SHORT_ID_65534; return id >= PRIMARY_LWM2M_SERVER.getId() && id <= LWM2M_SERVER_MAX.getId();
} }
@Override @Override

8
common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/store/LwM2MConfigurationChecker.java

@ -21,6 +21,10 @@ import org.eclipse.leshan.server.bootstrap.InvalidConfigurationException;
import java.util.Map; import java.util.Map;
import static org.thingsboard.server.common.data.device.credentials.lwm2m.Lwm2mServerIdentifier.BOOTSTRAP;
import static org.thingsboard.server.common.data.device.credentials.lwm2m.Lwm2mServerIdentifier.NOT_USED_IDENTIFYING_LWM2M_SERVER;
import static org.thingsboard.server.common.data.device.credentials.lwm2m.Lwm2mServerIdentifier.isLwm2mServer;
public class LwM2MConfigurationChecker extends ConfigurationChecker { public class LwM2MConfigurationChecker extends ConfigurationChecker {
@Override @Override
@ -74,8 +78,8 @@ public class LwM2MConfigurationChecker extends ConfigurationChecker {
* This Resource MUST be set when the Bootstrap-Server Resource has false value. * This Resource MUST be set when the Bootstrap-Server Resource has false value.
* Specific ID:0 and ID:65535 values MUST NOT be used for identifying the LwM2M Server (Section 6.3 of the LwM2M version 1.0 specification). * Specific ID:0 and ID:65535 values MUST NOT be used for identifying the LwM2M Server (Section 6.3 of the LwM2M version 1.0 specification).
*/ */
if (!security.bootstrapServer && (srvCfg.shortId < 1 && srvCfg.shortId > 65534 )) { if (!security.bootstrapServer && !isLwm2mServer(srvCfg.shortId)) {
throw new InvalidConfigurationException("Specific ID:0 and ID:65535 values MUST NOT be used for identifying the LwM2M Server"); throw new InvalidConfigurationException("Specific ID:" + BOOTSTRAP.getId() + " and ID:" + NOT_USED_IDENTIFYING_LWM2M_SERVER.getId() + " values MUST NOT be used for identifying the LwM2M Server");
} }
} }
} }

3
common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/utils/LwM2MTransportUtil.java

@ -81,9 +81,6 @@ public class LwM2MTransportUtil {
public static final String LOG_LWM2M_INFO = "info"; public static final String LOG_LWM2M_INFO = "info";
public static final String LOG_LWM2M_ERROR = "error"; public static final String LOG_LWM2M_ERROR = "error";
public static final String LOG_LWM2M_WARN = "warn"; public static final String LOG_LWM2M_WARN = "warn";
public static final int BOOTSTRAP_DEFAULT_SHORT_ID_0 = 0;
public static final int LWM2M_DEFAULT_SHORT_ID_1 = 1;
public static final int LWM2M_DEFAULT_SHORT_ID_65534 = 65534;
public static LwM2mOtaConvert convertOtaUpdateValueToString(String pathIdVer, Object value, ResourceModel.Type currentType) { public static LwM2mOtaConvert convertOtaUpdateValueToString(String pathIdVer, Object value, ResourceModel.Type currentType) {
String path = fromVersionedIdToObjectId(pathIdVer); String path = fromVersionedIdToObjectId(pathIdVer);

13
dao/src/main/java/org/thingsboard/server/dao/service/validator/DeviceProfileDataValidator.java

@ -69,6 +69,11 @@ import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.Set;
import static org.thingsboard.server.common.data.device.credentials.lwm2m.Lwm2mServerIdentifier.BOOTSTRAP;
import static org.thingsboard.server.common.data.device.credentials.lwm2m.Lwm2mServerIdentifier.LWM2M_SERVER_MAX;
import static org.thingsboard.server.common.data.device.credentials.lwm2m.Lwm2mServerIdentifier.PRIMARY_LWM2M_SERVER;
import static org.thingsboard.server.common.data.device.credentials.lwm2m.Lwm2mServerIdentifier.isLwm2mServer;
@Slf4j @Slf4j
@Component @Component
public class DeviceProfileDataValidator extends AbstractHasOtaPackageValidator<DeviceProfile> { public class DeviceProfileDataValidator extends AbstractHasOtaPackageValidator<DeviceProfile> {
@ -339,12 +344,12 @@ public class DeviceProfileDataValidator extends AbstractHasOtaPackageValidator<D
if (serverConfig.getShortServerId() != null) { if (serverConfig.getShortServerId() != null) {
if (serverConfig.isBootstrapServerIs()) { if (serverConfig.isBootstrapServerIs()) {
if (serverConfig.getShortServerId() < 0 || serverConfig.getShortServerId() > 65535) { if (serverConfig.getShortServerId() != BOOTSTRAP.getId()) {
throw new DeviceCredentialsValidationException("Bootstrap Server ShortServerId must be in range [0 - 65535]!"); throw new DeviceCredentialsValidationException("Bootstrap Server ShortServerId must be in range [" + BOOTSTRAP.getId() + "]!");
} }
} else { } else {
if (serverConfig.getShortServerId() < 1 || serverConfig.getShortServerId() > 65534) { if (!isLwm2mServer(serverConfig.getShortServerId())) {
throw new DeviceCredentialsValidationException("LwM2M Server ShortServerId must be in range [1 - 65534]!"); throw new DeviceCredentialsValidationException("LwM2M Server ShortServerId must be in range [" + PRIMARY_LWM2M_SERVER.getId() + " - " + LWM2M_SERVER_MAX.getId() + "!");
} }
} }
} else { } else {

10
dao/src/test/java/org/thingsboard/server/dao/service/validator/DeviceProfileDataValidatorTest.java

@ -48,6 +48,10 @@ import java.util.UUID;
import static org.assertj.core.api.Assertions.assertThatThrownBy; import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.mockito.BDDMockito.willReturn; import static org.mockito.BDDMockito.willReturn;
import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verify;
import static org.thingsboard.server.common.data.device.credentials.lwm2m.Lwm2mServerIdentifier.BOOTSTRAP;
import static org.thingsboard.server.common.data.device.credentials.lwm2m.Lwm2mServerIdentifier.LWM2M_SERVER_MAX;
import static org.thingsboard.server.common.data.device.credentials.lwm2m.Lwm2mServerIdentifier.NOT_USED_IDENTIFYING_LWM2M_SERVER;
import static org.thingsboard.server.common.data.device.credentials.lwm2m.Lwm2mServerIdentifier.PRIMARY_LWM2M_SERVER;
@SpringBootTest(classes = DeviceProfileDataValidator.class) @SpringBootTest(classes = DeviceProfileDataValidator.class)
class DeviceProfileDataValidatorTest { class DeviceProfileDataValidatorTest {
@ -74,8 +78,8 @@ class DeviceProfileDataValidatorTest {
" \"clientOnlyObserveAfterConnect\": 1\n" + " \"clientOnlyObserveAfterConnect\": 1\n" +
" }"; " }";
private static final String msgErrorLwm2mRange = "LwM2M Server ShortServerId must be in range [1 - 65534]!"; private static final String msgErrorLwm2mRange = "LwM2M Server ShortServerId must be in range [" + PRIMARY_LWM2M_SERVER.getId() + " - " + LWM2M_SERVER_MAX.getId() + "]!";
private static final String msgErrorBsRange = "Bootstrap Server ShortServerId must be in range [0 - 65535]!"; private static final String msgErrorBsRange = "Bootstrap Server ShortServerId must be in range [" + BOOTSTRAP.getId() + " - " + NOT_USED_IDENTIFYING_LWM2M_SERVER.getId() + "]!";
private static final String msgErrorNotNull = " Server ShortServerId must not be null!"; private static final String msgErrorNotNull = " Server ShortServerId must not be null!";
private static final String host = "localhost"; private static final String host = "localhost";
private static final String hostBs = "localhost"; private static final String hostBs = "localhost";
@ -153,7 +157,7 @@ class DeviceProfileDataValidatorTest {
@Test @Test
void testValidateDeviceProfile_Lwm2mShortServerId_More_65534_Error_BootstrapShortServerId_Ok() { void testValidateDeviceProfile_Lwm2mShortServerId_More_65534_Error_BootstrapShortServerId_Ok() {
verifyValidationError(65535, 111, msgErrorLwm2mRange); verifyValidationError(NOT_USED_IDENTIFYING_LWM2M_SERVER.getId(), 111, msgErrorLwm2mRange);
} }
@Test @Test

5
ui-ngx/src/app/modules/home/components/profile/device/lwm2m/lwm2m-device-config-server.component.ts

@ -76,8 +76,7 @@ export class Lwm2mDeviceConfigServerComponent implements OnInit, ControlValueAcc
readonly shortServerIdMin = 1; readonly shortServerIdMin = 1;
readonly shortServerIdMax = 65534; readonly shortServerIdMax = 65534;
readonly shortServerIdBsMin = 0; readonly shortServerIdBs = 0;
readonly shortServerIdBsMax = 65535;
@Input() @Input()
@coerceBoolean() @coerceBoolean()
@ -103,7 +102,7 @@ export class Lwm2mDeviceConfigServerComponent implements OnInit, ControlValueAcc
serverPublicKey: [''], serverPublicKey: [''],
clientHoldOffTime: ['', [Validators.required, Validators.min(0), Validators.pattern('[0-9]*')]], clientHoldOffTime: ['', [Validators.required, Validators.min(0), Validators.pattern('[0-9]*')]],
shortServerId: ['', this.isBootstrap shortServerId: ['', this.isBootstrap
? [Validators.required, Validators.pattern('^(' + this.shortServerIdBsMin+ '|' + this.shortServerIdBsMax + ')$' )] ? [Validators.required, Validators.pattern('^(' + this.shortServerIdBs + ')$' )]
: [Validators.required, Validators.pattern('[0-9]*'), Validators.min(this.shortServerIdMin), Validators.max(this.shortServerIdMax)] : [Validators.required, Validators.pattern('[0-9]*'), Validators.min(this.shortServerIdMin), Validators.max(this.shortServerIdMax)]
], ],
bootstrapServerAccountTimeout: ['', [Validators.required, Validators.min(0), Validators.pattern('[0-9]*')]], bootstrapServerAccountTimeout: ['', [Validators.required, Validators.min(0), Validators.pattern('[0-9]*')]],

2
ui-ngx/src/assets/locale/locale.constant-en_US.json

@ -2302,7 +2302,7 @@
"short-id-required": "Short server ID is required.", "short-id-required": "Short server ID is required.",
"short-id-range": "Short server ID should be in a range from {{ min }} to {{ max }}.", "short-id-range": "Short server ID should be in a range from {{ min }} to {{ max }}.",
"short-id-pattern": "Short server ID must be a positive integer.", "short-id-pattern": "Short server ID must be a positive integer.",
"short-id-pattern-bs": "Short server ID must be only 0 or 65535", "short-id-pattern-bs": "Short server ID must be only 0",
"lifetime": "Client registration lifetime", "lifetime": "Client registration lifetime",
"lifetime-required": "Client registration lifetime is required.", "lifetime-required": "Client registration lifetime is required.",
"lifetime-pattern": "Client registration lifetime must be a positive integer.", "lifetime-pattern": "Client registration lifetime must be a positive integer.",

Loading…
Cancel
Save