Browse Source

lwm2m: back transport newKey start (#4278)

* lwm2m: back transport newKey start

* lwm2m: back transport newKey start1

* lwm2m: back transport newKey fix bug save

* lwm2m: back transport newKey test All security - ok

* lwm2m: back transport newKey fix bug updateAttrShared
pull/4291/head
nickAS21 6 years ago
committed by GitHub
parent
commit
4bc417456b
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 23
      common/data/src/main/java/org/thingsboard/server/common/data/lwm2m/LwM2mConstants.java
  2. 4
      common/transport/lwm2m/pom.xml
  3. 4
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mServerListener.java
  4. 104
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mTransportHandler.java
  5. 26
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mTransportRequest.java
  6. 139
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mTransportServiceImpl.java
  7. 14
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mVersionedModelProvider.java
  8. 251
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/store/LwM2mInMemorySecurityStore.java
  9. 11
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/store/TbLwM2mStoreConfiguration.java
  10. 1
      dao/src/main/java/org/thingsboard/server/dao/model/ModelConstants.java
  11. 3
      dao/src/main/java/org/thingsboard/server/dao/model/sql/TbResourceEntity.java
  12. 31
      dao/src/main/java/org/thingsboard/server/dao/resource/BaseTbResourceService.java
  13. 2
      dao/src/main/java/org/thingsboard/server/dao/resource/TbResourceDao.java
  14. 7
      dao/src/main/java/org/thingsboard/server/dao/sql/resource/JpaTbResourceDao.java

23
common/data/src/main/java/org/thingsboard/server/common/data/lwm2m/LwM2mConstants.java

@ -0,0 +1,23 @@
/**
* 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.common.data.lwm2m;
public interface LwM2mConstants {
String LWM2M_SEPARATOR_PATH = "/";
String LWM2M_SEPARATOR_KEY = "_";
String LWM2M_SEPARATOR_SEARCH_TEXT = ":";
}

4
common/transport/lwm2m/pom.xml

@ -40,6 +40,10 @@
<groupId>org.thingsboard.common.transport</groupId> <groupId>org.thingsboard.common.transport</groupId>
<artifactId>transport-api</artifactId> <artifactId>transport-api</artifactId>
</dependency> </dependency>
<dependency>
<groupId>org.thingsboard.common</groupId>
<artifactId>data</artifactId>
</dependency>
<dependency> <dependency>
<groupId>org.springframework</groupId> <groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId> <artifactId>spring-context-support</artifactId>

4
common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mServerListener.java

@ -26,6 +26,8 @@ import org.eclipse.leshan.server.registration.RegistrationUpdate;
import java.util.Collection; import java.util.Collection;
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.convertToIdVerFromObjectId;
@Slf4j @Slf4j
public class LwM2mServerListener { public class LwM2mServerListener {
@ -90,7 +92,7 @@ public class LwM2mServerListener {
public void onResponse(Observation observation, Registration registration, ObserveResponse response) { public void onResponse(Observation observation, Registration registration, ObserveResponse response) {
if (registration != null) { if (registration != null) {
try { try {
service.onObservationResponse(registration, observation.getPath().toString(), response); service.onObservationResponse(registration, convertToIdVerFromObjectId(observation.getPath().toString(), registration), response);
} catch (Exception e) { } catch (Exception e) {
log.error("[{}] onResponse", e.toString()); log.error("[{}] onResponse", e.toString());

104
common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mTransportHandler.java

@ -22,6 +22,7 @@ import com.google.gson.JsonSyntaxException;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.eclipse.californium.core.network.config.NetworkConfig; import org.eclipse.californium.core.network.config.NetworkConfig;
import org.eclipse.leshan.core.model.ObjectModel;
import org.eclipse.leshan.core.model.ResourceModel; import org.eclipse.leshan.core.model.ResourceModel;
import org.eclipse.leshan.core.node.LwM2mMultipleResource; import org.eclipse.leshan.core.node.LwM2mMultipleResource;
import org.eclipse.leshan.core.node.LwM2mNode; import org.eclipse.leshan.core.node.LwM2mNode;
@ -32,6 +33,7 @@ import org.eclipse.leshan.core.node.LwM2mSingleResource;
import org.eclipse.leshan.core.node.codec.CodecException; import org.eclipse.leshan.core.node.codec.CodecException;
import org.eclipse.leshan.core.util.Hex; import org.eclipse.leshan.core.util.Hex;
import org.eclipse.leshan.server.californium.LeshanServerBuilder; import org.eclipse.leshan.server.californium.LeshanServerBuilder;
import org.eclipse.leshan.server.registration.Registration;
import org.nustaq.serialization.FSTConfiguration; import org.nustaq.serialization.FSTConfiguration;
import org.thingsboard.server.common.data.DeviceProfile; import org.thingsboard.server.common.data.DeviceProfile;
import org.thingsboard.server.common.data.device.profile.Lwm2mDeviceProfileTransportConfiguration; import org.thingsboard.server.common.data.device.profile.Lwm2mDeviceProfileTransportConfiguration;
@ -47,14 +49,12 @@ import java.util.Date;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.Optional; import java.util.Optional;
import static org.thingsboard.server.common.data.lwm2m.LwM2mConstants.LWM2M_SEPARATOR_KEY;
import static org.thingsboard.server.common.data.lwm2m.LwM2mConstants.LWM2M_SEPARATOR_PATH;
@Slf4j @Slf4j
//@Component("LwM2MTransportHandler")
//@ConditionalOnExpression("('${service.type:null}'=='tb-transport' && '${transport.lwm2m.enabled:false}'=='true' )|| ('${service.type:null}'=='monolith' && '${transport.lwm2m.enabled}'=='true')")
public class LwM2mTransportHandler { public class LwM2mTransportHandler {
// We choose a default timeout a bit higher to the MAX_TRANSMIT_WAIT(62-93s) which is the time from starting to
// send a Confirmable message to the time when an acknowledgement is no longer expected.
public static final String BASE_DEVICE_API_TOPIC = "v1/devices/me"; public static final String BASE_DEVICE_API_TOPIC = "v1/devices/me";
public static final String ATTRIBUTE = "attribute"; public static final String ATTRIBUTE = "attribute";
public static final String TELEMETRY = "telemetry"; public static final String TELEMETRY = "telemetry";
@ -84,6 +84,8 @@ public class LwM2mTransportHandler {
public static final String LOG_LW2M_ERROR = "error"; public static final String LOG_LW2M_ERROR = "error";
public static final String LOG_LW2M_WARN = "warn"; public static final String LOG_LW2M_WARN = "warn";
public static final int LWM2M_STRATEGY_1 = 1;
public static final int LWM2M_STRATEGY_2 = 2;
public static final String CLIENT_NOT_AUTHORIZED = "Client not authorized"; public static final String CLIENT_NOT_AUTHORIZED = "Client not authorized";
@ -110,39 +112,6 @@ public class LwM2mTransportHandler {
public static final String SERVICE_CHANNEL = "SERVICE"; public static final String SERVICE_CHANNEL = "SERVICE";
public static final String RESPONSE_CHANNEL = "RESP"; public static final String RESPONSE_CHANNEL = "RESP";
// @Autowired
// @Qualifier("LeshanServerCert")
// private LeshanServer lhServerCert;
//
// @Autowired
// @Qualifier("LeshanServerNoSecPskRpk")
// private LeshanServer lhServerNoSecPskRpk;
// @Autowired
// @Qualifier("ServerListenerCert")
// private LwM2mServerListener serverListenerCert;
//
// @Autowired
// @Qualifier("ServerListenerNoSecPskRpk")
// private LwM2mServerListener serverListenerNoSecPskRpk;
// @PostConstruct
// public void init() {
// try {
// serverListenerCert.init(lhServerCert);
// this.lhServerCert.getRegistrationService().addListener(serverListenerCert.registrationListener);
// this.lhServerCert.getPresenceService().addListener(serverListenerCert.presenceListener);
// this.lhServerCert.getObservationService().addListener(serverListenerCert.observationListener);
// serverListenerNoSecPskRpk.init(lhServerNoSecPskRpk);
// this.lhServerNoSecPskRpk.getRegistrationService().addListener(serverListenerNoSecPskRpk.registrationListener);
// this.lhServerNoSecPskRpk.getPresenceService().addListener(serverListenerNoSecPskRpk.presenceListener);
// this.lhServerNoSecPskRpk.getObservationService().addListener(serverListenerNoSecPskRpk.observationListener);
// } catch (Exception e) {
// log.error("init [{}]", e.toString());
// }
// }
public static NetworkConfig getCoapConfig(Integer serverPortNoSec, Integer serverSecurePort) { public static NetworkConfig getCoapConfig(Integer serverPortNoSec, Integer serverSecurePort) {
NetworkConfig coapConfig; NetworkConfig coapConfig;
File configFile = new File(NetworkConfig.DEFAULT_FILE_NAME); File configFile = new File(NetworkConfig.DEFAULT_FILE_NAME);
@ -202,10 +171,10 @@ public class LwM2mTransportHandler {
/** /**
* @return deviceProfileBody with Observe&Attribute&Telemetry From Thingsboard * @return deviceProfileBody with Observe&Attribute&Telemetry From Thingsboard
* Example: * Example:
* property: {"clientLwM2mSettings": { * property: {"clientLwM2mSettings": {
* clientUpdateValueAfterConnect: false; * clientUpdateValueAfterConnect: false;
* } * }
* property: "observeAttr" * property: "observeAttr"
* {"keyName": { * {"keyName": {
* "/3/0/1": "modelNumber", * "/3/0/1": "modelNumber",
@ -222,7 +191,7 @@ public class LwM2mTransportHandler {
try { try {
ObjectMapper mapper = new ObjectMapper(); ObjectMapper mapper = new ObjectMapper();
String profileStr = mapper.writeValueAsString(profile); String profileStr = mapper.writeValueAsString(profile);
JsonObject profileJson = (profileStr != null) ? validateJson(profileStr) : null; JsonObject profileJson = (profileStr != null) ? validateJson(profileStr) : null;
return (getValidateCredentialsBodyFromThingsboard(profileJson)) ? LwM2mTransportHandler.getNewProfileParameters(profileJson, deviceProfile.getTenantId()) : null; return (getValidateCredentialsBodyFromThingsboard(profileJson)) ? LwM2mTransportHandler.getNewProfileParameters(profileJson, deviceProfile.getTenantId()) : null;
} catch (IOException e) { } catch (IOException e) {
log.error("", e); log.error("", e);
@ -246,9 +215,9 @@ public class LwM2mTransportHandler {
return null; return null;
} }
public static boolean getClientOnlyObserveAfterConnect (LwM2mClientProfile profile) { public static int getClientOnlyObserveAfterConnect(LwM2mClientProfile profile) {
return profile.getPostClientLwM2mSettings().getAsJsonObject().has("clientOnlyObserveAfterConnect") && return profile.getPostClientLwM2mSettings().getAsJsonObject().has("clientOnlyObserveAfterConnect") ?
profile.getPostClientLwM2mSettings().getAsJsonObject().get("clientOnlyObserveAfterConnect").getAsBoolean(); profile.getPostClientLwM2mSettings().getAsJsonObject().get("clientOnlyObserveAfterConnect").getAsInt() : 1;
} }
private static boolean getValidateCredentialsBodyFromThingsboard(JsonObject objectMsg) { private static boolean getValidateCredentialsBodyFromThingsboard(JsonObject objectMsg) {
@ -346,4 +315,49 @@ public class LwM2mTransportHandler {
} }
}; };
} }
public static String convertToObjectIdFromIdVer(String key) {
try {
String[] keyArray = key.split(LWM2M_SEPARATOR_PATH);
if (keyArray.length > 1 && keyArray[1].split(LWM2M_SEPARATOR_KEY).length == 2) {
keyArray[1] = keyArray[1].split(LWM2M_SEPARATOR_KEY)[0];
return StringUtils.join(keyArray, LWM2M_SEPARATOR_PATH);
} else {
return key;
}
} catch (Exception e) {
return null;
}
}
public static String convertToIdVerFromObjectId(String path, Registration registration) {
String ver = registration.getSupportedObject().get(new LwM2mPath(path).getObjectId());
try {
String[] keyArray = path.split(LWM2M_SEPARATOR_PATH);
if (keyArray.length > 1) {
keyArray[1] = keyArray[1] + LWM2M_SEPARATOR_KEY + ver;
return StringUtils.join(keyArray, LWM2M_SEPARATOR_PATH);
} else {
return path;
}
} catch (Exception e) {
return null;
}
}
public static Integer validateObjectIdFromKey(String key) {
try {
return Integer.parseInt(key.split(LWM2M_SEPARATOR_PATH)[1].split(LWM2M_SEPARATOR_KEY)[0]);
} catch (Exception e) {
return null;
}
}
public static String validateObjectVerFromKey(String key) {
try {
return (key.split(LWM2M_SEPARATOR_PATH)[1].split(LWM2M_SEPARATOR_KEY)[1]);
} catch (Exception e) {
return ObjectModel.DEFAULT_VERSION;
}
}
} }

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

@ -72,6 +72,8 @@ import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandle
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.PUT_TYPE_OPER_WRITE_ATTRIBUTES; import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.PUT_TYPE_OPER_WRITE_ATTRIBUTES;
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.PUT_TYPE_OPER_WRITE_UPDATE; import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.PUT_TYPE_OPER_WRITE_UPDATE;
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.RESPONSE_CHANNEL; import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.RESPONSE_CHANNEL;
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.convertToIdVerFromObjectId;
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.convertToObjectIdFromIdVer;
@Slf4j @Slf4j
@Service @Service
@ -114,7 +116,7 @@ public class LwM2mTransportRequest {
*/ */
public void sendAllRequest(Registration registration, String target, String typeOper, public void sendAllRequest(Registration registration, String target, String typeOper,
String contentFormatParam, Observation observation, Object params, long timeoutInMs) { String contentFormatParam, Observation observation, Object params, long timeoutInMs) {
LwM2mPath resultIds = new LwM2mPath(target); LwM2mPath resultIds = new LwM2mPath(convertToObjectIdFromIdVer(target));
if (registration != null && resultIds.getObjectId() >= 0) { if (registration != null && resultIds.getObjectId() >= 0) {
DownlinkRequest request = null; DownlinkRequest request = null;
ContentFormat contentFormat = contentFormatParam != null ? ContentFormat.fromName(contentFormatParam.toUpperCase()) : null; ContentFormat contentFormat = contentFormatParam != null ? ContentFormat.fromName(contentFormatParam.toUpperCase()) : null;
@ -229,9 +231,8 @@ public class LwM2mTransportRequest {
private void sendRequest(Registration registration, DownlinkRequest request, long timeoutInMs) { private void sendRequest(Registration registration, DownlinkRequest request, long timeoutInMs) {
LwM2mClient lwM2MClient = lwM2mClientContext.getLwM2mClientWithReg(registration, null); LwM2mClient lwM2MClient = lwM2mClientContext.getLwM2mClientWithReg(registration, null);
leshanServer.send(registration, request, timeoutInMs, (ResponseCallback<?>) response -> { leshanServer.send(registration, request, timeoutInMs, (ResponseCallback<?>) response -> {
if (!lwM2MClient.isInit()) { if (!lwM2MClient.isInit()) {
lwM2MClient.initValue(this.serviceImpl, request.getPath().toString()); lwM2MClient.initValue(this.serviceImpl, convertToIdVerFromObjectId(request.getPath().toString(), registration));
} }
if (isSuccess(((Response) response.getCoapResponse()).getCode())) { if (isSuccess(((Response) response.getCoapResponse()).getCode())) {
this.handleResponse(registration, request.getPath().toString(), response, request); this.handleResponse(registration, request.getPath().toString(), response, request);
@ -251,7 +252,7 @@ public class LwM2mTransportRequest {
} }
}, e -> { }, e -> {
if (!lwM2MClient.isInit()) { if (!lwM2MClient.isInit()) {
lwM2MClient.initValue(this.serviceImpl, request.getPath().toString()); lwM2MClient.initValue(this.serviceImpl, convertToIdVerFromObjectId(request.getPath().toString(), registration));
} }
String msg = String.format("%s: sendRequest: Resource path - %s msg error - %s SendRequest to Client", String msg = String.format("%s: sendRequest: Resource path - %s msg error - %s SendRequest to Client",
LOG_LW2M_ERROR, request.getPath().toString(), e.toString()); LOG_LW2M_ERROR, request.getPath().toString(), e.toString());
@ -310,21 +311,22 @@ public class LwM2mTransportRequest {
* @param response - * @param response -
*/ */
private void sendResponse(Registration registration, String path, LwM2mResponse response, DownlinkRequest request) { private void sendResponse(Registration registration, String path, LwM2mResponse response, DownlinkRequest request) {
String pathIdVer = convertToIdVerFromObjectId(path, registration);
if (response instanceof ReadResponse) { if (response instanceof ReadResponse) {
serviceImpl.onObservationResponse(registration, path, (ReadResponse) response); serviceImpl.onObservationResponse(registration, pathIdVer, (ReadResponse) response);
} else if (response instanceof CancelObservationResponse) { } else if (response instanceof CancelObservationResponse) {
log.info("[{}] Path [{}] CancelObservationResponse 3_Send", path, response); log.info("[{}] Path [{}] CancelObservationResponse 3_Send", pathIdVer, response);
} else if (response instanceof DeleteResponse) { } else if (response instanceof DeleteResponse) {
log.info("[{}] Path [{}] DeleteResponse 5_Send", path, response); log.info("[{}] Path [{}] DeleteResponse 5_Send", pathIdVer, response);
} else if (response instanceof DiscoverResponse) { } else if (response instanceof DiscoverResponse) {
log.info("[{}] Path [{}] DiscoverResponse 6_Send", path, response); log.info("[{}] Path [{}] DiscoverResponse 6_Send", pathIdVer, response);
} else if (response instanceof ExecuteResponse) { } else if (response instanceof ExecuteResponse) {
log.info("[{}] Path [{}] ExecuteResponse 7_Send", path, response); log.info("[{}] Path [{}] ExecuteResponse 7_Send", pathIdVer, response);
} else if (response instanceof WriteAttributesResponse) { } else if (response instanceof WriteAttributesResponse) {
log.info("[{}] Path [{}] WriteAttributesResponse 8_Send", path, response); log.info("[{}] Path [{}] WriteAttributesResponse 8_Send", pathIdVer, response);
} else if (response instanceof WriteResponse) { } else if (response instanceof WriteResponse) {
log.info("[{}] Path [{}] WriteAttributesResponse 9_Send", path, response); log.info("[{}] Path [{}] WriteAttributesResponse 9_Send", pathIdVer, response);
serviceImpl.onWriteResponseOk(registration, path, (WriteRequest) request); serviceImpl.onWriteResponseOk(registration, pathIdVer, (WriteRequest) request);
} }
} }
} }

139
common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mTransportServiceImpl.java

@ -88,10 +88,15 @@ import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandle
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.LOG_LW2M_ERROR; import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.LOG_LW2M_ERROR;
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.LOG_LW2M_INFO; import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.LOG_LW2M_INFO;
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.LOG_LW2M_TELEMETRY; import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.LOG_LW2M_TELEMETRY;
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.LWM2M_STRATEGY_2;
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.POST_TYPE_OPER_EXECUTE; import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.POST_TYPE_OPER_EXECUTE;
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.POST_TYPE_OPER_WRITE_REPLACE; import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.POST_TYPE_OPER_WRITE_REPLACE;
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.SERVICE_CHANNEL; import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.SERVICE_CHANNEL;
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.convertToIdVerFromObjectId;
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.convertToObjectIdFromIdVer;
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.getAckCallback; import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.getAckCallback;
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.validateObjectIdFromKey;
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.validateObjectVerFromKey;
@Slf4j @Slf4j
@Service @Service
@ -290,19 +295,19 @@ public class LwM2mTransportServiceImpl implements LwM2mTransportService {
if (msg.getSharedUpdatedCount() > 0) { if (msg.getSharedUpdatedCount() > 0) {
JsonElement el = JsonConverter.toJson(msg); JsonElement el = JsonConverter.toJson(msg);
el.getAsJsonObject().entrySet().forEach(de -> { el.getAsJsonObject().entrySet().forEach(de -> {
String path = this.getPathAttributeUpdate(sessionInfo, de.getKey()); String pathIdVer = this.getPathAttributeUpdate(sessionInfo, de.getKey());
String value = de.getValue().getAsString(); String value = de.getValue().getAsString();
LwM2mClient lwM2MClient = lwM2mClientContext.getLwM2mClient(new UUID(sessionInfo.getSessionIdMSB(), sessionInfo.getSessionIdLSB())); LwM2mClient lwM2MClient = lwM2mClientContext.getLwM2mClient(new UUID(sessionInfo.getSessionIdMSB(), sessionInfo.getSessionIdLSB()));
LwM2mClientProfile clientProfile = lwM2mClientContext.getProfile(new UUID(sessionInfo.getDeviceProfileIdMSB(), sessionInfo.getDeviceProfileIdLSB())); LwM2mClientProfile clientProfile = lwM2mClientContext.getProfile(new UUID(sessionInfo.getDeviceProfileIdMSB(), sessionInfo.getDeviceProfileIdLSB()));
if (path != null && !path.isEmpty() && (this.validatePathInAttrProfile(clientProfile, path) || this.validatePathInTelemetryProfile(clientProfile, path))) { if (pathIdVer != null && !pathIdVer.isEmpty() && (this.validatePathInAttrProfile(clientProfile, pathIdVer) || this.validatePathInTelemetryProfile(clientProfile, pathIdVer))) {
ResourceModel resourceModel = lwM2mTransportContextServer.getLwM2MTransportConfigServer().getResourceModel(lwM2MClient.getRegistration(), new LwM2mPath(path)); ResourceModel resourceModel = lwM2mTransportContextServer.getLwM2MTransportConfigServer().getResourceModel(lwM2MClient.getRegistration(), new LwM2mPath(convertToObjectIdFromIdVer(pathIdVer)));
if (resourceModel != null && resourceModel.operations.isWritable()) { if (resourceModel != null && resourceModel.operations.isWritable()) {
lwM2mTransportRequest.sendAllRequest(lwM2MClient.getRegistration(), path, POST_TYPE_OPER_WRITE_REPLACE, lwM2mTransportRequest.sendAllRequest(lwM2MClient.getRegistration(), pathIdVer, POST_TYPE_OPER_WRITE_REPLACE,
ContentFormat.TLV.getName(), null, value, this.lwM2mTransportContextServer.getLwM2MTransportConfigServer().getTimeout()); ContentFormat.TLV.getName(), null, value, this.lwM2mTransportContextServer.getLwM2MTransportConfigServer().getTimeout());
} else { } else {
log.error("Resource path - [{}] value - [{}] is not Writable and cannot be updated", path, value); log.error("Resource path - [{}] value - [{}] is not Writable and cannot be updated", pathIdVer, value);
String logMsg = String.format("%s: attributeUpdate: Resource path - %s value - %s is not Writable and cannot be updated", String logMsg = String.format("%s: attributeUpdate: Resource path - %s value - %s is not Writable and cannot be updated",
LOG_LW2M_ERROR, path, value); LOG_LW2M_ERROR, pathIdVer, value);
this.sentLogsToThingsboard(logMsg, lwM2MClient.getRegistration()); this.sentLogsToThingsboard(logMsg, lwM2MClient.getRegistration());
} }
} else { } else {
@ -348,7 +353,7 @@ public class LwM2mTransportServiceImpl implements LwM2mTransportService {
/** /**
* Trigger Server path = "/1/0/8" * Trigger Server path = "/1/0/8"
* * <p>
* Trigger bootStrap path = "/1/0/9" - have to implemented on client * Trigger bootStrap path = "/1/0/9" - have to implemented on client
*/ */
@Override @Override
@ -458,7 +463,7 @@ public class LwM2mTransportServiceImpl implements LwM2mTransportService {
private void initLwM2mFromClientValue(Registration registration, LwM2mClient lwM2MClient) { private void initLwM2mFromClientValue(Registration registration, LwM2mClient lwM2MClient) {
LwM2mClientProfile lwM2MClientProfile = lwM2mClientContext.getProfile(registration); LwM2mClientProfile lwM2MClientProfile = lwM2mClientContext.getProfile(registration);
Set<String> clientObjects = this.getAllOjectsInClient(registration); Set<String> clientObjects = this.getAllOjectsInClient(registration);
if (clientObjects != null && !LwM2mTransportHandler.getClientOnlyObserveAfterConnect(lwM2MClientProfile)) { if (clientObjects != null && LWM2M_STRATEGY_2 == LwM2mTransportHandler.getClientOnlyObserveAfterConnect(lwM2MClientProfile)) {
// #2 // #2
lwM2MClient.getPendingRequests().addAll(clientObjects); lwM2MClient.getPendingRequests().addAll(clientObjects);
clientObjects.forEach(path -> lwM2mTransportRequest.sendAllRequest(registration, path, GET_TYPE_OPER_READ, ContentFormat.TLV.getName(), clientObjects.forEach(path -> lwM2mTransportRequest.sendAllRequest(registration, path, GET_TYPE_OPER_READ, ContentFormat.TLV.getName(),
@ -499,9 +504,9 @@ public class LwM2mTransportServiceImpl implements LwM2mTransportService {
* #1 Return old Value Resource from LwM2MClient * #1 Return old Value Resource from LwM2MClient
* #2 Update new Resources (replace old Resource Value on new Resource Value) * #2 Update new Resources (replace old Resource Value on new Resource Value)
* *
* @param registration - Registration LwM2M Client * @param registration - Registration LwM2M Client
* @param lwM2mResource - LwM2mSingleResource response.getContent() * @param lwM2mResource - LwM2mSingleResource response.getContent()
* @param path - resource * @param path - resource
*/ */
private void updateResourcesValue(Registration registration, LwM2mResource lwM2mResource, String path) { private void updateResourcesValue(Registration registration, LwM2mResource lwM2mResource, String path) {
LwM2mClient lwM2MClient = lwM2mClientContext.getLwM2mClientWithReg(registration, null); LwM2mClient lwM2MClient = lwM2mClientContext.getLwM2mClientWithReg(registration, null);
@ -539,7 +544,7 @@ public class LwM2mTransportServiceImpl implements LwM2mTransportService {
/** /**
* @param clientProfile - * @param clientProfile -
* @param path - * @param path -
* @return true if path isPresent in postAttributeProfile * @return true if path isPresent in postAttributeProfile
*/ */
private boolean validatePathInAttrProfile(LwM2mClientProfile clientProfile, String path) { private boolean validatePathInAttrProfile(LwM2mClientProfile clientProfile, String path) {
@ -555,7 +560,7 @@ public class LwM2mTransportServiceImpl implements LwM2mTransportService {
/** /**
* @param clientProfile - * @param clientProfile -
* @param path - * @param path -
* @return true if path isPresent in postAttributeProfile * @return true if path isPresent in postAttributeProfile
*/ */
private boolean validatePathInTelemetryProfile(LwM2mClientProfile clientProfile, String path) { private boolean validatePathInTelemetryProfile(LwM2mClientProfile clientProfile, String path) {
@ -581,10 +586,13 @@ public class LwM2mTransportServiceImpl implements LwM2mTransportService {
Set<String> clientInstances = this.getAllInstancesInClient(registration); Set<String> clientInstances = this.getAllInstancesInClient(registration);
Set<String> result; Set<String> result;
if (GET_TYPE_OPER_READ.equals(typeOper)) { if (GET_TYPE_OPER_READ.equals(typeOper)) {
result = JacksonUtil.fromString(lwM2MClientProfile.getPostAttributeProfile().toString(), new TypeReference<>() {}); result = JacksonUtil.fromString(lwM2MClientProfile.getPostAttributeProfile().toString(), new TypeReference<>() {
result.addAll(JacksonUtil.fromString(lwM2MClientProfile.getPostTelemetryProfile().toString(), new TypeReference<>() {})); });
result.addAll(JacksonUtil.fromString(lwM2MClientProfile.getPostTelemetryProfile().toString(), new TypeReference<>() {
}));
} else { } else {
result = JacksonUtil.fromString(lwM2MClientProfile.getPostObserveProfile().toString(), new TypeReference<>() {}); result = JacksonUtil.fromString(lwM2MClientProfile.getPostObserveProfile().toString(), new TypeReference<>() {
});
} }
Set<String> pathSent = ConcurrentHashMap.newKeySet(); Set<String> pathSent = ConcurrentHashMap.newKeySet();
result.forEach(target -> { result.forEach(target -> {
@ -646,7 +654,7 @@ public class LwM2mTransportServiceImpl implements LwM2mTransportService {
Arrays.stream(registration.getObjectLinks()).forEach(url -> { Arrays.stream(registration.getObjectLinks()).forEach(url -> {
LwM2mPath pathIds = new LwM2mPath(url.getUrl()); LwM2mPath pathIds = new LwM2mPath(url.getUrl());
if (pathIds.isObjectInstance()) { if (pathIds.isObjectInstance()) {
clientInstances.add(url.getUrl()); clientInstances.add(convertToIdVerFromObjectId(url.getUrl(), registration));
} }
}); });
return (clientInstances.size() > 0) ? clientInstances : null; return (clientInstances.size() > 0) ? clientInstances : null;
@ -656,26 +664,22 @@ public class LwM2mTransportServiceImpl implements LwM2mTransportService {
* @param attributes - new JsonObject * @param attributes - new JsonObject
* @param telemetry - new JsonObject * @param telemetry - new JsonObject
* @param registration - Registration LwM2M Client * @param registration - Registration LwM2M Client
* @param path - * @param path -
*/ */
private void getParametersFromProfile(JsonObject attributes, JsonObject telemetry, Registration registration, Set<String> path) { private void getParametersFromProfile(JsonObject attributes, JsonObject telemetry, Registration registration, Set<String> path) {
LwM2mClientProfile lwM2MClientProfile = lwM2mClientContext.getProfile(registration); if (path != null && path.size() > 0) {
lwM2MClientProfile.getPostAttributeProfile().forEach(p -> { LwM2mClientProfile lwM2MClientProfile = lwM2mClientContext.getProfile(registration);
LwM2mPath pathIds = new LwM2mPath(p.getAsString()); lwM2MClientProfile.getPostAttributeProfile().forEach(idVer -> {
if (pathIds.isResource()) { if (path.contains(idVer.getAsString())) {
if (path == null || path.contains(p.getAsString())) { this.addParameters(idVer.getAsString(), attributes, registration);
this.addParameters(p.getAsString(), attributes, registration);
} }
} });
}); lwM2MClientProfile.getPostTelemetryProfile().forEach(idVer -> {
lwM2MClientProfile.getPostTelemetryProfile().forEach(p -> { if (path.contains(idVer.getAsString())) {
LwM2mPath pathIds = new LwM2mPath(p.getAsString()); this.addParameters(idVer.getAsString(), telemetry, registration);
if (pathIds.isResource()) {
if (path == null || path.contains(p.getAsString())) {
this.addParameters(p.getAsString(), telemetry, registration);
} }
} });
}); }
} }
/** /**
@ -703,22 +707,21 @@ public class LwM2mTransportServiceImpl implements LwM2mTransportService {
* @return - value of Resource or null * @return - value of Resource or null
*/ */
private String getResourceValueToString(LwM2mClient lwM2MClient, String path) { private String getResourceValueToString(LwM2mClient lwM2MClient, String path) {
LwM2mPath pathIds = new LwM2mPath(path); LwM2mPath pathIds =new LwM2mPath(convertToObjectIdFromIdVer(path));
ResourceValue resourceValue = this.returnResourceValueFromLwM2MClient(lwM2MClient, pathIds); ResourceValue resourceValue = this.returnResourceValueFromLwM2MClient(lwM2MClient, path);
return resourceValue == null ? null : return resourceValue == null ? null :
this.converter.convertValue(resourceValue.getResourceValue(), this.lwM2mTransportContextServer.getLwM2MTransportConfigServer().getResourceModelType(lwM2MClient.getRegistration(), pathIds), ResourceModel.Type.STRING, pathIds).toString(); this.converter.convertValue(resourceValue.getResourceValue(), this.lwM2mTransportContextServer.getLwM2MTransportConfigServer().getResourceModelType(lwM2MClient.getRegistration(), pathIds), ResourceModel.Type.STRING, pathIds).toString();
} }
/** /**
*
* @param lwM2MClient - * @param lwM2MClient -
* @param pathIds - * @param path -
* @return - return value of Resource by idPath * @return - return value of Resource by idPath
*/ */
private ResourceValue returnResourceValueFromLwM2MClient(LwM2mClient lwM2MClient, LwM2mPath pathIds) { private ResourceValue returnResourceValueFromLwM2MClient(LwM2mClient lwM2MClient, String path) {
ResourceValue resourceValue = null; ResourceValue resourceValue = null;
if (pathIds.isResource()) { if (new LwM2mPath(convertToObjectIdFromIdVer(path)).isResource()) {
resourceValue = lwM2MClient.getResources().get(pathIds.toString()); resourceValue = lwM2MClient.getResources().get(path);
} }
return resourceValue; return resourceValue;
} }
@ -818,8 +821,10 @@ public class LwM2mTransportServiceImpl implements LwM2mTransportService {
// #5.1 // #5.1
if (!observeOld.equals(observeNew)) { if (!observeOld.equals(observeNew)) {
Set<String> observeSetOld = new Gson().fromJson(observeOld, new TypeToken<>() {}.getType()); Set<String> observeSetOld = new Gson().fromJson(observeOld, new TypeToken<>() {
Set<String> observeSetNew = new Gson().fromJson(observeNew, new TypeToken<>() {}.getType()); }.getType());
Set<String> observeSetNew = new Gson().fromJson(observeNew, new TypeToken<>() {
}.getType());
//#5.2 add //#5.2 add
// path Attr/Telemetry includes newObserve // path Attr/Telemetry includes newObserve
attributeSetOld.addAll(telemetrySetOld); attributeSetOld.addAll(telemetrySetOld);
@ -840,7 +845,7 @@ public class LwM2mTransportServiceImpl implements LwM2mTransportService {
} }
} }
private Set <String> convertJsonArrayToSet (JsonArray jsonArray) { private Set<String> convertJsonArrayToSet(JsonArray jsonArray) {
List<String> attributeListOld = new Gson().fromJson(jsonArray, new TypeToken<>() { List<String> attributeListOld = new Gson().fromJson(jsonArray, new TypeToken<>() {
}.getType()); }.getType());
return Sets.newConcurrentHashSet(attributeListOld); return Sets.newConcurrentHashSet(attributeListOld);
@ -907,7 +912,7 @@ public class LwM2mTransportServiceImpl implements LwM2mTransportService {
private void cancelObserveIsValue(Registration registration, Set<String> paramAnallyzer) { private void cancelObserveIsValue(Registration registration, Set<String> paramAnallyzer) {
LwM2mClient lwM2MClient = lwM2mClientContext.getLwM2mClientWithReg(registration, null); LwM2mClient lwM2MClient = lwM2mClientContext.getLwM2mClientWithReg(registration, null);
paramAnallyzer.forEach(p -> { paramAnallyzer.forEach(p -> {
if (this.returnResourceValueFromLwM2MClient(lwM2MClient, new LwM2mPath(p)) != null) { if (this.returnResourceValueFromLwM2MClient(lwM2MClient, p) != null) {
this.setCancelObservationRecourse(registration, p); this.setCancelObservationRecourse(registration, p);
} }
} }
@ -953,8 +958,9 @@ public class LwM2mTransportServiceImpl implements LwM2mTransportService {
*/ */
private String getPathAttributeUpdateProfile(TransportProtos.SessionInfoProto sessionInfo, String name) { private String getPathAttributeUpdateProfile(TransportProtos.SessionInfoProto sessionInfo, String name) {
LwM2mClientProfile profile = lwM2mClientContext.getProfile(new UUID(sessionInfo.getDeviceProfileIdMSB(), sessionInfo.getDeviceProfileIdLSB())); LwM2mClientProfile profile = lwM2mClientContext.getProfile(new UUID(sessionInfo.getDeviceProfileIdMSB(), sessionInfo.getDeviceProfileIdLSB()));
Registration registration = lwM2mClientContext.getLwM2MClient(sessionInfo).getRegistration();
return profile.getPostKeyNameProfile().getAsJsonObject().entrySet().stream() return profile.getPostKeyNameProfile().getAsJsonObject().entrySet().stream()
.filter(e -> e.getValue().getAsString().equals(name)).findFirst().map(Map.Entry::getKey) .filter(e -> e.getValue().getAsString().equals(name) && validateResourceInModelByVer(registration, e.getKey())).findFirst().map(Map.Entry::getKey)
.orElse(""); .orElse("");
} }
@ -974,12 +980,14 @@ public class LwM2mTransportServiceImpl implements LwM2mTransportService {
try { try {
LwM2mClient lwM2MClient = lwM2mClientContext.getLwM2MClient(sessionInfo); LwM2mClient lwM2MClient = lwM2mClientContext.getLwM2MClient(sessionInfo);
attributesResponse.getSharedAttributeListList().forEach(attr -> { attributesResponse.getSharedAttributeListList().forEach(attr -> {
String path = this.getPathAttributeUpdate(sessionInfo, attr.getKv().getKey()); String path =this.getPathAttributeUpdate(sessionInfo, attr.getKv().getKey());
// #1.1 if (path != null) {
if (lwM2MClient.getDelayedRequests().containsKey(path) && attr.getTs() > lwM2MClient.getDelayedRequests().get(path).getTs()) { // #1.1
lwM2MClient.getDelayedRequests().put(path, attr); if (lwM2MClient.getDelayedRequests().containsKey(path) && attr.getTs() > lwM2MClient.getDelayedRequests().get(path).getTs()) {
} else { lwM2MClient.getDelayedRequests().put(path, attr);
lwM2MClient.getDelayedRequests().put(path, attr); } else {
lwM2MClient.getDelayedRequests().put(path, attr);
}
} }
}); });
// #2.1 // #2.1
@ -1057,6 +1065,7 @@ public class LwM2mTransportServiceImpl implements LwM2mTransportService {
} }
/** /**
* !!! sharedAttr === profileAttr !!!
* If there is a difference in values between the current resource values and the shared attribute values * If there is a difference in values between the current resource values and the shared attribute values
* when the client connects to the server * when the client connects to the server
* #1 get attributes name from profile include name resources in ModelObject if resource isWritable * #1 get attributes name from profile include name resources in ModelObject if resource isWritable
@ -1083,24 +1092,42 @@ public class LwM2mTransportServiceImpl implements LwM2mTransportService {
/** /**
* Get names and keyNames from profile shared!!!! attr resources IsWritable * !!! sharedAttr === profileAttr !!!
* Get names or keyNames from profile: resources IsWritable
* *
* @param lwM2MClient - * @param lwM2MClient -
* @return ArrayList keyNames from profile attr resources shared!!!! && IsWritable * @return ArrayList keyNames from profile profileAttr && IsWritable
*/ */
private List<String> getNamesAttrFromProfileIsWritable(LwM2mClient lwM2MClient) { private List<String> getNamesAttrFromProfileIsWritable(LwM2mClient lwM2MClient) {
LwM2mClientProfile profile = lwM2mClientContext.getProfile(lwM2MClient.getProfileId()); LwM2mClientProfile profile = lwM2mClientContext.getProfile(lwM2MClient.getProfileId());
Set<String> attrSet = new Gson().fromJson(profile.getPostAttributeProfile(), new TypeToken<>() {}.getType()); Set<String> attrSet = new Gson().fromJson(profile.getPostAttributeProfile(),
ConcurrentMap<String, String> keyNamesMap = new Gson().fromJson(profile.getPostKeyNameProfile().toString(), new TypeToken<ConcurrentHashMap<String, String>>() {}.getType()); new TypeToken<HashSet<String>>() {
}.getType());
ConcurrentMap<String, String> keyNamesMap = new Gson().fromJson(profile.getPostKeyNameProfile().toString(),
new TypeToken<ConcurrentHashMap<String, String>>() {
}.getType());
ConcurrentMap<String, String> keyNamesIsWritable = keyNamesMap.entrySet() ConcurrentMap<String, String> keyNamesIsWritable = keyNamesMap.entrySet()
.stream() .stream()
.filter(e -> (attrSet.contains(e.getKey()) && lwM2mTransportContextServer.getLwM2MTransportConfigServer().getResourceModel(lwM2MClient.getRegistration(), new LwM2mPath(e.getKey())) != null && .filter(e -> (attrSet.contains(e.getKey()) && resourceIsWritable(lwM2MClient.getRegistration(), e.getKey())))
lwM2mTransportContextServer.getLwM2MTransportConfigServer().getResourceModel(lwM2MClient.getRegistration(), new LwM2mPath(e.getKey())).operations.isWritable()))
.collect(Collectors.toConcurrentMap(Map.Entry::getKey, Map.Entry::getValue)); .collect(Collectors.toConcurrentMap(Map.Entry::getKey, Map.Entry::getValue));
Set<String> namesIsWritable = ConcurrentHashMap.newKeySet(); Set<String> namesIsWritable = ConcurrentHashMap.newKeySet();
namesIsWritable.addAll(new HashSet<>(keyNamesIsWritable.values())); namesIsWritable.addAll(new HashSet<>(keyNamesIsWritable.values()));
return new ArrayList<>(namesIsWritable); return new ArrayList<>(namesIsWritable);
} }
private boolean resourceIsWritable(Registration registration, String pathKey) {
return validateResourceInModelByVer(registration, pathKey) &&
lwM2mTransportContextServer.getLwM2MTransportConfigServer().getResourceModel(registration,
new LwM2mPath(convertToObjectIdFromIdVer(pathKey))).operations.isWritable();
}
private boolean validateResourceInModelByVer(Registration registration, String pathKey) {
Integer objectId = validateObjectIdFromKey(pathKey);
String objectVer = validateObjectVerFromKey(pathKey);
LwM2mPath lwM2mPath = new LwM2mPath(convertToObjectIdFromIdVer(pathKey));
return objectId != null && objectVer != null && objectVer.equals(registration.getSupportedVersion(objectId)) &&
lwM2mTransportContextServer.getLwM2MTransportConfigServer().getResourceModel(registration, lwM2mPath) != null;
}
} }

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

@ -32,6 +32,7 @@ import java.util.Iterator;
import java.util.Map; import java.util.Map;
import static org.thingsboard.server.common.data.ResourceType.LWM2M_MODEL; import static org.thingsboard.server.common.data.ResourceType.LWM2M_MODEL;
import static org.thingsboard.server.common.data.lwm2m.LwM2mConstants.LWM2M_SEPARATOR_KEY;
@Slf4j @Slf4j
public class LwM2mVersionedModelProvider implements LwM2mModelProvider { public class LwM2mVersionedModelProvider implements LwM2mModelProvider {
@ -49,12 +50,9 @@ public class LwM2mVersionedModelProvider implements LwM2mModelProvider {
this.lwM2mClientContext = lwM2mClientContext; this.lwM2mClientContext = lwM2mClientContext;
this.lwM2mTransportContextServer = lwM2mTransportContextServer; this.lwM2mTransportContextServer = lwM2mTransportContextServer;
} }
private String getIdVer(ObjectModel objectModel) {
return objectModel.id + "##" + ((objectModel.getVersion() == null || objectModel.getVersion().isEmpty()) ? ObjectModel.DEFAULT_VERSION : objectModel.getVersion());
}
private String getIdVer(Integer objectId, String version) { private String getKeyIdVer(Integer objectId, String version) {
return objectId != null ? objectId + "##" + ((version == null || version.isEmpty()) ? ObjectModel.DEFAULT_VERSION : version) : null; return objectId != null ? objectId + LWM2M_SEPARATOR_KEY + ((version == null || version.isEmpty()) ? ObjectModel.DEFAULT_VERSION : version) : null;
} }
/** /**
@ -65,8 +63,7 @@ public class LwM2mVersionedModelProvider implements LwM2mModelProvider {
*/ */
@Override @Override
public LwM2mModel getObjectModel(Registration registration) { public LwM2mModel getObjectModel(Registration registration) {
return new DynamicModel(registration return new DynamicModel(registration);
);
} }
private class DynamicModel implements LwM2mModel { private class DynamicModel implements LwM2mModel {
@ -107,7 +104,6 @@ public class LwM2mVersionedModelProvider implements LwM2mModelProvider {
Map<Integer, String> supportedObjects = this.registration.getSupportedObject(); Map<Integer, String> supportedObjects = this.registration.getSupportedObject();
Collection<ObjectModel> result = new ArrayList<>(supportedObjects.size()); Collection<ObjectModel> result = new ArrayList<>(supportedObjects.size());
Iterator<Map.Entry<Integer, String>> i$ = supportedObjects.entrySet().iterator(); Iterator<Map.Entry<Integer, String>> i$ = supportedObjects.entrySet().iterator();
while (i$.hasNext()) { while (i$.hasNext()) {
Map.Entry<Integer, String> supportedObject = i$.next(); Map.Entry<Integer, String> supportedObject = i$.next();
ObjectModel objectModel = this.getObjectModelDynamic(supportedObject.getKey(), supportedObject.getValue()); ObjectModel objectModel = this.getObjectModelDynamic(supportedObject.getKey(), supportedObject.getValue());
@ -119,7 +115,7 @@ public class LwM2mVersionedModelProvider implements LwM2mModelProvider {
} }
private ObjectModel getObjectModelDynamic(Integer objectId, String version) { private ObjectModel getObjectModelDynamic(Integer objectId, String version) {
String key = getIdVer(objectId, version); String key = getKeyIdVer(objectId, version);
String xmlB64 = lwM2mTransportContextServer.getTransportResourceCache().get( String xmlB64 = lwM2mTransportContextServer.getTransportResourceCache().get(
this.tenantId, this.tenantId,
LWM2M_MODEL, LWM2M_MODEL,

251
common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/store/LwM2mInMemorySecurityStore.java

@ -1,251 +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 lombok.extern.slf4j.Slf4j;
import org.eclipse.leshan.core.util.Hex;
import org.eclipse.leshan.server.registration.Registration;
import org.eclipse.leshan.server.security.InMemorySecurityStore;
import org.eclipse.leshan.server.security.SecurityInfo;
import org.eclipse.leshan.server.security.SecurityStoreListener;
import org.springframework.beans.factory.annotation.Autowired;
import org.thingsboard.server.common.data.DeviceProfile;
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.server.LwM2mTransportHandler;
import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient;
import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClientProfile;
import org.thingsboard.server.transport.lwm2m.utils.TypeServer;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import java.util.stream.Collectors;
import static org.thingsboard.server.transport.lwm2m.secure.LwM2MSecurityMode.NO_SEC;
@Slf4j
//@Service("LwM2mInMemorySecurityStore")
//@TbLwM2mTransportComponent
@Deprecated
public class LwM2mInMemorySecurityStore extends InMemorySecurityStore {
private static final boolean INFOS_ARE_COMPROMISED = false;
// lock for the two maps
private final ReadWriteLock readWriteLock = new ReentrantReadWriteLock();
private final Lock readLock = readWriteLock.readLock();
private final Lock writeLock = readWriteLock.writeLock();
private final Map<String /** registrationId */, LwM2mClient> sessions = new ConcurrentHashMap<>();
private Map<UUID /** profileUUid */, LwM2mClientProfile> profiles = new ConcurrentHashMap<>();
private SecurityStoreListener listener;
@Autowired
LwM2mCredentialsSecurityInfoValidator lwM2MCredentialsSecurityInfoValidator;
/**
* Start after DefaultAuthorizer or LwM2mPskStore
* @param endPoint -
* @return SecurityInfo
*/
@Override
public SecurityInfo getByEndpoint(String endPoint) {
readLock.lock();
try {
String registrationId = this.getRegistrationId(endPoint, null);
return (registrationId != null && sessions.size() > 0 && sessions.get(registrationId) != null) ?
sessions.get(registrationId).getSecurityInfo() : this.addLwM2MClientToSession(endPoint);
} finally {
readLock.unlock();
}
}
/**
* Start after LwM2mPskStore
* @param identity -
* @return SecurityInfo
*/
@Override
public SecurityInfo getByIdentity(String identity) {
readLock.lock();
try {
String integrationId = this.getRegistrationId(null, identity);
return (integrationId != null) ? sessions.get(integrationId).getSecurityInfo() : this.addLwM2MClientToSession(identity);
} finally {
readLock.unlock();
}
}
@Override
public Collection<SecurityInfo> getAll() {
readLock.lock();
try {
return this.sessions.values().stream().map(LwM2mClient::getSecurityInfo).collect(Collectors.toUnmodifiableList());
} finally {
readLock.unlock();
}
}
/**
* Removed registration Client from sessions and listener
* @param registrationId if Client
*/
public void delRemoveSessionAndListener(String registrationId) {
writeLock.lock();
try {
LwM2mClient lwM2MClient = (sessions.get(registrationId) != null) ? sessions.get(registrationId) : null;
if (lwM2MClient != null) {
if (listener != null) {
listener.securityInfoRemoved(INFOS_ARE_COMPROMISED, lwM2MClient.getSecurityInfo());
}
sessions.remove(registrationId);
}
} finally {
writeLock.unlock();
}
}
@Override
public void setListener(SecurityStoreListener listener) {
this.listener = listener;
}
public LwM2mClient getLwM2MClient(String endPoint, String identity) {
Map.Entry<String, LwM2mClient> modelClients = endPoint != null ?
this.sessions.entrySet().stream().filter(model -> endPoint.equals(model.getValue().getEndpoint())).findAny().orElse(null) :
this.sessions.entrySet().stream().filter(model -> identity.equals(model.getValue().getIdentity())).findAny().orElse(null);
return modelClients != null ? modelClients.getValue() : null;
}
public LwM2mClient getLwM2MClientWithReg(Registration registration, String registrationId) {
return registrationId != null ?
this.sessions.get(registrationId) :
this.sessions.containsKey(registration.getId()) ?
this.sessions.get(registration.getId()) :
this.sessions.get(registration.getEndpoint());
}
public LwM2mClient getLwM2MClient(TransportProtos.SessionInfoProto sessionInfo) {
return this.getSession(new UUID(sessionInfo.getSessionIdMSB(), sessionInfo.getSessionIdLSB())).entrySet().iterator().next().getValue();
}
/**
* Update in sessions (LwM2MClient for key registration_Id) after starting registration LwM2MClient in LwM2MTransportServiceImpl
* Remove from sessions LwM2MClient with key registration_Endpoint
* @param registration -
* @return LwM2MClient after adding it to session
*/
public LwM2mClient updateInSessionsLwM2MClient(Registration registration) {
writeLock.lock();
try {
if (this.sessions.get(registration.getEndpoint()) == null) {
this.addLwM2MClientToSession(registration.getEndpoint());
}
LwM2mClient lwM2MClient = this.sessions.get(registration.getEndpoint());
lwM2MClient.setRegistration(registration);
// lwM2MClient.getAttributes().putAll(registration.getAdditionalRegistrationAttributes());
this.sessions.remove(registration.getEndpoint());
this.sessions.put(registration.getId(), lwM2MClient);
return lwM2MClient;
} finally {
writeLock.unlock();
}
}
private String getRegistrationId(String endPoint, String identity) {
List<String> registrationIds = (endPoint != null) ?
this.sessions.entrySet().stream().filter(model -> endPoint.equals(model.getValue().getEndpoint())).map(Map.Entry::getKey).collect(Collectors.toList()) :
this.sessions.entrySet().stream().filter(model -> identity.equals(model.getValue().getIdentity())).map(Map.Entry::getKey).collect(Collectors.toList());
return (registrationIds != null && registrationIds.size() > 0) ? registrationIds.get(0) : null;
}
public Registration getByRegistration(String registrationId) {
return this.sessions.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
*/
private SecurityInfo addLwM2MClientToSession(String identity) {
ReadResultSecurityStore store = lwM2MCredentialsSecurityInfoValidator.createAndValidateCredentialsSecurityInfo(identity, TypeServer.CLIENT);
if (store.getSecurityMode() < LwM2MSecurityMode.DEFAULT_MODE.code) {
UUID profileUuid = (store.getDeviceProfile() != null && addUpdateProfileParameters(store.getDeviceProfile())) ? store.getDeviceProfile().getUuidId() : null;
if (store.getSecurityInfo() != null && profileUuid != null) {
String endpoint = store.getSecurityInfo().getEndpoint();
sessions.put(endpoint, new LwM2mClient(endpoint, store.getSecurityInfo().getIdentity(), store.getSecurityInfo(), store.getMsg(), profileUuid, UUID.randomUUID()));
} else if (store.getSecurityMode() == NO_SEC.code && profileUuid != null) {
sessions.put(identity, new LwM2mClient(identity, null, null, store.getMsg(), profileUuid, UUID.randomUUID()));
} else {
log.error("Registration failed: FORBIDDEN/profileUuid/device [{}] , endpointId: [{}]", profileUuid, identity);
/**
* Return Error securityInfo
*/
byte[] preSharedKey = Hex.decodeHex("0A0B".toCharArray());
SecurityInfo infoError = SecurityInfo.newPreSharedKeyInfo("error", "error_identity", preSharedKey);
return infoError;
}
}
return store.getSecurityInfo();
}
public Map<String, LwM2mClient> getSession(UUID sessionUuId) {
return this.sessions.entrySet().stream()
.filter(e -> e.getValue().getSessionId().equals(sessionUuId))
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
}
public Map<String, LwM2mClient> getSessions() {
return this.sessions;
}
public Map<UUID, LwM2mClientProfile> getProfiles() {
return this.profiles;
}
public LwM2mClientProfile getProfile(UUID profileUuId) {
return this.profiles.get(profileUuId);
}
public LwM2mClientProfile getProfile(String registrationId) {
UUID profileUUid = this.getSessions().get(registrationId).getProfileId();
return this.getProfiles().get(profileUUid);
}
public Map<UUID, LwM2mClientProfile> setProfiles(Map<UUID, LwM2mClientProfile> profiles) {
return this.profiles = profiles;
}
public boolean addUpdateProfileParameters(DeviceProfile deviceProfile) {
LwM2mClientProfile lwM2MClientProfile = LwM2mTransportHandler.getLwM2MClientProfileFromThingsboard(deviceProfile);
if (lwM2MClientProfile != null) {
profiles.put(deviceProfile.getUuidId(), lwM2MClientProfile);
return true;
}
return false;
}
}

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

@ -29,6 +29,7 @@ import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.thingsboard.server.cache.TBRedisCacheConfiguration; import org.thingsboard.server.cache.TBRedisCacheConfiguration;
import org.thingsboard.server.queue.util.TbLwM2mTransportComponent; 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 org.thingsboard.server.transport.lwm2m.server.client.LwM2mClientContext;
import java.util.Collection; import java.util.Collection;
@ -89,10 +90,14 @@ public class TbLwM2mStoreConfiguration {
} }
@Override @Override
public SecurityInfo getByEndpoint(String endpoint) { public SecurityInfo getByEndpoint(String endPoint) {
SecurityInfo securityInfo = securityStore.getByEndpoint(endpoint); SecurityInfo securityInfo = securityStore.getByEndpoint(endPoint);
if (securityInfo == null) { if (securityInfo == null) {
securityInfo = clientContext.addLwM2mClientToSession(endpoint).getSecurityInfo(); LwM2mClient lwM2mClient = clientContext.getLwM2MClient(endPoint, null);
if (lwM2mClient != null && !lwM2mClient.getRegistration().getIdentity().isSecure()){
return null;
}
securityInfo = clientContext.addLwM2mClientToSession(endPoint).getSecurityInfo();
try { try {
if (securityInfo != null) { if (securityInfo != null) {
add(securityInfo); add(securityInfo);

1
dao/src/main/java/org/thingsboard/server/dao/model/ModelConstants.java

@ -466,7 +466,6 @@ public class ModelConstants {
public static final String RESOURCE_TITLE_COLUMN = TITLE_PROPERTY; public static final String RESOURCE_TITLE_COLUMN = TITLE_PROPERTY;
public static final String RESOURCE_DATA_COLUMN = "data"; public static final String RESOURCE_DATA_COLUMN = "data";
/** /**
* Cassandra attributes and timeseries constants. * Cassandra attributes and timeseries constants.
*/ */

3
dao/src/main/java/org/thingsboard/server/dao/model/sql/TbResourceEntity.java

@ -65,7 +65,8 @@ public class TbResourceEntity extends BaseSqlEntity<TbResource> implements Searc
} }
public TbResourceEntity(TbResource resource) { public TbResourceEntity(TbResource resource) {
this.setUuid(resource.getId().getId()); this.id = resource.getUuidId();
this.createdTime = resource.getCreatedTime();
this.tenantId = resource.getTenantId().getId(); this.tenantId = resource.getTenantId().getId();
this.title = resource.getTitle(); this.title = resource.getTitle();
this.resourceType = resource.getResourceType().name(); this.resourceType = resource.getResourceType().name();

31
dao/src/main/java/org/thingsboard/server/dao/resource/BaseTbResourceService.java

@ -43,6 +43,8 @@ import java.util.Comparator;
import java.util.List; import java.util.List;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import static org.thingsboard.server.common.data.lwm2m.LwM2mConstants.LWM2M_SEPARATOR_KEY;
import static org.thingsboard.server.common.data.lwm2m.LwM2mConstants.LWM2M_SEPARATOR_SEARCH_TEXT;
import static org.thingsboard.server.dao.device.DeviceServiceImpl.INCORRECT_TENANT_ID; import static org.thingsboard.server.dao.device.DeviceServiceImpl.INCORRECT_TENANT_ID;
import static org.thingsboard.server.dao.service.Validator.validateId; import static org.thingsboard.server.dao.service.Validator.validateId;
@ -62,26 +64,24 @@ public class BaseTbResourceService implements TbResourceService {
} }
@Override @Override
public TbResource saveResource(TbResource resource) throws InvalidDDFFileException, IOException { public TbResource saveResource(TbResource tbResource) throws InvalidDDFFileException, IOException {
log.trace("Executing saveResource [{}]", resource); log.trace("Executing saveResource [{}]", tbResource);
if (ResourceType.LWM2M_MODEL.equals(tbResource.getResourceType())) {
if (resource.getId() == null && ResourceType.LWM2M_MODEL.equals(resource.getResourceType())) {
List<ObjectModel> objectModels = List<ObjectModel> objectModels =
ddfFileParser.parseEx(new ByteArrayInputStream(Base64.getDecoder().decode(resource.getData())), resource.getSearchText()); ddfFileParser.parseEx(new ByteArrayInputStream(Base64.getDecoder().decode(tbResource.getData())), tbResource.getSearchText());
if (!objectModels.isEmpty()) { if (!objectModels.isEmpty()) {
ObjectModel objectModel = objectModels.get(0); ObjectModel objectModel = objectModels.get(0);
String resourceKey = objectModel.id + LWM2M_SEPARATOR_KEY + objectModel.getVersion();
String resourceKey = objectModel.id + "_" + objectModel.getVersion();
String name = objectModel.name; String name = objectModel.name;
resource.setResourceKey(resourceKey); tbResource.setResourceKey(resourceKey);
resource.setTitle(name); tbResource.setTitle(name);
resource.setSearchText(resourceKey + ":" + name); tbResource.setSearchText(resourceKey + LWM2M_SEPARATOR_SEARCH_TEXT + name);
} else {
throw new DataValidationException(String.format("Could not parse the XML of objectModel with name %s", tbResource.getSearchText()));
} }
} }
validate(tbResource);
validate(resource); return resourceDao.save(tbResource.getTenantId(), tbResource);
return resourceDao.saveResource(resource);
} }
@Override @Override
@ -162,9 +162,6 @@ public class BaseTbResourceService implements TbResourceService {
throw new DataValidationException("Resource value should be specified!"); throw new DataValidationException("Resource value should be specified!");
} }
validate(resource.getTenantId(), resource.getResourceType(), resource.getResourceKey()); validate(resource.getTenantId(), resource.getResourceType(), resource.getResourceKey());
if (resource.getResourceType().equals(ResourceType.LWM2M_MODEL) && this.toLwM2mObject(resource) == null) {
throw new DataValidationException(String.format("Could not parse the XML of objectModel with name %s", resource.getSearchText()));
}
} }
protected void validate(TenantId tenantId, ResourceType resourceType, String resourceId) { protected void validate(TenantId tenantId, ResourceType resourceType, String resourceId) {

2
dao/src/main/java/org/thingsboard/server/dao/resource/TbResourceDao.java

@ -26,8 +26,6 @@ import java.util.List;
public interface TbResourceDao extends Dao<TbResource> { public interface TbResourceDao extends Dao<TbResource> {
TbResource saveResource(TbResource resource);
TbResource getResource(TenantId tenantId, ResourceType resourceType, String resourceId); TbResource getResource(TenantId tenantId, ResourceType resourceType, String resourceId);
PageData<TbResource> findAllByTenantId(TenantId tenantId, PageLink pageLink); PageData<TbResource> findAllByTenantId(TenantId tenantId, PageLink pageLink);

7
dao/src/main/java/org/thingsboard/server/dao/sql/resource/JpaTbResourceDao.java

@ -18,7 +18,6 @@ package org.thingsboard.server.dao.sql.resource;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.data.repository.CrudRepository; import org.springframework.data.repository.CrudRepository;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import org.thingsboard.server.common.data.ResourceType; import org.thingsboard.server.common.data.ResourceType;
import org.thingsboard.server.common.data.TbResource; import org.thingsboard.server.common.data.TbResource;
import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.id.TenantId;
@ -53,12 +52,6 @@ public class JpaTbResourceDao extends JpaAbstractSearchTextDao<TbResourceEntity,
return resourceRepository; return resourceRepository;
} }
@Override
@Transactional
public TbResource saveResource(TbResource resource) {
return DaoUtil.getData(resourceRepository.save(new TbResourceEntity(resource)));
}
@Override @Override
public TbResource getResource(TenantId tenantId, ResourceType resourceType, String resourceKey) { public TbResource getResource(TenantId tenantId, ResourceType resourceType, String resourceKey) {

Loading…
Cancel
Save