Browse Source

LwM2M Server refactoring

pull/4542/head
Andrii Shvaika 6 years ago
parent
commit
72382a52e3
  1. 10
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2MBootstrapSecurityStore.java
  2. 2
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/EndpointSecurityInfo.java
  3. 41
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/LwM2mCredentialsSecurityInfoValidator.java
  4. 281
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/DefaultLwM2MTransportMsgHandler.java
  5. 2
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mTransportRequest.java
  6. 3
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mTransportUtil.java
  7. 98
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClient.java
  8. 23
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClientContext.java
  9. 168
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClientContextImpl.java
  10. 94
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/store/TbLwM2mSecurityStore.java
  11. 128
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/store/TbLwM2mStoreConfiguration.java
  12. 59
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/store/TbLwM2mStoreFactory.java

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

@ -32,7 +32,7 @@ import org.springframework.stereotype.Service;
import org.thingsboard.server.gen.transport.TransportProtos;
import org.thingsboard.server.transport.lwm2m.secure.LwM2MSecurityMode;
import org.thingsboard.server.transport.lwm2m.secure.LwM2mCredentialsSecurityInfoValidator;
import org.thingsboard.server.transport.lwm2m.secure.ReadResultSecurityStore;
import org.thingsboard.server.transport.lwm2m.secure.EndpointSecurityInfo;
import org.thingsboard.server.transport.lwm2m.server.LwM2mSessionMsgListener;
import org.thingsboard.server.transport.lwm2m.server.LwM2mTransportContext;
import org.thingsboard.server.transport.lwm2m.server.LwM2mTransportServerHelper;
@ -72,7 +72,7 @@ public class LwM2MBootstrapSecurityStore implements BootstrapSecurityStore {
@Override
public List<SecurityInfo> getAllByEndpoint(String endPoint) {
ReadResultSecurityStore store = lwM2MCredentialsSecurityInfoValidator.createAndValidateCredentialsSecurityInfo(endPoint, LwM2mTransportUtil.LwM2mTypeServer.BOOTSTRAP);
EndpointSecurityInfo store = lwM2MCredentialsSecurityInfoValidator.getEndpointSecurityInfo(endPoint, LwM2mTransportUtil.LwM2mTypeServer.BOOTSTRAP);
if (store.getBootstrapJsonCredential() != null && store.getSecurityMode() < LwM2MSecurityMode.DEFAULT_MODE.code) {
/* add value to store from BootstrapJson */
this.setBootstrapConfigScurityInfo(store);
@ -96,7 +96,7 @@ public class LwM2MBootstrapSecurityStore implements BootstrapSecurityStore {
@Override
public SecurityInfo getByIdentity(String identity) {
ReadResultSecurityStore store = lwM2MCredentialsSecurityInfoValidator.createAndValidateCredentialsSecurityInfo(identity, LwM2mTransportUtil.LwM2mTypeServer.BOOTSTRAP);
EndpointSecurityInfo store = lwM2MCredentialsSecurityInfoValidator.getEndpointSecurityInfo(identity, LwM2mTransportUtil.LwM2mTypeServer.BOOTSTRAP);
if (store.getBootstrapJsonCredential() != null && store.getSecurityMode() < LwM2MSecurityMode.DEFAULT_MODE.code) {
/* add value to store from BootstrapJson */
this.setBootstrapConfigScurityInfo(store);
@ -113,7 +113,7 @@ public class LwM2MBootstrapSecurityStore implements BootstrapSecurityStore {
return null;
}
private void setBootstrapConfigScurityInfo(ReadResultSecurityStore store) {
private void setBootstrapConfigScurityInfo(EndpointSecurityInfo store) {
/* BootstrapConfig */
LwM2MBootstrapConfig lwM2MBootstrapConfig = this.getParametersBootstrap(store);
if (lwM2MBootstrapConfig != null) {
@ -150,7 +150,7 @@ public class LwM2MBootstrapSecurityStore implements BootstrapSecurityStore {
}
}
private LwM2MBootstrapConfig getParametersBootstrap(ReadResultSecurityStore store) {
private LwM2MBootstrapConfig getParametersBootstrap(EndpointSecurityInfo store) {
try {
JsonObject bootstrapJsonCredential = store.getBootstrapJsonCredential();
if (bootstrapJsonCredential != null) {

2
common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/ReadResultSecurityStore.java → common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/EndpointSecurityInfo.java

@ -25,7 +25,7 @@ import org.thingsboard.server.gen.transport.TransportProtos.ValidateDeviceCreden
import static org.thingsboard.server.transport.lwm2m.secure.LwM2MSecurityMode.DEFAULT_MODE;
@Data
public class ReadResultSecurityStore {
public class EndpointSecurityInfo {
private ValidateDeviceCredentialsResponseMsg msg;
private SecurityInfo securityInfo;
private int securityMode = DEFAULT_MODE.code;

41
common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/LwM2mCredentialsSecurityInfoValidator.java

@ -52,15 +52,10 @@ public class LwM2mCredentialsSecurityInfoValidator {
private final LwM2mTransportContext context;
private final LwM2MTransportServerConfig config;
/**
* Request to thingsboard Response from thingsboard ValidateDeviceLwM2MCredentials
* @param endpoint -
* @param keyValue -
* @return ValidateDeviceCredentialsResponseMsg and SecurityInfo
*/
public ReadResultSecurityStore createAndValidateCredentialsSecurityInfo(String endpoint, LwM2mTransportUtil.LwM2mTypeServer keyValue) {
public EndpointSecurityInfo getEndpointSecurityInfo(String endpoint, LwM2mTransportUtil.LwM2mTypeServer keyValue) {
CountDownLatch latch = new CountDownLatch(1);
final ReadResultSecurityStore[] resultSecurityStore = new ReadResultSecurityStore[1];
final EndpointSecurityInfo[] resultSecurityStore = new EndpointSecurityInfo[1];
context.getTransportService().process(ValidateDeviceLwM2MCredentialsRequestMsg.newBuilder().setCredentialsId(endpoint).build(),
new TransportServiceCallback<>() {
@Override
@ -90,27 +85,27 @@ public class LwM2mCredentialsSecurityInfoValidator {
/**
* Create new SecurityInfo
* @param endPoint -
* @param endpoint -
* @param jsonStr -
* @param keyValue -
* @return SecurityInfo
*/
private ReadResultSecurityStore createSecurityInfo(String endPoint, String jsonStr, LwM2mTransportUtil.LwM2mTypeServer keyValue) {
ReadResultSecurityStore result = new ReadResultSecurityStore();
private EndpointSecurityInfo createSecurityInfo(String endpoint, String jsonStr, LwM2mTransportUtil.LwM2mTypeServer keyValue) {
EndpointSecurityInfo result = new EndpointSecurityInfo();
JsonObject objectMsg = LwM2mTransportUtil.validateJson(jsonStr);
if (objectMsg != null && !objectMsg.isJsonNull()) {
JsonObject object = (objectMsg.has(keyValue.type) && !objectMsg.get(keyValue.type).isJsonNull()) ? objectMsg.get(keyValue.type).getAsJsonObject() : null;
/**
* Only PSK
*/
String endPointPsk = (objectMsg.has("client")
String endpointPsk = (objectMsg.has("client")
&& objectMsg.get("client").getAsJsonObject().has("endpoint")
&& objectMsg.get("client").getAsJsonObject().get("endpoint").isJsonPrimitive()) ? objectMsg.get("client").getAsJsonObject().get("endpoint").getAsString() : null;
endPoint = (endPointPsk == null || endPointPsk.isEmpty()) ? endPoint : endPointPsk;
endpoint = (endpointPsk == null || endpointPsk.isEmpty()) ? endpoint : endpointPsk;
if (object != null && !object.isJsonNull()) {
if (keyValue.equals(LwM2mTransportUtil.LwM2mTypeServer.BOOTSTRAP)) {
result.setBootstrapJsonCredential(object);
result.setEndPoint(endPoint);
result.setEndPoint(endpoint);
result.setSecurityMode(LwM2MSecurityMode.fromSecurityMode(object.get("bootstrapServer").getAsJsonObject().get("securityMode").getAsString().toLowerCase()).code);
} else {
LwM2MSecurityMode lwM2MSecurityMode = LwM2MSecurityMode.fromSecurityMode(object.get("securityConfigClientMode").getAsString().toLowerCase());
@ -119,13 +114,13 @@ public class LwM2mCredentialsSecurityInfoValidator {
createClientSecurityInfoNoSec(result);
break;
case PSK:
createClientSecurityInfoPSK(result, endPoint, object);
createClientSecurityInfoPSK(result, endpoint, object);
break;
case RPK:
createClientSecurityInfoRPK(result, endPoint, object);
createClientSecurityInfoRPK(result, endpoint, object);
break;
case X509:
createClientSecurityInfoX509(result, endPoint);
createClientSecurityInfoX509(result, endpoint);
break;
default:
break;
@ -136,20 +131,20 @@ public class LwM2mCredentialsSecurityInfoValidator {
return result;
}
private void createClientSecurityInfoNoSec(ReadResultSecurityStore result) {
private void createClientSecurityInfoNoSec(EndpointSecurityInfo result) {
result.setSecurityInfo(null);
result.setSecurityMode(NO_SEC.code);
}
private void createClientSecurityInfoPSK(ReadResultSecurityStore result, String endPoint, JsonObject object) {
private void createClientSecurityInfoPSK(EndpointSecurityInfo result, String endpoint, JsonObject object) {
/** PSK Deserialization */
String identity = (object.has("identity") && object.get("identity").isJsonPrimitive()) ? object.get("identity").getAsString() : null;
if (identity != null && !identity.isEmpty()) {
try {
byte[] key = (object.has("key") && object.get("key").isJsonPrimitive()) ? Hex.decodeHex(object.get("key").getAsString().toCharArray()) : null;
if (key != null && key.length > 0) {
if (endPoint != null && !endPoint.isEmpty()) {
result.setSecurityInfo(SecurityInfo.newPreSharedKeyInfo(endPoint, identity, key));
if (endpoint != null && !endpoint.isEmpty()) {
result.setSecurityInfo(SecurityInfo.newPreSharedKeyInfo(endpoint, identity, key));
result.setSecurityMode(PSK.code);
}
}
@ -161,7 +156,7 @@ public class LwM2mCredentialsSecurityInfoValidator {
}
}
private void createClientSecurityInfoRPK(ReadResultSecurityStore result, String endpoint, JsonObject object) {
private void createClientSecurityInfoRPK(EndpointSecurityInfo result, String endpoint, JsonObject object) {
try {
if (object.has("key") && object.get("key").isJsonPrimitive()) {
byte[] rpkkey = Hex.decodeHex(object.get("key").getAsString().toLowerCase().toCharArray());
@ -176,7 +171,7 @@ public class LwM2mCredentialsSecurityInfoValidator {
}
}
private void createClientSecurityInfoX509(ReadResultSecurityStore result, String endpoint) {
private void createClientSecurityInfoX509(EndpointSecurityInfo result, String endpoint) {
result.setSecurityInfo(SecurityInfo.newX509CertInfo(endpoint));
result.setSecurityMode(X509.code);
}

281
common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/DefaultLwM2MTransportMsgHandler.java

@ -32,11 +32,11 @@ import org.eclipse.leshan.core.observation.Observation;
import org.eclipse.leshan.core.request.ContentFormat;
import org.eclipse.leshan.core.request.WriteRequest;
import org.eclipse.leshan.core.response.ReadResponse;
import org.eclipse.leshan.core.util.NamedThreadFactory;
import org.eclipse.leshan.server.registration.Registration;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.thingsboard.common.util.JacksonUtil;
import org.thingsboard.common.util.ThingsBoardExecutors;
import org.thingsboard.server.cache.firmware.FirmwareDataCache;
import org.thingsboard.server.common.data.Device;
import org.thingsboard.server.common.data.DeviceProfile;
@ -66,8 +66,8 @@ import org.thingsboard.server.transport.lwm2m.utils.LwM2mValueConverterImpl;
import javax.annotation.PostConstruct;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Optional;
@ -77,7 +77,6 @@ import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
@ -85,6 +84,7 @@ 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_KEY;
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.LwM2mTransportUtil.CLIENT_NOT_AUTHORIZED;
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.DEVICE_ATTRIBUTES_REQUEST;
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.FR_OBJECT_ID;
@ -103,7 +103,6 @@ import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.L
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_UPDATE;
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.SERVICE_CHANNEL;
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.convertJsonArrayToSet;
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.convertPathFromIdVerToObjectId;
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.convertPathFromObjectIdToIdVer;
@ -115,9 +114,9 @@ import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.v
@TbLwM2mTransportComponent
public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler {
private ExecutorService executorRegistered;
private ExecutorService executorUpdateRegistered;
private ExecutorService executorUnRegistered;
private ExecutorService registrationExecutor;
private ExecutorService updateRegistrationExecutor;
private ExecutorService unregistrationExecutor;
private LwM2mValueConverterImpl converter;
private final TransportService transportService;
@ -126,18 +125,18 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler
private final FirmwareDataCache firmwareDataCache;
private final LwM2mTransportServerHelper helper;
private final LwM2MJsonAdaptor adaptor;
private final LwM2mClientContext lwM2mClientContext;
private final LwM2mClientContext clientContext;
private final LwM2mTransportRequest lwM2mTransportRequest;
public DefaultLwM2MTransportMsgHandler(TransportService transportService, LwM2MTransportServerConfig config, LwM2mTransportServerHelper helper,
LwM2mClientContext lwM2mClientContext,
LwM2mClientContext clientContext,
@Lazy LwM2mTransportRequest lwM2mTransportRequest,
FirmwareDataCache firmwareDataCache,
LwM2mTransportContext context, LwM2MJsonAdaptor adaptor) {
this.transportService = transportService;
this.config = config;
this.helper = helper;
this.lwM2mClientContext = lwM2mClientContext;
this.clientContext = clientContext;
this.lwM2mTransportRequest = lwM2mTransportRequest;
this.firmwareDataCache = firmwareDataCache;
this.context = context;
@ -146,13 +145,10 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler
@PostConstruct
public void init() {
this.context.getScheduler().scheduleAtFixedRate(this::checkInactivityAndReportActivity, new Random().nextInt((int) config.getSessionReportTimeout()), config.getSessionReportTimeout(), TimeUnit.MILLISECONDS);
this.executorRegistered = Executors.newFixedThreadPool(this.config.getRegisteredPoolSize(),
new NamedThreadFactory(String.format("LwM2M %s channel registered", SERVICE_CHANNEL)));
this.executorUpdateRegistered = Executors.newFixedThreadPool(this.config.getUpdateRegisteredPoolSize(),
new NamedThreadFactory(String.format("LwM2M %s channel update registered", SERVICE_CHANNEL)));
this.executorUnRegistered = Executors.newFixedThreadPool(this.config.getUnRegisteredPoolSize(),
new NamedThreadFactory(String.format("LwM2M %s channel un registered", SERVICE_CHANNEL)));
this.context.getScheduler().scheduleAtFixedRate(this::reportActivity, new Random().nextInt((int) config.getSessionReportTimeout()), config.getSessionReportTimeout(), TimeUnit.MILLISECONDS);
this.registrationExecutor = ThingsBoardExecutors.newWorkStealingPool(this.config.getRegisteredPoolSize(), "LwM2M registration");
this.updateRegistrationExecutor = ThingsBoardExecutors.newWorkStealingPool(this.config.getUpdateRegisteredPoolSize(), "LwM2M update registration");
this.unregistrationExecutor = ThingsBoardExecutors.newWorkStealingPool(this.config.getUnRegisteredPoolSize(), "LwM2M unregistration");
this.converter = LwM2mValueConverterImpl.getInstance();
}
@ -171,14 +167,13 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler
* @param previousObservations - may be null
*/
public void onRegistered(Registration registration, Collection<Observation> previousObservations) {
executorRegistered.submit(() -> {
registrationExecutor.submit(() -> {
try {
log.warn("[{}] [{{}] Client: create after Registration", registration.getEndpoint(), registration.getId());
LwM2mClient lwM2MClient = this.lwM2mClientContext.updateInSessionsLwM2MClient(registration);
LwM2mClient lwM2MClient = this.clientContext.registerOrUpdate(registration);
if (lwM2MClient != null) {
SessionInfoProto sessionInfo = this.getValidateSessionInfo(registration);
SessionInfoProto sessionInfo = this.getSessionInfoOrCloseSession(lwM2MClient);
if (sessionInfo != null) {
this.initLwM2mClient(lwM2MClient, sessionInfo);
transportService.registerAsyncSession(sessionInfo, new LwM2mSessionMsgListener(this, sessionInfo));
transportService.process(sessionInfo, DefaultTransportService.getSessionEventMsg(SessionEvent.OPEN), null);
transportService.process(sessionInfo, TransportProtos.SubscribeToAttributeUpdatesMsg.newBuilder().build(), null);
@ -204,24 +199,18 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler
* @param registration - Registration LwM2M Client
*/
public void updatedReg(Registration registration) {
executorUpdateRegistered.submit(() -> {
updateRegistrationExecutor.submit(() -> {
try {
SessionInfoProto sessionInfo = this.getValidateSessionInfo(registration);
if (sessionInfo != null) {
this.checkInactivity(sessionInfo);
LwM2mClient lwM2MClient = this.lwM2mClientContext.getLwM2MClient(sessionInfo);
if (lwM2MClient.getDeviceId() == null && lwM2MClient.getProfileId() == null) {
initLwM2mClient(lwM2MClient, sessionInfo);
} else {
if (registration.getBindingMode().useQueueMode()) {
LwM2mQueuedRequest request;
while ((request = lwM2MClient.getQueuedRequests().poll()) != null) {
request.send();
}
LwM2mClient client = clientContext.getOrRegister(registration);
if (client != null && client.getSession() != null) {
SessionInfoProto sessionInfo = client.getSession();
this.reportActivityAndRegister(sessionInfo);
if (registration.getBindingMode().useQueueMode()) {
LwM2mQueuedRequest request;
while ((request = client.getQueuedRequests().poll()) != null) {
request.send();
}
}
log.info("Client: [{}] updatedReg [{}] name [{}] profile ", registration.getId(), registration.getEndpoint(), sessionInfo.getDeviceType());
} else {
log.error("Client: [{}] updatedReg [{}] name [{}] sessionInfo ", registration.getId(), registration.getEndpoint(), null);
}
@ -237,7 +226,7 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler
* !!! Warn: if have not finishing unReg, then this operation will be finished on next Client`s connect
*/
public void unReg(Registration registration, Collection<Observation> observations) {
executorUnRegistered.submit(() -> {
unregistrationExecutor.submit(() -> {
try {
this.setCancelObservations(registration);
this.sendLogsToThingsboard(LOG_LW2M_INFO + ": Client unRegistration", registration.getId());
@ -248,22 +237,12 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler
});
}
private void initLwM2mClient(LwM2mClient lwM2MClient, SessionInfoProto sessionInfo) {
lwM2MClient.setDeviceId(new UUID(sessionInfo.getDeviceIdMSB(), sessionInfo.getDeviceIdLSB()));
lwM2MClient.setProfileId(new UUID(sessionInfo.getDeviceProfileIdMSB(), sessionInfo.getDeviceProfileIdLSB()));
lwM2MClient.setDeviceName(sessionInfo.getDeviceName());
lwM2MClient.setDeviceProfileName(sessionInfo.getDeviceType());
}
private void closeClientSession(Registration registration) {
SessionInfoProto sessionInfo = this.getValidateSessionInfo(registration);
SessionInfoProto sessionInfo = this.getSessionInfoOrCloseSession(registration);
if (sessionInfo != null) {
transportService.deregisterSession(sessionInfo);
this.doCloseSession(sessionInfo);
lwM2mClientContext.delRemoveSessionAndListener(registration.getId());
if (lwM2mClientContext.getProfiles().size() > 0) {
this.syncSessionsAndProfiles();
}
clientContext.removeClientByRegistrationId(registration.getId());
log.info("Client close session: [{}] unReg [{}] name [{}] profile ", registration.getId(), registration.getEndpoint(), sessionInfo.getDeviceType());
} else {
log.error("Client close session: [{}] unReg [{}] name [{}] sessionInfo ", registration.getId(), registration.getEndpoint(), null);
@ -331,12 +310,12 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler
*/
@Override
public void onAttributeUpdate(AttributeUpdateNotificationMsg msg, TransportProtos.SessionInfoProto sessionInfo) {
LwM2mClient lwM2MClient = lwM2mClientContext.getLwM2mClient(new UUID(sessionInfo.getSessionIdMSB(), sessionInfo.getSessionIdLSB()));
LwM2mClient lwM2MClient = clientContext.getClient(new UUID(sessionInfo.getSessionIdMSB(), sessionInfo.getSessionIdLSB()));
if (msg.getSharedUpdatedCount() > 0) {
msg.getSharedUpdatedList().forEach(tsKvProto -> {
String pathName = tsKvProto.getKv().getKey();
String pathIdVer = this.getPresentPathIntoProfile(sessionInfo, pathName);
Object valueNew = LwM2mTransportServerHelper.getValueFromKvProto(tsKvProto.getKv());
Object valueNew = getValueFromKvProto(tsKvProto.getKv());
//TODO: react on change of the firmware name.
if (FirmwareUtil.getAttributeKey(FirmwareType.FIRMWARE, FirmwareKey.VERSION).equals(pathName) && !valueNew.equals(lwM2MClient.getFrUpdate().getCurrentFwVersion())) {
this.getInfoFirmwareUpdate(lwM2MClient);
@ -363,7 +342,7 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler
} else if (msg.getSharedDeletedCount() > 0) {
msg.getSharedUpdatedList().forEach(tsKvProto -> {
String pathName = tsKvProto.getKv().getKey();
Object valueNew = LwM2mTransportServerHelper.getValueFromKvProto(tsKvProto.getKv());
Object valueNew = getValueFromKvProto(tsKvProto.getKv());
if (FirmwareUtil.getAttributeKey(FirmwareType.FIRMWARE, FirmwareKey.VERSION).equals(pathName) && !valueNew.equals(lwM2MClient.getFrUpdate().getCurrentFwVersion())) {
lwM2MClient.getFrUpdate().setCurrentFwVersion((String) valueNew);
}
@ -378,45 +357,34 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler
*/
@Override
public void onDeviceProfileUpdate(SessionInfoProto sessionInfo, DeviceProfile deviceProfile) {
Set<String> registrationIds = lwM2mClientContext.getLwM2mClients().entrySet()
.stream()
.filter(e -> e.getValue().getProfileId().equals(deviceProfile.getUuidId()))
.map(Map.Entry::getKey).sorted().collect(Collectors.toCollection(LinkedHashSet::new));
Set<LwM2mClient> clients = clientContext.getLwM2mClients()
.stream().filter(e -> e.getProfileId().equals(deviceProfile.getUuidId())).collect(Collectors.toSet());
clients.forEach(client -> client.onDeviceProfileUpdate(deviceProfile));
Set<String> registrationIds = clients.stream().map(LwM2mClient::getRegistration).map(Registration::getId).collect(Collectors.toSet());
if (registrationIds.size() > 0) {
this.onDeviceUpdateChangeProfile(registrationIds, deviceProfile);
this.onDeviceProfileUpdate(registrationIds, deviceProfile);
}
}
/**
* @param sessionInfo -
* @param device -
* @param deviceProfileOpt -
*/
@Override
public void onDeviceUpdate(SessionInfoProto sessionInfo, Device device, Optional<DeviceProfile> deviceProfileOpt) {
Optional<String> registrationIdOpt = lwM2mClientContext.getLwM2mClients().entrySet().stream()
.filter(e -> device.getUuidId().equals(e.getValue().getDeviceId()))
.map(Map.Entry::getKey)
.findFirst();
registrationIdOpt.ifPresent(registrationId -> this.onDeviceUpdateLwM2MClient(registrationId, device, deviceProfileOpt));
//TODO: check, maybe device has multiple sessions/registrations? Is this possible according to the standard.
LwM2mClient client = clientContext.getClientByDeviceId(device.getUuidId());
if (client != null) {
this.onDeviceUpdate(client, device, deviceProfileOpt);
}
}
/**
* @param resourceUpdateMsgOpt -
*/
@Override
public void onResourceUpdate(Optional<TransportProtos.ResourceUpdateMsg> resourceUpdateMsgOpt) {
String idVer = resourceUpdateMsgOpt.get().getResourceKey();
lwM2mClientContext.getLwM2mClients().values().stream().forEach(e -> e.updateResourceModel(idVer, this.config.getModelProvider()));
clientContext.getLwM2mClients().forEach(e -> e.updateResourceModel(idVer, this.config.getModelProvider()));
}
/**
* @param resourceDeleteMsgOpt -
*/
@Override
public void onResourceDelete(Optional<TransportProtos.ResourceDeleteMsg> resourceDeleteMsgOpt) {
String pathIdVer = resourceDeleteMsgOpt.get().getResourceKey();
lwM2mClientContext.getLwM2mClients().values().stream().forEach(e -> e.deleteResources(pathIdVer, this.config.getModelProvider()));
clientContext.getLwM2mClients().forEach(e -> e.deleteResources(pathIdVer, this.config.getModelProvider()));
}
@Override
@ -424,9 +392,9 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler
Lwm2mClientRpcRequest lwm2mClientRpcRequest = null;
try {
log.info("[{}] toDeviceRpcRequest", toDeviceRequest);
Registration registration = lwM2mClientContext.getLwM2mClient(new UUID(sessionInfo.getSessionIdMSB(), sessionInfo.getSessionIdLSB())).getRegistration();
Registration registration = clientContext.getClient(new UUID(sessionInfo.getSessionIdMSB(), sessionInfo.getSessionIdLSB())).getRegistration();
lwm2mClientRpcRequest = this.getDeviceRpcRequest(toDeviceRequest, sessionInfo, registration);
if (lwm2mClientRpcRequest != null && lwm2mClientRpcRequest.getErrorMsg() != null) {
if (lwm2mClientRpcRequest.getErrorMsg() != null) {
lwm2mClientRpcRequest.setResponseCode(BAD_REQUEST.name());
this.onToDeviceRpcResponse(lwm2mClientRpcRequest.getDeviceRpcResponseResultMsg(), sessionInfo);
} else {
@ -446,13 +414,6 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler
}
}
/**
* @param toDeviceRequest -
* @param sessionInfo -
* @param registration -
* @return
* @throws IllegalArgumentException
*/
private Lwm2mClientRpcRequest getDeviceRpcRequest(TransportProtos.ToDeviceRpcRequestMsg toDeviceRequest,
SessionInfoProto sessionInfo, Registration registration) throws IllegalArgumentException {
Lwm2mClientRpcRequest lwm2mClientRpcRequest = new Lwm2mClientRpcRequest();
@ -590,35 +551,14 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler
}
/**
* This method is used to sync with sessions
* Removes a profile if not used in sessions
*/
private void syncSessionsAndProfiles() {
Map<UUID, LwM2mClientProfile> profilesClone = lwM2mClientContext.getProfiles().entrySet()
.stream()
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
profilesClone.forEach((k, v) -> {
String registrationId = lwM2mClientContext.getLwM2mClients().entrySet()
.stream()
.filter(e -> e.getValue().getProfileId().equals(k))
.findFirst()
.map(Map.Entry::getKey) // return the key of the matching entry if found
.orElse("");
if (registrationId.isEmpty()) {
lwM2mClientContext.getProfiles().remove(k);
}
});
}
/**
* @param logMsg - text msg
* @param logMsg - text msg
* @param registrationId - Id of Registration LwM2M Client
*/
@Override
public void sendLogsToThingsboard(String logMsg, String registrationId) {
SessionInfoProto sessionInfo = this.getValidateSessionInfo(registrationId);
SessionInfoProto sessionInfo = this.getSessionInfoOrCloseSession(registrationId);
if (logMsg != null && sessionInfo != null) {
if(logMsg.length() > 1024){
if (logMsg.length() > 1024) {
logMsg = logMsg.substring(0, 1024);
}
this.helper.sendParametersOnThingsboardTelemetry(this.helper.getKvLogyToThingsboard(logMsg), sessionInfo);
@ -638,8 +578,8 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler
* @param lwM2MClient - object with All parameters off client
*/
private void initLwM2mFromClientValue(Registration registration, LwM2mClient lwM2MClient) {
LwM2mClientProfile lwM2MClientProfile = lwM2mClientContext.getProfile(registration);
Set<String> clientObjects = lwM2mClientContext.getSupportedIdVerInClient(registration);
LwM2mClientProfile lwM2MClientProfile = clientContext.getProfile(registration);
Set<String> clientObjects = clientContext.getSupportedIdVerInClient(registration);
if (clientObjects != null && clientObjects.size() > 0) {
if (LWM2M_STRATEGY_2 == LwM2mTransportUtil.getClientOnlyObserveAfterConnect(lwM2MClientProfile)) {
// #2
@ -693,7 +633,7 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler
* @param path - resource
*/
private void updateResourcesValue(Registration registration, LwM2mResource lwM2mResource, String path) {
LwM2mClient lwM2MClient = lwM2mClientContext.getLwM2mClientWithReg(registration, null);
LwM2mClient lwM2MClient = clientContext.getOrRegister(registration);
if (lwM2MClient.saveResourceValue(path, lwM2mResource, this.config
.getModelProvider())) {
if (FR_PATH_RESOURCE_VER_ID.equals(convertPathFromIdVerToObjectId(path)) &&
@ -730,7 +670,7 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler
private void updateAttrTelemetry(Registration registration, Set<String> paths) {
try {
ResultsAddKeyValueProto results = getParametersFromProfile(registration, paths);
SessionInfoProto sessionInfo = this.getValidateSessionInfo(registration);
SessionInfoProto sessionInfo = this.getSessionInfoOrCloseSession(registration);
if (results != null && sessionInfo != null) {
if (results.getResultAttributes().size() > 0) {
this.helper.sendParametersOnThingsboardAttribute(results.getResultAttributes(), sessionInfo);
@ -752,7 +692,7 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler
*/
private void initReadAttrTelemetryObserveToClient(Registration registration, LwM2mClient lwM2MClient,
LwM2mTypeOper typeOper, Set<String> clientObjects) {
LwM2mClientProfile lwM2MClientProfile = lwM2mClientContext.getProfile(registration);
LwM2mClientProfile lwM2MClientProfile = clientContext.getProfile(registration);
Set<String> result = null;
ConcurrentHashMap<String, Object> params = null;
if (READ.equals(typeOper)) {
@ -784,8 +724,8 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler
lwM2MClient.getPendingReadRequests().addAll(pathSend);
ConcurrentHashMap<String, Object> finalParams = params;
pathSend.forEach(target -> {
lwM2mTransportRequest.sendAllRequest(registration, target, typeOper, ContentFormat.TLV.getName(),
finalParams != null ? finalParams.get(target) : null, this.config.getTimeout(), null);
lwM2mTransportRequest.sendAllRequest(registration, target, typeOper, ContentFormat.TLV.getName(),
finalParams != null ? finalParams.get(target) : null, this.config.getTimeout(), null);
});
if (OBSERVE.equals(typeOper)) {
lwM2MClient.initReadValue(this, null);
@ -801,23 +741,9 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler
return pathAttributes;
}
/**
* Update parameters device in LwM2MClient
* If new deviceProfile != old deviceProfile => update deviceProfile
*
* @param registrationId -
* @param device -
*/
private void onDeviceUpdateLwM2MClient(String registrationId, Device device, Optional<DeviceProfile> deviceProfileOpt) {
LwM2mClient lwM2MClient = lwM2mClientContext.getLwM2mClients().get(registrationId);
lwM2MClient.setDeviceName(device.getName());
if (!lwM2MClient.getProfileId().equals(device.getDeviceProfileId().getId())) {
Set<String> registrationIds = new HashSet<>();
registrationIds.add(registrationId);
deviceProfileOpt.ifPresent(deviceProfile -> this.onDeviceUpdateChangeProfile(registrationIds, deviceProfile));
}
lwM2MClient.setProfileId(device.getDeviceProfileId().getId());
private void onDeviceUpdate(LwM2mClient lwM2MClient, Device device, Optional<DeviceProfile> deviceProfileOpt) {
deviceProfileOpt.ifPresent(deviceProfile -> this.onDeviceProfileUpdate(Collections.singleton(lwM2MClient.getRegistration().getId()), deviceProfile));
lwM2MClient.onDeviceUpdate(device, deviceProfileOpt);
}
/**
@ -830,7 +756,7 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler
private ResultsAddKeyValueProto getParametersFromProfile(Registration registration, Set<String> path) {
if (path != null && path.size() > 0) {
ResultsAddKeyValueProto results = new ResultsAddKeyValueProto();
LwM2mClientProfile lwM2MClientProfile = lwM2mClientContext.getProfile(registration);
LwM2mClientProfile lwM2MClientProfile = clientContext.getProfile(registration);
List<TransportProtos.KeyValueProto> resultAttributes = new ArrayList<>();
lwM2MClientProfile.getPostAttributeProfile().forEach(pathIdVer -> {
if (path.contains(pathIdVer.getAsString())) {
@ -861,8 +787,8 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler
}
private TransportProtos.KeyValueProto getKvToThingsboard(String pathIdVer, Registration registration) {
LwM2mClient lwM2MClient = this.lwM2mClientContext.getLwM2mClientWithReg(null, registration.getId());
JsonObject names = lwM2mClientContext.getProfiles().get(lwM2MClient.getProfileId()).getPostKeyNameProfile();
LwM2mClient lwM2MClient = this.clientContext.getClientByRegistrationId(registration.getId());
JsonObject names = clientContext.getProfiles().get(lwM2MClient.getProfileId()).getPostKeyNameProfile();
if (names != null && names.has(pathIdVer)) {
String resourceName = names.get(pathIdVer).getAsString();
if (resourceName != null && !resourceName.isEmpty()) {
@ -960,9 +886,9 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler
* @param registrationIds -
* @param deviceProfile -
*/
private void onDeviceUpdateChangeProfile(Set<String> registrationIds, DeviceProfile deviceProfile) {
LwM2mClientProfile lwM2MClientProfileOld = lwM2mClientContext.getProfiles().get(deviceProfile.getUuidId()).clone();
if (lwM2mClientContext.addUpdateProfileParameters(deviceProfile)) {
private void onDeviceProfileUpdate(Set<String> registrationIds, DeviceProfile deviceProfile) {
LwM2mClientProfile lwM2MClientProfileOld = clientContext.getProfiles().get(deviceProfile.getUuidId()).clone();
if (clientContext.toClientProfile(deviceProfile) != null) {
// #1
JsonArray attributeOld = lwM2MClientProfileOld.getPostAttributeProfile();
Set<String> attributeSetOld = convertJsonArrayToSet(attributeOld);
@ -972,7 +898,7 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler
JsonObject keyNameOld = lwM2MClientProfileOld.getPostKeyNameProfile();
JsonObject attributeLwm2mOld = lwM2MClientProfileOld.getPostAttributeLwm2mProfile();
LwM2mClientProfile lwM2MClientProfileNew = lwM2mClientContext.getProfiles().get(deviceProfile.getUuidId());
LwM2mClientProfile lwM2MClientProfileNew = clientContext.getProfiles().get(deviceProfile.getUuidId());
JsonArray attributeNew = lwM2MClientProfileNew.getPostAttributeProfile();
Set<String> attributeSetNew = convertJsonArrayToSet(attributeNew);
JsonArray telemetryNew = lwM2MClientProfileNew.getPostTelemetryProfile();
@ -1018,7 +944,7 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler
if (sendAttrToThingsboard.getPathPostParametersAdd().size() > 0) {
// update value in Resources
registrationIds.forEach(registrationId -> {
Registration registration = lwM2mClientContext.getRegistration(registrationId);
Registration registration = clientContext.getRegistration(registrationId);
this.readObserveFromProfile(registration, sendAttrToThingsboard.getPathPostParametersAdd(), READ);
// send attr/telemetry to tingsboard for new path
this.updateAttrTelemetry(registration, sendAttrToThingsboard.getPathPostParametersAdd());
@ -1046,7 +972,7 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler
ResultsAnalyzerParameters postObserveAnalyzer = this.getAnalyzerParameters(sendObserveToClientOld.getPathPostParametersAdd(), sendObserveToClientNew.getPathPostParametersAdd());
// send Request observe to Client
registrationIds.forEach(registrationId -> {
Registration registration = lwM2mClientContext.getRegistration(registrationId);
Registration registration = clientContext.getRegistration(registrationId);
if (postObserveAnalyzer.getPathPostParametersAdd().size() > 0) {
this.readObserveFromProfile(registration, postObserveAnalyzer.getPathPostParametersAdd(), OBSERVE);
}
@ -1151,8 +1077,8 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler
// #6.2
if (analyzerParameters.getPathPostParametersAdd().size() > 0) {
registrationIds.forEach(registrationId -> {
Registration registration = this.lwM2mClientContext.getRegistration(registrationId);
Set<String> clientObjects = lwM2mClientContext.getSupportedIdVerInClient(registration);
Registration registration = this.clientContext.getRegistration(registrationId);
Set<String> clientObjects = clientContext.getSupportedIdVerInClient(registration);
Set<String> pathSend = analyzerParameters.getPathPostParametersAdd().stream().filter(target -> clientObjects.contains("/" + target.split(LWM2M_SEPARATOR_PATH)[1]))
.collect(Collectors.toUnmodifiableSet());
if (!pathSend.isEmpty()) {
@ -1165,8 +1091,8 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler
// #6.2
if (analyzerParameters.getPathPostParametersDel().size() > 0) {
registrationIds.forEach(registrationId -> {
Registration registration = this.lwM2mClientContext.getRegistration(registrationId);
Set<String> clientObjects = lwM2mClientContext.getSupportedIdVerInClient(registration);
Registration registration = this.clientContext.getRegistration(registrationId);
Set<String> clientObjects = clientContext.getSupportedIdVerInClient(registration);
Set<String> pathSend = analyzerParameters.getPathPostParametersDel().stream().filter(target -> clientObjects.contains("/" + target.split(LWM2M_SEPARATOR_PATH)[1]))
.collect(Collectors.toUnmodifiableSet());
if (!pathSend.isEmpty()) {
@ -1184,7 +1110,7 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler
}
private void cancelObserveFromProfile(Registration registration, Set<String> paramAnallyzer) {
LwM2mClient lwM2MClient = lwM2mClientContext.getLwM2mClientWithReg(registration, null);
LwM2mClient lwM2MClient = clientContext.getOrRegister(registration);
paramAnallyzer.forEach(pathIdVer -> {
if (this.getResourceValueFromLwM2MClient(lwM2MClient, pathIdVer) != null) {
lwM2mTransportRequest.sendAllRequest(registration, pathIdVer, OBSERVE_CANCEL, null,
@ -1224,8 +1150,8 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler
* @return -
*/
private String getPresentPathIntoProfile(TransportProtos.SessionInfoProto sessionInfo, String name) {
LwM2mClientProfile profile = lwM2mClientContext.getProfile(new UUID(sessionInfo.getDeviceProfileIdMSB(), sessionInfo.getDeviceProfileIdLSB()));
LwM2mClient lwM2mClient = lwM2mClientContext.getLwM2MClient(sessionInfo);
LwM2mClientProfile profile = clientContext.getProfile(new UUID(sessionInfo.getDeviceProfileIdMSB(), sessionInfo.getDeviceProfileIdLSB()));
LwM2mClient lwM2mClient = clientContext.getClient(sessionInfo);
return profile.getPostKeyNameProfile().getAsJsonObject().entrySet().stream()
.filter(e -> e.getValue().getAsString().equals(name) && validateResourceInModel(lwM2mClient, e.getKey(), false)).findFirst().map(Map.Entry::getKey)
.orElse(null);
@ -1244,7 +1170,7 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler
try {
List<TransportProtos.TsKvProto> tsKvProtos = attributesResponse.getSharedAttributeListList();
this.updateAttriuteFromThingsboard(tsKvProtos, sessionInfo);
this.updateAttributeFromThingsboard(tsKvProtos, sessionInfo);
} catch (Exception e) {
log.error(String.valueOf(e));
}
@ -1260,8 +1186,8 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler
* @param tsKvProtos
* @param sessionInfo
*/
public void updateAttriuteFromThingsboard(List<TransportProtos.TsKvProto> tsKvProtos, TransportProtos.SessionInfoProto sessionInfo) {
LwM2mClient lwM2MClient = lwM2mClientContext.getLwM2MClient(sessionInfo);
public void updateAttributeFromThingsboard(List<TransportProtos.TsKvProto> tsKvProtos, TransportProtos.SessionInfoProto sessionInfo) {
LwM2mClient lwM2MClient = clientContext.getClient(sessionInfo);
tsKvProtos.forEach(tsKvProto -> {
String pathIdVer = this.getPresentPathIntoProfile(sessionInfo, tsKvProto.getKv().getKey());
if (pathIdVer != null) {
@ -1276,7 +1202,7 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler
// #2.1
lwM2MClient.getDelayedRequests().forEach((pathIdVer, tsKvProto) -> {
this.updateResourcesValueToClient(lwM2MClient, this.getResourceValueFormatKv(lwM2MClient, pathIdVer),
this.helper.getValueFromKvProto(tsKvProto.getKv()), pathIdVer);
getValueFromKvProto(tsKvProto.getKv()), pathIdVer);
});
}
@ -1284,30 +1210,14 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler
* @param lwM2MClient -
* @return SessionInfoProto -
*/
private SessionInfoProto getNewSessionInfoProto(LwM2mClient lwM2MClient) {
private SessionInfoProto getSessionInfoOrCloseSession(LwM2mClient lwM2MClient) {
if (lwM2MClient != null) {
TransportProtos.ValidateDeviceCredentialsResponseMsg msg = lwM2MClient.getCredentialsResponse();
if (msg == null) {
log.error("[{}] [{}]", lwM2MClient.getEndpoint(), CLIENT_NOT_AUTHORIZED);
SessionInfoProto sessionInfoProto = lwM2MClient.getSession();
if (sessionInfoProto == null) {
log.info("[{}] [{}]", lwM2MClient.getEndpoint(), CLIENT_NOT_AUTHORIZED);
this.closeClientSession(lwM2MClient.getRegistration());
return null;
} else {
return SessionInfoProto.newBuilder()
.setNodeId(this.context.getNodeId())
.setSessionIdMSB(lwM2MClient.getSessionId().getMostSignificantBits())
.setSessionIdLSB(lwM2MClient.getSessionId().getLeastSignificantBits())
.setDeviceIdMSB(msg.getDeviceInfo().getDeviceIdMSB())
.setDeviceIdLSB(msg.getDeviceInfo().getDeviceIdLSB())
.setTenantIdMSB(msg.getDeviceInfo().getTenantIdMSB())
.setTenantIdLSB(msg.getDeviceInfo().getTenantIdLSB())
.setCustomerIdMSB(msg.getDeviceInfo().getCustomerIdMSB())
.setCustomerIdLSB(msg.getDeviceInfo().getCustomerIdLSB())
.setDeviceName(msg.getDeviceInfo().getDeviceName())
.setDeviceType(msg.getDeviceInfo().getDeviceType())
.setDeviceProfileIdLSB(msg.getDeviceInfo().getDeviceProfileIdLSB())
.setDeviceProfileIdMSB(msg.getDeviceInfo().getDeviceProfileIdMSB())
.build();
}
return sessionInfoProto;
}
return null;
}
@ -1316,18 +1226,16 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler
* @param registration - Registration LwM2M Client
* @return - sessionInfo after access connect client
*/
private SessionInfoProto getValidateSessionInfo(Registration registration) {
LwM2mClient lwM2MClient = lwM2mClientContext.getLwM2mClientWithReg(registration, null);
return getNewSessionInfoProto(lwM2MClient);
private SessionInfoProto getSessionInfoOrCloseSession(Registration registration) {
return getSessionInfoOrCloseSession(clientContext.getOrRegister(registration));
}
/**
* @param registrationId -
* @return -
*/
private SessionInfoProto getValidateSessionInfo(String registrationId) {
LwM2mClient lwM2MClient = lwM2mClientContext.getLwM2mClientWithReg(null, registrationId);
return lwM2MClient != null ? this.getNewSessionInfoProto(lwM2MClient) : null;
private SessionInfoProto getSessionInfoOrCloseSession(String registrationId) {
return getSessionInfoOrCloseSession(clientContext.getClientByRegistrationId(registrationId));
}
/**
@ -1335,14 +1243,14 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler
*
* @param sessionInfo -
*/
private void checkInactivity(SessionInfoProto sessionInfo) {
if (transportService.reportActivity(sessionInfo) == null) {
private void reportActivityAndRegister(SessionInfoProto sessionInfo) {
if (sessionInfo != null && transportService.reportActivity(sessionInfo) == null) {
transportService.registerAsyncSession(sessionInfo, new LwM2mSessionMsgListener(this, sessionInfo));
}
}
private void checkInactivityAndReportActivity() {
lwM2mClientContext.getLwM2mClients().forEach((key, value) -> this.checkInactivity(this.getValidateSessionInfo(key)));
private void reportActivity() {
clientContext.getLwM2mClients().forEach(client -> reportActivityAndRegister(client.getSession()));
}
/**
@ -1356,7 +1264,7 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler
* @param lwM2MClient - LwM2M Client
*/
public void putDelayedUpdateResourcesThingsboard(LwM2mClient lwM2MClient) {
SessionInfoProto sessionInfo = this.getValidateSessionInfo(lwM2MClient.getRegistration());
SessionInfoProto sessionInfo = this.getSessionInfoOrCloseSession(lwM2MClient);
if (sessionInfo != null) {
//#1.1
ConcurrentMap<String, String> keyNamesMap = this.getNamesFromProfileForSharedAttributes(lwM2MClient);
@ -1374,7 +1282,7 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler
}
public void getInfoFirmwareUpdate(LwM2mClient lwM2MClient) {
SessionInfoProto sessionInfo = this.getValidateSessionInfo(lwM2MClient.getRegistration());
SessionInfoProto sessionInfo = this.getSessionInfoOrCloseSession(lwM2MClient);
if (sessionInfo != null) {
TransportProtos.GetFirmwareRequestMsg getFirmwareRequestMsg = TransportProtos.GetFirmwareRequestMsg.newBuilder()
.setDeviceIdMSB(sessionInfo.getDeviceIdMSB())
@ -1415,7 +1323,6 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler
}
/**
*
* @param lwM2MClient -
*/
public void updateFirmwareClient(LwM2mClient lwM2MClient) {
@ -1441,7 +1348,7 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler
*/
private ConcurrentMap<String, String> getNamesFromProfileForSharedAttributes(LwM2mClient lwM2MClient) {
LwM2mClientProfile profile = lwM2mClientContext.getProfile(lwM2MClient.getProfileId());
LwM2mClientProfile profile = clientContext.getProfile(lwM2MClient.getProfileId());
return new Gson().fromJson(profile.getPostKeyNameProfile().toString(),
new TypeToken<ConcurrentHashMap<String, String>>() {
}.getType());

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

@ -115,7 +115,7 @@ public class LwM2mTransportRequest {
String target = convertPathFromIdVerToObjectId(targetIdVer);
DownlinkRequest request = null;
ContentFormat contentFormat = contentFormatName != null ? ContentFormat.fromName(contentFormatName.toUpperCase()) : ContentFormat.DEFAULT;
LwM2mClient lwM2MClient = this.lwM2mClientContext.getLwM2mClientWithReg(registration, null);
LwM2mClient lwM2MClient = this.lwM2mClientContext.getOrRegister(registration);
LwM2mPath resultIds = target != null ? new LwM2mPath(target) : null;
if (!OBSERVE_READ_ALL.name().equals(typeOper.name()) && resultIds != null && registration != null && resultIds.getObjectId() >= 0 && lwM2MClient != null) {
if (lwM2MClient.isValidObjectVersion(targetIdVer)) {

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

@ -183,7 +183,6 @@ public class LwM2mTransportUtil {
}
public static final String EVENT_AWAKE = "AWAKE";
public static final String SERVICE_CHANNEL = "SERVICE";
public static final String RESPONSE_CHANNEL = "RESP";
public static boolean equalsResourceValue(Object valueOld, Object valueNew, ResourceModel.Type type, LwM2mPath resourcePath) throws CodecException {
@ -249,7 +248,7 @@ public class LwM2mTransportUtil {
* "/3_1.0/0": {"gt": 17},
* "/3_1.0/0/9": {"pmax": 45}, "/3_1.2": {ver": "3_1.2"}}
*/
public static LwM2mClientProfile getLwM2MClientProfileFromThingsboard(DeviceProfile deviceProfile) {
public static LwM2mClientProfile toLwM2MClientProfile(DeviceProfile deviceProfile) {
if (deviceProfile != null && ((Lwm2mDeviceProfileTransportConfiguration) deviceProfile.getProfileData().getTransportConfiguration()).getProperties().size() > 0) {
Object profile = ((Lwm2mDeviceProfileTransportConfiguration) deviceProfile.getProfileData().getTransportConfiguration()).getProperties();
try {

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

@ -16,6 +16,8 @@
package org.thingsboard.server.transport.lwm2m.server.client;
import lombok.Data;
import lombok.Getter;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import org.eclipse.leshan.core.model.ResourceModel;
import org.eclipse.leshan.core.node.LwM2mPath;
@ -24,7 +26,11 @@ import org.eclipse.leshan.core.node.LwM2mSingleResource;
import org.eclipse.leshan.server.model.LwM2mModelProvider;
import org.eclipse.leshan.server.registration.Registration;
import org.eclipse.leshan.server.security.SecurityInfo;
import org.thingsboard.server.common.data.Device;
import org.thingsboard.server.common.data.DeviceProfile;
import org.thingsboard.server.gen.transport.TransportProtos;
import org.thingsboard.server.gen.transport.TransportProtos.TsKvProto;
import org.thingsboard.server.gen.transport.TransportProtos.SessionInfoProto;
import org.thingsboard.server.gen.transport.TransportProtos.ValidateDeviceCredentialsResponseMsg;
import org.thingsboard.server.transport.lwm2m.server.DefaultLwM2MTransportMsgHandler;
import org.thingsboard.server.transport.lwm2m.server.LwM2mQueuedRequest;
@ -33,6 +39,7 @@ import org.thingsboard.server.transport.lwm2m.utils.LwM2mValueConverterImpl;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Queue;
import java.util.Set;
import java.util.UUID;
@ -47,31 +54,52 @@ import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.c
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.getVerFromPathIdVerOrId;
@Slf4j
@Data
public class LwM2mClient implements Cloneable {
@Getter
private String deviceName;
@Getter
private String deviceProfileName;
@Getter
private String endpoint;
@Getter
private String identity;
@Getter
private SecurityInfo securityInfo;
@Getter
private UUID deviceId;
@Getter
private UUID sessionId;
@Getter
private SessionInfoProto session;
@Getter
private UUID profileId;
@Getter
@Setter
private volatile LwM2mFirmwareUpdate frUpdate;
@Getter
@Setter
private Registration registration;
private ValidateDeviceCredentialsResponseMsg credentialsResponse;
@Getter
private final Map<String, ResourceValue> resources;
private final Map<String, TransportProtos.TsKvProto> delayedRequests;
@Getter
private final Map<String, TsKvProto> delayedRequests;
@Getter
private final List<String> pendingReadRequests;
@Getter
private final Queue<LwM2mQueuedRequest> queuedRequests;
@Getter
private boolean init;
@Getter
@Setter
private volatile boolean updateFw;
public Object clone() throws CloneNotSupportedException {
return super.clone();
}
public LwM2mClient(String endpoint, String identity, SecurityInfo securityInfo, ValidateDeviceCredentialsResponseMsg credentialsResponse, UUID profileId, UUID sessionId) {
public LwM2mClient(String nodeId, String endpoint, String identity, SecurityInfo securityInfo, ValidateDeviceCredentialsResponseMsg credentialsResponse, UUID profileId, UUID sessionId) {
this.endpoint = endpoint;
this.identity = identity;
this.securityInfo = securityInfo;
@ -85,6 +113,56 @@ public class LwM2mClient implements Cloneable {
this.updateFw = false;
this.queuedRequests = new ConcurrentLinkedQueue<>();
this.frUpdate = new LwM2mFirmwareUpdate();
if (this.credentialsResponse != null && this.credentialsResponse.hasDeviceInfo()) {
this.session = createSession(nodeId, sessionId, credentialsResponse);
this.deviceId = new UUID(session.getDeviceIdMSB(), session.getDeviceIdLSB());
this.profileId = new UUID(session.getDeviceProfileIdMSB(), session.getDeviceProfileIdLSB());
this.deviceName = session.getDeviceName();
this.deviceProfileName = session.getDeviceType();
}
}
public void onDeviceUpdate(Device device, Optional<DeviceProfile> deviceProfileOpt) {
SessionInfoProto.Builder builder = SessionInfoProto.newBuilder().mergeFrom(session);
this.deviceId = device.getUuidId();
this.deviceName = device.getName();
builder.setDeviceIdMSB(deviceId.getMostSignificantBits());
builder.setDeviceIdLSB(deviceId.getLeastSignificantBits());
builder.setDeviceName(deviceName);
deviceProfileOpt.ifPresent(deviceProfile -> updateSession(deviceProfile, builder));
this.session = builder.build();
}
public void onDeviceProfileUpdate(DeviceProfile deviceProfile) {
SessionInfoProto.Builder builder = SessionInfoProto.newBuilder().mergeFrom(session);
updateSession(deviceProfile, builder);
this.session = builder.build();
}
private void updateSession(DeviceProfile deviceProfile, SessionInfoProto.Builder builder) {
this.deviceProfileName = deviceProfile.getName();
this.profileId = deviceProfile.getUuidId();
builder.setDeviceProfileIdMSB(profileId.getMostSignificantBits());
builder.setDeviceProfileIdLSB(profileId.getLeastSignificantBits());
builder.setDeviceType(this.deviceProfileName);
}
private SessionInfoProto createSession(String nodeId, UUID sessionId, ValidateDeviceCredentialsResponseMsg msg) {
return SessionInfoProto.newBuilder()
.setNodeId(nodeId)
.setSessionIdMSB(sessionId.getMostSignificantBits())
.setSessionIdLSB(sessionId.getLeastSignificantBits())
.setDeviceIdMSB(msg.getDeviceInfo().getDeviceIdMSB())
.setDeviceIdLSB(msg.getDeviceInfo().getDeviceIdLSB())
.setTenantIdMSB(msg.getDeviceInfo().getTenantIdMSB())
.setTenantIdLSB(msg.getDeviceInfo().getTenantIdLSB())
.setCustomerIdMSB(msg.getDeviceInfo().getCustomerIdMSB())
.setCustomerIdLSB(msg.getDeviceInfo().getCustomerIdLSB())
.setDeviceName(msg.getDeviceInfo().getDeviceName())
.setDeviceType(msg.getDeviceInfo().getDeviceType())
.setDeviceProfileIdLSB(msg.getDeviceInfo().getDeviceProfileIdLSB())
.setDeviceProfileIdMSB(msg.getDeviceInfo().getDeviceProfileIdMSB())
.build();
}
public boolean saveResourceValue(String pathRez, LwM2mResource rez, LwM2mModelProvider modelProvider) {
@ -123,7 +201,7 @@ public class LwM2mClient implements Cloneable {
return resources;
}
public boolean isValidObjectVersion (String path) {
public boolean isValidObjectVersion(String path) {
LwM2mPath pathIds = new LwM2mPath(convertPathFromIdVerToObjectId(path));
String verSupportedObject = registration.getSupportedObject().get(pathIds.getObjectId());
String verRez = getVerFromPathIdVerOrId(path);
@ -131,8 +209,7 @@ public class LwM2mClient implements Cloneable {
}
/**
*
* @param pathIdVer == "3_1.0"
* @param pathIdVer == "3_1.0"
* @param modelProvider -
*/
public void deleteResources(String pathIdVer, LwM2mModelProvider modelProvider) {
@ -142,16 +219,14 @@ public class LwM2mClient implements Cloneable {
ResourceModel resourceModel = modelProvider.getObjectModel(registration).getResourceModel(pathIds.getObjectId(), pathIds.getResourceId());
if (resourceModel != null) {
this.resources.get(pathRez).setResourceModel(resourceModel);
}
else {
} else {
this.resources.remove(pathRez);
}
});
}
/**
*
* @param idVer -
* @param idVer -
* @param modelProvider -
*/
public void updateResourceModel(String idVer, LwM2mModelProvider modelProvider) {
@ -182,8 +257,5 @@ public class LwM2mClient implements Cloneable {
}
}
public LwM2mClient copy() {
return new LwM2mClient(this.endpoint, this.identity, this.securityInfo, this.credentialsResponse, this.profileId, this.sessionId);
}
}

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

@ -19,29 +19,32 @@ import org.eclipse.leshan.server.registration.Registration;
import org.thingsboard.server.common.data.DeviceProfile;
import org.thingsboard.server.gen.transport.TransportProtos;
import java.util.Collection;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
public interface LwM2mClientContext {
void delRemoveSessionAndListener(String registrationId);
void removeClientByRegistrationId(String registrationId);
LwM2mClient getLwM2MClient(String endPoint, String identity);
LwM2mClient getClientByEndpoint(String endpoint);
LwM2mClient getLwM2MClient(TransportProtos.SessionInfoProto sessionInfo);
LwM2mClient getClientByRegistrationId(String registrationId);
LwM2mClient getLwM2mClient(UUID sessionId);
LwM2mClient getClient(TransportProtos.SessionInfoProto sessionInfo);
LwM2mClient getLwM2mClientWithReg(Registration registration, String registrationId);
LwM2mClient getClient(UUID sessionId);
LwM2mClient updateInSessionsLwM2MClient(Registration registration);
LwM2mClient getOrRegister(Registration registration);
LwM2mClient addLwM2mClientToSession(String identity);
LwM2mClient registerOrUpdate(Registration registration);
LwM2mClient fetchClientByEndpoint(String endpoint);
Registration getRegistration(String registrationId);
Map<String, LwM2mClient> getLwM2mClients();
Collection<LwM2mClient> getLwM2mClients();
Map<UUID, LwM2mClientProfile> getProfiles();
@ -51,7 +54,9 @@ public interface LwM2mClientContext {
Map<UUID, LwM2mClientProfile> setProfiles(Map<UUID, LwM2mClientProfile> profiles);
boolean addUpdateProfileParameters(DeviceProfile deviceProfile);
LwM2mClientProfile toClientProfile(DeviceProfile deviceProfile);
Set<String> getSupportedIdVerInClient(Registration registration);
LwM2mClient getClientByDeviceId(UUID deviceId);
}

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

@ -15,6 +15,7 @@
*/
package org.thingsboard.server.transport.lwm2m.server.client;
import lombok.RequiredArgsConstructor;
import org.eclipse.leshan.core.node.LwM2mPath;
import org.eclipse.leshan.server.registration.Registration;
import org.eclipse.leshan.server.security.EditableSecurityStore;
@ -24,123 +25,121 @@ import org.thingsboard.server.gen.transport.TransportProtos;
import org.thingsboard.server.queue.util.TbLwM2mTransportComponent;
import org.thingsboard.server.transport.lwm2m.secure.LwM2MSecurityMode;
import org.thingsboard.server.transport.lwm2m.secure.LwM2mCredentialsSecurityInfoValidator;
import org.thingsboard.server.transport.lwm2m.secure.ReadResultSecurityStore;
import org.thingsboard.server.transport.lwm2m.secure.EndpointSecurityInfo;
import org.thingsboard.server.transport.lwm2m.server.LwM2mTransportContext;
import org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil;
import java.util.Arrays;
import java.util.Collection;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;
import static org.thingsboard.server.transport.lwm2m.secure.LwM2MSecurityMode.NO_SEC;
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.convertPathFromObjectIdToIdVer;
@Service
@TbLwM2mTransportComponent
@RequiredArgsConstructor
public class LwM2mClientContextImpl implements LwM2mClientContext {
private static final boolean INFOS_ARE_COMPROMISED = false;
private final Map<String /** registrationId */, LwM2mClient> lwM2mClients = new ConcurrentHashMap<>();
private Map<UUID /** profileUUid */, LwM2mClientProfile> profiles = new ConcurrentHashMap<>();
private final LwM2mTransportContext context;
private final Map<String, LwM2mClient> lwM2mClientsByEndpoint = new ConcurrentHashMap<>();
private final Map<String, LwM2mClient> lwM2mClientsByRegistrationId = new ConcurrentHashMap<>();
private Map<UUID, LwM2mClientProfile> profiles = new ConcurrentHashMap<>();
private final LwM2mCredentialsSecurityInfoValidator lwM2MCredentialsSecurityInfoValidator;
private final EditableSecurityStore securityStore;
public LwM2mClientContextImpl(LwM2mCredentialsSecurityInfoValidator lwM2MCredentialsSecurityInfoValidator, EditableSecurityStore securityStore) {
this.lwM2MCredentialsSecurityInfoValidator = lwM2MCredentialsSecurityInfoValidator;
this.securityStore = securityStore;
}
public void delRemoveSessionAndListener(String registrationId) {
LwM2mClient lwM2MClient = this.lwM2mClients.get(registrationId);
if (lwM2MClient != null) {
this.securityStore.remove(lwM2MClient.getEndpoint(), INFOS_ARE_COMPROMISED);
this.lwM2mClients.remove(registrationId);
}
@Override
public LwM2mClient getClientByEndpoint(String endpoint) {
return lwM2mClientsByEndpoint.get(endpoint);
}
@Override
public LwM2mClient getLwM2MClient(String endPoint, String identity) {
Map.Entry<String, LwM2mClient> modelClients = endPoint != null ?
this.lwM2mClients.entrySet().stream().filter(model -> endPoint.equals(model.getValue().getEndpoint())).findAny().orElse(null) :
this.lwM2mClients.entrySet().stream().filter(model -> identity.equals(model.getValue().getIdentity())).findAny().orElse(null);
return modelClients != null ? modelClients.getValue() : null;
public LwM2mClient getClientByRegistrationId(String registrationId) {
return lwM2mClientsByRegistrationId.get(registrationId);
}
@Override
public LwM2mClient getLwM2MClient(TransportProtos.SessionInfoProto sessionInfo) {
return getLwM2mClient(new UUID(sessionInfo.getSessionIdMSB(), sessionInfo.getSessionIdLSB()));
public LwM2mClient getOrRegister(Registration registration) {
if (registration == null) {
return null;
}
LwM2mClient client = lwM2mClientsByRegistrationId.get(registration.getId());
if (client == null) {
client = lwM2mClientsByEndpoint.get(registration.getEndpoint());
if (client == null) {
client = registerOrUpdate(registration);
}
}
return client;
}
@Override
public LwM2mClient getLwM2mClient(UUID sessionId) {
return lwM2mClients.values().stream().filter(c -> c.getSessionId().equals(sessionId)).findAny().get();
public LwM2mClient getClient(TransportProtos.SessionInfoProto sessionInfo) {
return getClient(new UUID(sessionInfo.getSessionIdMSB(), sessionInfo.getSessionIdLSB()));
}
@Override
public LwM2mClient getLwM2mClientWithReg(Registration registration, String registrationId) {
LwM2mClient client = registrationId != null && this.lwM2mClients.containsKey(registrationId) ?
this.lwM2mClients.get(registrationId) :
registration !=null && this.lwM2mClients.containsKey(registration.getId()) ?
this.lwM2mClients.get(registration.getId()) : registration !=null && this.lwM2mClients.containsKey(registration) ?
this.lwM2mClients.get(registration.getEndpoint()) : null;
return client != null ? client : registration!= null ? updateInSessionsLwM2MClient(registration) : null;
public LwM2mClient getClient(UUID sessionId) {
//TODO: refactor this to search by sessionId efficiently.
return lwM2mClientsByEndpoint.values().stream().filter(c -> c.getSessionId().equals(sessionId)).findAny().get();
}
@Override
public LwM2mClient updateInSessionsLwM2MClient(Registration registration) {
if (this.lwM2mClients.get(registration.getEndpoint()) == null) {
this.addLwM2mClientToSession(registration.getEndpoint());
public LwM2mClient registerOrUpdate(Registration registration) {
LwM2mClient lwM2MClient = lwM2mClientsByEndpoint.get(registration.getEndpoint());
if (lwM2MClient == null) {
lwM2MClient = this.fetchClientByEndpoint(registration.getEndpoint());
}
LwM2mClient lwM2MClient = lwM2mClients.get(registration.getEndpoint());
lwM2MClient.setRegistration(registration);
this.lwM2mClients.remove(registration.getEndpoint());
this.lwM2mClients.put(registration.getId(), lwM2MClient);
// TODO: this remove is probably redundant. We should remove it.
// this.lwM2mClientsByEndpoint.remove(registration.getEndpoint());
this.lwM2mClientsByRegistrationId.put(registration.getId(), lwM2MClient);
return lwM2MClient;
}
public Registration getRegistration(String registrationId) {
return this.lwM2mClients.get(registrationId).getRegistration();
return this.lwM2mClientsByRegistrationId.get(registrationId).getRegistration();
}
/**
* Add new LwM2MClient to session
*
* @param identity-
* @return SecurityInfo. If error - SecurityInfoError
* and log:
* - FORBIDDEN - if there is no authorization
* - profileUuid - if the device does not have a profile
* - device - if the thingsboard does not have a device with a name equal to the identity
*/
@Override
public LwM2mClient addLwM2mClientToSession(String identity) {
ReadResultSecurityStore store = lwM2MCredentialsSecurityInfoValidator.createAndValidateCredentialsSecurityInfo(identity, LwM2mTransportUtil.LwM2mTypeServer.CLIENT);
if (store.getSecurityMode() < LwM2MSecurityMode.DEFAULT_MODE.code) {
UUID profileUuid = (store.getDeviceProfile() != null && addUpdateProfileParameters(store.getDeviceProfile())) ? store.getDeviceProfile().getUuidId() : null;
LwM2mClient client;
if (store.getSecurityInfo() != null && profileUuid != null) {
String endpoint = store.getSecurityInfo().getEndpoint();
client = new LwM2mClient(endpoint, store.getSecurityInfo().getIdentity(), store.getSecurityInfo(), store.getMsg(), profileUuid, UUID.randomUUID());
lwM2mClients.put(endpoint, client);
} else if (store.getSecurityMode() == NO_SEC.code && profileUuid != null) {
client = new LwM2mClient(identity, null, null, store.getMsg(), profileUuid, UUID.randomUUID());
lwM2mClients.put(identity, client);
public LwM2mClient fetchClientByEndpoint(String endpoint) {
EndpointSecurityInfo securityInfo = lwM2MCredentialsSecurityInfoValidator.getEndpointSecurityInfo(endpoint, LwM2mTransportUtil.LwM2mTypeServer.CLIENT);
if (securityInfo.getSecurityMode() < LwM2MSecurityMode.DEFAULT_MODE.code) {
if (securityInfo.getDeviceProfile() != null) {
toClientProfile(securityInfo.getDeviceProfile());
UUID profileUuid = securityInfo.getDeviceProfile().getUuidId();
LwM2mClient client;
if (securityInfo.getSecurityInfo() != null) {
client = new LwM2mClient(context.getNodeId(), securityInfo.getSecurityInfo().getEndpoint(),
securityInfo.getSecurityInfo().getIdentity(), securityInfo.getSecurityInfo(),
securityInfo.getMsg(), profileUuid, UUID.randomUUID());
} else if (securityInfo.getSecurityMode() == NO_SEC.code) {
client = new LwM2mClient(context.getNodeId(), endpoint,
null, null,
securityInfo.getMsg(), profileUuid, UUID.randomUUID());
} else {
throw new RuntimeException(String.format("Registration failed: device %s not found.", endpoint));
}
lwM2mClientsByEndpoint.put(client.getEndpoint(), client);
return client;
} else {
throw new RuntimeException(String.format("Registration failed: FORBIDDEN/profileUuid/device %s , endpointId: %s [PSK]", profileUuid, identity));
throw new RuntimeException(String.format("Registration failed: device %s not found.", endpoint));
}
return client;
} else {
throw new RuntimeException(String.format("Registration failed: FORBIDDEN, endpointId: %s", identity));
throw new RuntimeException(String.format("Registration failed: FORBIDDEN, endpointId: %s", endpoint));
}
}
@Override
public Map<String, LwM2mClient> getLwM2mClients() {
return lwM2mClients;
public Collection<LwM2mClient> getLwM2mClients() {
return lwM2mClientsByEndpoint.values();
}
@Override
@ -155,7 +154,7 @@ public class LwM2mClientContextImpl implements LwM2mClientContext {
@Override
public LwM2mClientProfile getProfile(Registration registration) {
return this.getProfiles().get(getLwM2mClientWithReg(registration, null).getProfileId());
return this.getProfiles().get(getOrRegister(registration).getProfileId());
}
@Override
@ -164,17 +163,18 @@ public class LwM2mClientContextImpl implements LwM2mClientContext {
}
@Override
public boolean addUpdateProfileParameters(DeviceProfile deviceProfile) {
LwM2mClientProfile lwM2MClientProfile = LwM2mTransportUtil.getLwM2MClientProfileFromThingsboard(deviceProfile);
if (lwM2MClientProfile != null) {
public LwM2mClientProfile toClientProfile(DeviceProfile deviceProfile) {
LwM2mClientProfile lwM2MClientProfile = profiles.get(deviceProfile.getUuidId());
if (lwM2MClientProfile == null) {
lwM2MClientProfile = LwM2mTransportUtil.toLwM2MClientProfile(deviceProfile);
profiles.put(deviceProfile.getUuidId(), lwM2MClientProfile);
return true;
}
return false;
return lwM2MClientProfile;
}
/**
* if isVer - ok or default ver=DEFAULT_LWM2M_VERSION
*
* @param registration -
* @return - all objectIdVer in client
*/
@ -184,9 +184,31 @@ public class LwM2mClientContextImpl implements LwM2mClientContext {
Arrays.stream(registration.getObjectLinks()).forEach(url -> {
LwM2mPath pathIds = new LwM2mPath(url.getUrl());
if (!pathIds.isRoot()) {
clientObjects.add(convertPathFromObjectIdToIdVer(url.getUrl(), registration));
clientObjects.add(convertPathFromObjectIdToIdVer(url.getUrl(), registration));
}
});
return (clientObjects.size() > 0) ? clientObjects : null;
}
@Override
public LwM2mClient getClientByDeviceId(UUID deviceId) {
return lwM2mClientsByRegistrationId.values().stream().filter(e -> deviceId.equals(e.getDeviceId())).findFirst().orElse(null);
}
@Override
public void removeClientByRegistrationId(String registrationId) {
LwM2mClient lwM2MClient = this.lwM2mClientsByRegistrationId.get(registrationId);
if (lwM2MClient != null) {
this.securityStore.remove(lwM2MClient.getEndpoint(), false);
this.lwM2mClientsByEndpoint.remove(lwM2MClient.getEndpoint());
this.lwM2mClientsByRegistrationId.remove(registrationId);
UUID profileId = lwM2MClient.getProfileId();
if (profileId != null) {
Optional<LwM2mClient> otherClients = lwM2mClientsByRegistrationId.values().stream().filter(e -> e.getProfileId().equals(profileId)).findFirst();
if (otherClients.isEmpty()) {
profiles.remove(profileId);
}
}
}
}
}

94
common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/store/TbLwM2mSecurityStore.java

@ -0,0 +1,94 @@
/**
* 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.store;
import lombok.extern.slf4j.Slf4j;
import org.eclipse.leshan.server.security.EditableSecurityStore;
import org.eclipse.leshan.server.security.NonUniqueSecurityInfoException;
import org.eclipse.leshan.server.security.SecurityInfo;
import org.eclipse.leshan.server.security.SecurityStoreListener;
import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient;
import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClientContext;
import java.util.Collection;
@Slf4j
public class TbLwM2mSecurityStore implements EditableSecurityStore {
private final LwM2mClientContext clientContext;
private final EditableSecurityStore securityStore;
public TbLwM2mSecurityStore(LwM2mClientContext clientContext, EditableSecurityStore securityStore) {
this.clientContext = clientContext;
this.securityStore = securityStore;
}
@Override
public Collection<SecurityInfo> getAll() {
return securityStore.getAll();
}
@Override
public SecurityInfo add(SecurityInfo info) throws NonUniqueSecurityInfoException {
return securityStore.add(info);
}
@Override
public SecurityInfo remove(String endpoint, boolean infosAreCompromised) {
return securityStore.remove(endpoint, infosAreCompromised);
}
@Override
public void setListener(SecurityStoreListener listener) {
securityStore.setListener(listener);
}
@Override
public SecurityInfo getByEndpoint(String endpoint) {
SecurityInfo securityInfo = securityStore.getByEndpoint(endpoint);
if (securityInfo == null) {
LwM2mClient lwM2mClient = clientContext.getClientByEndpoint(endpoint);
if (lwM2mClient != null && lwM2mClient.getRegistration() != null && !lwM2mClient.getRegistration().getIdentity().isSecure()) {
return null;
}
securityInfo = clientContext.fetchClientByEndpoint(endpoint).getSecurityInfo();
try {
if (securityInfo != null) {
add(securityInfo);
}
} catch (NonUniqueSecurityInfoException e) {
log.warn("Failed to add security info: {}", securityInfo, e);
}
}
return securityInfo;
}
@Override
public SecurityInfo getByIdentity(String pskIdentity) {
SecurityInfo securityInfo = securityStore.getByIdentity(pskIdentity);
if (securityInfo == null) {
securityInfo = clientContext.fetchClientByEndpoint(pskIdentity).getSecurityInfo();
try {
if (securityInfo != null) {
add(securityInfo);
}
} catch (NonUniqueSecurityInfoException e) {
log.warn("Failed to add security info: {}", securityInfo, e);
}
}
return securityInfo;
}
}

128
common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/store/TbLwM2mStoreConfiguration.java

@ -1,128 +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.store;
import org.eclipse.leshan.server.californium.registration.CaliforniumRegistrationStore;
import org.eclipse.leshan.server.californium.registration.InMemoryRegistrationStore;
import org.eclipse.leshan.server.security.EditableSecurityStore;
import org.eclipse.leshan.server.security.InMemorySecurityStore;
import org.eclipse.leshan.server.security.NonUniqueSecurityInfoException;
import org.eclipse.leshan.server.security.SecurityInfo;
import org.eclipse.leshan.server.security.SecurityStoreListener;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.thingsboard.server.cache.TBRedisCacheConfiguration;
import org.thingsboard.server.queue.util.TbLwM2mTransportComponent;
import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient;
import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClientContext;
import java.util.Collection;
import java.util.Optional;
@Service
@TbLwM2mTransportComponent
public class TbLwM2mStoreConfiguration {
@Autowired(required = false)
private Optional<TBRedisCacheConfiguration> redisConfiguration;
@Autowired
@Lazy
private LwM2mClientContext clientContext;
@Value("${transport.lwm2m.redis.enabled:false}")
private boolean useRedis;
@Bean
private CaliforniumRegistrationStore registrationStore() {
return redisConfiguration.isPresent() && useRedis ?
new TbLwM2mRedisRegistrationStore(redisConfiguration.get().redisConnectionFactory()) : new InMemoryRegistrationStore();
}
@Bean
private EditableSecurityStore securityStore() {
return new TbLwM2mSecurityStoreWrapper(redisConfiguration.isPresent() && useRedis ?
new TbLwM2mRedisSecurityStore(redisConfiguration.get().redisConnectionFactory()) : new InMemorySecurityStore());
}
public class TbLwM2mSecurityStoreWrapper implements EditableSecurityStore {
private final EditableSecurityStore securityStore;
public TbLwM2mSecurityStoreWrapper(EditableSecurityStore securityStore) {
this.securityStore = securityStore;
}
@Override
public Collection<SecurityInfo> getAll() {
return securityStore.getAll();
}
@Override
public SecurityInfo add(SecurityInfo info) throws NonUniqueSecurityInfoException {
return securityStore.add(info);
}
@Override
public SecurityInfo remove(String endpoint, boolean infosAreCompromised) {
return securityStore.remove(endpoint, infosAreCompromised);
}
@Override
public void setListener(SecurityStoreListener listener) {
securityStore.setListener(listener);
}
@Override
public SecurityInfo getByEndpoint(String endPoint) {
SecurityInfo securityInfo = securityStore.getByEndpoint(endPoint);
if (securityInfo == null) {
LwM2mClient lwM2mClient = clientContext.getLwM2MClient(endPoint, null);
if (lwM2mClient != null && lwM2mClient.getRegistration() != null && !lwM2mClient.getRegistration().getIdentity().isSecure()){
return null;
}
securityInfo = clientContext.addLwM2mClientToSession(endPoint).getSecurityInfo();
try {
if (securityInfo != null) {
add(securityInfo);
}
} catch (NonUniqueSecurityInfoException e) {
e.printStackTrace();
}
}
return securityInfo;
}
@Override
public SecurityInfo getByIdentity(String pskIdentity) {
SecurityInfo securityInfo = securityStore.getByIdentity(pskIdentity);
if (securityInfo == null) {
securityInfo = clientContext.addLwM2mClientToSession(pskIdentity).getSecurityInfo();
try {
if (securityInfo != null) {
add(securityInfo);
}
} catch (NonUniqueSecurityInfoException e) {
e.printStackTrace();
}
}
return securityInfo;
}
}
}

59
common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/store/TbLwM2mStoreFactory.java

@ -0,0 +1,59 @@
/**
* 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.store;
import org.eclipse.leshan.server.californium.registration.CaliforniumRegistrationStore;
import org.eclipse.leshan.server.californium.registration.InMemoryRegistrationStore;
import org.eclipse.leshan.server.security.EditableSecurityStore;
import org.eclipse.leshan.server.security.InMemorySecurityStore;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component;
import org.thingsboard.server.cache.TBRedisCacheConfiguration;
import org.thingsboard.server.queue.util.TbLwM2mTransportComponent;
import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClientContext;
import java.util.Optional;
@Component
@TbLwM2mTransportComponent
public class TbLwM2mStoreFactory {
@Autowired(required = false)
private Optional<TBRedisCacheConfiguration> redisConfiguration;
@Autowired
@Lazy
private LwM2mClientContext clientContext;
@Value("${transport.lwm2m.redis.enabled:false}")
private boolean useRedis;
@Bean
private CaliforniumRegistrationStore registrationStore() {
return redisConfiguration.isPresent() && useRedis ?
new TbLwM2mRedisRegistrationStore(redisConfiguration.get().redisConnectionFactory()) : new InMemoryRegistrationStore();
}
@Bean
private EditableSecurityStore securityStore() {
return new TbLwM2mSecurityStore(clientContext, redisConfiguration.isPresent() && useRedis ?
new TbLwM2mRedisSecurityStore(redisConfiguration.get().redisConnectionFactory()) : new InMemorySecurityStore());
}
}
Loading…
Cancel
Save