diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2MBootstrapSecurityStore.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2MBootstrapSecurityStore.java index d1e136d6f3..68c1ff405d 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2MBootstrapSecurityStore.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2MBootstrapSecurityStore.java @@ -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 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) { diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/ReadResultSecurityStore.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/EndpointSecurityInfo.java similarity index 97% rename from common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/ReadResultSecurityStore.java rename to common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/EndpointSecurityInfo.java index 30f15116af..851934a806 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/ReadResultSecurityStore.java +++ b/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; diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/LwM2mCredentialsSecurityInfoValidator.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/LwM2mCredentialsSecurityInfoValidator.java index 7154a234a4..0263e72fb2 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/LwM2mCredentialsSecurityInfoValidator.java +++ b/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); } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/DefaultLwM2MTransportMsgHandler.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/DefaultLwM2MTransportMsgHandler.java index 4ab206e856..e2e0184230 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/DefaultLwM2MTransportMsgHandler.java +++ b/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 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 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 registrationIds = lwM2mClientContext.getLwM2mClients().entrySet() - .stream() - .filter(e -> e.getValue().getProfileId().equals(deviceProfile.getUuidId())) - .map(Map.Entry::getKey).sorted().collect(Collectors.toCollection(LinkedHashSet::new)); + Set clients = clientContext.getLwM2mClients() + .stream().filter(e -> e.getProfileId().equals(deviceProfile.getUuidId())).collect(Collectors.toSet()); + clients.forEach(client -> client.onDeviceProfileUpdate(deviceProfile)); + Set 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 deviceProfileOpt) { - Optional 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 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 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 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 clientObjects = lwM2mClientContext.getSupportedIdVerInClient(registration); + LwM2mClientProfile lwM2MClientProfile = clientContext.getProfile(registration); + Set 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 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 clientObjects) { - LwM2mClientProfile lwM2MClientProfile = lwM2mClientContext.getProfile(registration); + LwM2mClientProfile lwM2MClientProfile = clientContext.getProfile(registration); Set result = null; ConcurrentHashMap params = null; if (READ.equals(typeOper)) { @@ -784,8 +724,8 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler lwM2MClient.getPendingReadRequests().addAll(pathSend); ConcurrentHashMap 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 deviceProfileOpt) { - LwM2mClient lwM2MClient = lwM2mClientContext.getLwM2mClients().get(registrationId); - lwM2MClient.setDeviceName(device.getName()); - if (!lwM2MClient.getProfileId().equals(device.getDeviceProfileId().getId())) { - Set 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 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 path) { if (path != null && path.size() > 0) { ResultsAddKeyValueProto results = new ResultsAddKeyValueProto(); - LwM2mClientProfile lwM2MClientProfile = lwM2mClientContext.getProfile(registration); + LwM2mClientProfile lwM2MClientProfile = clientContext.getProfile(registration); List 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 registrationIds, DeviceProfile deviceProfile) { - LwM2mClientProfile lwM2MClientProfileOld = lwM2mClientContext.getProfiles().get(deviceProfile.getUuidId()).clone(); - if (lwM2mClientContext.addUpdateProfileParameters(deviceProfile)) { + private void onDeviceProfileUpdate(Set registrationIds, DeviceProfile deviceProfile) { + LwM2mClientProfile lwM2MClientProfileOld = clientContext.getProfiles().get(deviceProfile.getUuidId()).clone(); + if (clientContext.toClientProfile(deviceProfile) != null) { // #1 JsonArray attributeOld = lwM2MClientProfileOld.getPostAttributeProfile(); Set 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 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 clientObjects = lwM2mClientContext.getSupportedIdVerInClient(registration); + Registration registration = this.clientContext.getRegistration(registrationId); + Set clientObjects = clientContext.getSupportedIdVerInClient(registration); Set 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 clientObjects = lwM2mClientContext.getSupportedIdVerInClient(registration); + Registration registration = this.clientContext.getRegistration(registrationId); + Set clientObjects = clientContext.getSupportedIdVerInClient(registration); Set 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 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 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 tsKvProtos, TransportProtos.SessionInfoProto sessionInfo) { - LwM2mClient lwM2MClient = lwM2mClientContext.getLwM2MClient(sessionInfo); + public void updateAttributeFromThingsboard(List 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 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 getNamesFromProfileForSharedAttributes(LwM2mClient lwM2MClient) { - LwM2mClientProfile profile = lwM2mClientContext.getProfile(lwM2MClient.getProfileId()); + LwM2mClientProfile profile = clientContext.getProfile(lwM2MClient.getProfileId()); return new Gson().fromJson(profile.getPostKeyNameProfile().toString(), new TypeToken>() { }.getType()); diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mTransportRequest.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mTransportRequest.java index 4e0b0740b1..92a2a59e9a 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mTransportRequest.java +++ b/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)) { diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mTransportUtil.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mTransportUtil.java index 6a8e74f229..8b6e46172a 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mTransportUtil.java +++ b/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 { diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClient.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClient.java index 8577e177c4..a934779e03 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClient.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClient.java @@ -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 resources; - private final Map delayedRequests; + @Getter + private final Map delayedRequests; + @Getter private final List pendingReadRequests; + @Getter private final Queue 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 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); - } } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClientContext.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClientContext.java index 358f760fef..8e7f6a70ec 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClientContext.java +++ b/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 getLwM2mClients(); + Collection getLwM2mClients(); Map getProfiles(); @@ -51,7 +54,9 @@ public interface LwM2mClientContext { Map setProfiles(Map profiles); - boolean addUpdateProfileParameters(DeviceProfile deviceProfile); + LwM2mClientProfile toClientProfile(DeviceProfile deviceProfile); Set getSupportedIdVerInClient(Registration registration); + + LwM2mClient getClientByDeviceId(UUID deviceId); } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClientContextImpl.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClientContextImpl.java index d209d8d829..4afe54c056 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClientContextImpl.java +++ b/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 lwM2mClients = new ConcurrentHashMap<>(); - private Map profiles = new ConcurrentHashMap<>(); + private final LwM2mTransportContext context; + private final Map lwM2mClientsByEndpoint = new ConcurrentHashMap<>(); + private final Map lwM2mClientsByRegistrationId = new ConcurrentHashMap<>(); + private Map 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 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 getLwM2mClients() { - return lwM2mClients; + public Collection 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 otherClients = lwM2mClientsByRegistrationId.values().stream().filter(e -> e.getProfileId().equals(profileId)).findFirst(); + if (otherClients.isEmpty()) { + profiles.remove(profileId); + } + } + } + } } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/store/TbLwM2mSecurityStore.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/store/TbLwM2mSecurityStore.java new file mode 100644 index 0000000000..e6ed99c5e6 --- /dev/null +++ b/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 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; + } +} diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/store/TbLwM2mStoreConfiguration.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/store/TbLwM2mStoreConfiguration.java deleted file mode 100644 index 679e95bdbb..0000000000 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/store/TbLwM2mStoreConfiguration.java +++ /dev/null @@ -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 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 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; - } - } -} diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/store/TbLwM2mStoreFactory.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/store/TbLwM2mStoreFactory.java new file mode 100644 index 0000000000..1fcbd15e33 --- /dev/null +++ b/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 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()); + } + +}