Merge pull request #5775 from YevhenBondarenko/develop/3.3.3-lwm2m-improvements

[3.3.3] lwm2m improvements
This commit is contained in:
Yevhen Bondarenko 2021-12-28 15:16:51 +02:00 committed by GitHub
commit b21e1be0eb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 62 additions and 87 deletions

View File

@ -108,24 +108,6 @@ public class RpcLwm2mIntegrationWriteTest extends AbstractRpcLwM2MIntegrationTes
assertTrue(actualValues.contains(expected)); assertTrue(actualValues.contains(expected));
} }
/**
* id
* WriteReplace {"id":"/19/0/0","value":"0081"}..
*/
@Test
public void testWriteReplaceValueMultipleResourceAsSingleResource_Result_BAD_REQUEST_Value_Multi_Instance_Resource_must_be_in_Json_format() throws Exception {
String objectInstanceIdVer_19 = (String) expectedObjectIdVerInstances.stream().filter(path -> ((String) path).contains("/" + BINARY_APP_DATA_CONTAINER)).findFirst().get();
String expectedPath = objectInstanceIdVer_19 + "/" + resourceId_0;
String expectedValue = "0081";
String actualResult = sendRPCWriteStringById("WriteReplace", expectedPath, expectedValue);
ObjectNode rpcActualResult = JacksonUtil.fromString(actualResult, ObjectNode.class);
assertEquals(ResponseCode.BAD_REQUEST.getName(), rpcActualResult.get("result").asText());
String actualValues = rpcActualResult.get("error").asText();
String expected = "Value of Multi-Instance Resource must be in Json format!";
assertTrue(actualValues.contains(expected));
}
/** /**
* bad: singleResource, operation="R" - only read * bad: singleResource, operation="R" - only read
* WriteReplace {"id":"/3/0/9","value":90} * WriteReplace {"id":"/3/0/9","value":90}

View File

@ -33,7 +33,6 @@ import org.thingsboard.server.gen.transport.TransportProtos.GetAttributeResponse
import org.thingsboard.server.queue.util.TbLwM2mTransportComponent; import org.thingsboard.server.queue.util.TbLwM2mTransportComponent;
import org.thingsboard.server.transport.lwm2m.config.LwM2MTransportServerConfig; import org.thingsboard.server.transport.lwm2m.config.LwM2MTransportServerConfig;
import org.thingsboard.server.transport.lwm2m.server.LwM2mTransportServerHelper; import org.thingsboard.server.transport.lwm2m.server.LwM2mTransportServerHelper;
import org.thingsboard.server.transport.lwm2m.utils.LwM2MTransportUtil;
import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient; 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 org.thingsboard.server.transport.lwm2m.server.downlink.LwM2mDownlinkMsgHandler; import org.thingsboard.server.transport.lwm2m.server.downlink.LwM2mDownlinkMsgHandler;
@ -42,6 +41,7 @@ import org.thingsboard.server.transport.lwm2m.server.downlink.TbLwM2MWriteRespon
import org.thingsboard.server.transport.lwm2m.server.log.LwM2MTelemetryLogService; import org.thingsboard.server.transport.lwm2m.server.log.LwM2MTelemetryLogService;
import org.thingsboard.server.transport.lwm2m.server.ota.LwM2MOtaUpdateService; import org.thingsboard.server.transport.lwm2m.server.ota.LwM2MOtaUpdateService;
import org.thingsboard.server.transport.lwm2m.server.uplink.LwM2mUplinkMsgHandler; import org.thingsboard.server.transport.lwm2m.server.uplink.LwM2mUplinkMsgHandler;
import org.thingsboard.server.transport.lwm2m.utils.LwM2MTransportUtil;
import org.thingsboard.server.transport.lwm2m.utils.LwM2mValueConverterImpl; import org.thingsboard.server.transport.lwm2m.utils.LwM2mValueConverterImpl;
import java.util.ArrayList; import java.util.ArrayList;
@ -191,7 +191,7 @@ public class DefaultLwM2MAttributesService implements LwM2MAttributesService {
@Override @Override
public void onAttributesUpdate(LwM2mClient lwM2MClient, List<TransportProtos.TsKvProto> tsKvProtos, boolean logFailedUpdateOfNonChangedValue) { public void onAttributesUpdate(LwM2mClient lwM2MClient, List<TransportProtos.TsKvProto> tsKvProtos, boolean logFailedUpdateOfNonChangedValue) {
log.trace("[{}] onAttributesUpdate [{}]", lwM2MClient.getEndpoint(), tsKvProtos); log.trace("[{}] onAttributesUpdate [{}]", lwM2MClient.getEndpoint(), tsKvProtos);
Map <String, TransportProtos.TsKvProto> attributesUpdate = new ConcurrentHashMap<>(); Map<String, TransportProtos.TsKvProto> attributesUpdate = new ConcurrentHashMap<>();
tsKvProtos.forEach(tsKvProto -> { tsKvProtos.forEach(tsKvProto -> {
try { try {
String pathIdVer = clientContext.getObjectIdByKeyNameFromProfile(lwM2MClient, tsKvProto.getKv().getKey()); String pathIdVer = clientContext.getObjectIdByKeyNameFromProfile(lwM2MClient, tsKvProto.getKv().getKey());
@ -207,8 +207,8 @@ public class DefaultLwM2MAttributesService implements LwM2MAttributesService {
attributesUpdate.put(pathIdVer, tsKvProto); attributesUpdate.put(pathIdVer, tsKvProto);
} }
} }
} catch (IllegalArgumentException e){ } catch (IllegalArgumentException e) {
log.error("Failed update resource ["+lwM2MClient.getEndpoint()+"] onAttributesUpdate:", e); log.error("Failed update resource [" + lwM2MClient.getEndpoint() + "] onAttributesUpdate:", e);
String logMsg = String.format("%s: Failed update resource onAttributesUpdate %s.", String logMsg = String.format("%s: Failed update resource onAttributesUpdate %s.",
LOG_LWM2M_ERROR, e.getMessage()); LOG_LWM2M_ERROR, e.getMessage());
logService.log(lwM2MClient, logMsg); logService.log(lwM2MClient, logMsg);
@ -226,8 +226,8 @@ public class DefaultLwM2MAttributesService implements LwM2MAttributesService {
try { try {
pushUpdateMultiToClientIfNeeded(lwM2MClient, resourceModel, (JsonElement) newValProto, pushUpdateMultiToClientIfNeeded(lwM2MClient, resourceModel, (JsonElement) newValProto,
(Map<Integer, LwM2mResourceInstance>) oldResourceValue, pathIdVer, logFailedUpdateOfNonChangedValue); (Map<Integer, LwM2mResourceInstance>) oldResourceValue, pathIdVer, logFailedUpdateOfNonChangedValue);
} catch (Exception e){ } catch (Exception e) {
log.error("Failed update resource ["+lwM2MClient.getEndpoint()+"] onAttributesUpdate:", e); log.error("Failed update resource [" + lwM2MClient.getEndpoint() + "] onAttributesUpdate:", e);
String logMsg = String.format("%s: Failed update resource onAttributesUpdate %s.", String logMsg = String.format("%s: Failed update resource onAttributesUpdate %s.",
LOG_LWM2M_ERROR, e.getMessage()); LOG_LWM2M_ERROR, e.getMessage());
logService.log(lwM2MClient, logMsg); logService.log(lwM2MClient, logMsg);
@ -256,10 +256,10 @@ public class DefaultLwM2MAttributesService implements LwM2MAttributesService {
private void pushUpdateMultiToClientIfNeeded(LwM2mClient client, ResourceModel resourceModel, JsonElement newValProto, private void pushUpdateMultiToClientIfNeeded(LwM2mClient client, ResourceModel resourceModel, JsonElement newValProto,
Map<Integer, LwM2mResourceInstance> valueOld, String versionedId, Map<Integer, LwM2mResourceInstance> valueOld, String versionedId,
boolean logFailedUpdateOfNonChangedValue) throws Exception { boolean logFailedUpdateOfNonChangedValue) {
Map newValues = convertMultiResourceValuesFromJson(newValProto, resourceModel.type, versionedId); Map<Integer, Object> newValues = convertMultiResourceValuesFromJson(newValProto, resourceModel.type, versionedId);
if (newValues.size() > 0 && valueOld != null && valueOld.size() > 0) { if (newValues.size() > 0 && valueOld != null && valueOld.size() > 0) {
valueOld.values().stream().forEach((v) -> { valueOld.values().forEach((v) -> {
if (newValues.containsKey(v.getId())) { if (newValues.containsKey(v.getId())) {
if (valueEquals(newValues.get(v.getId()), v.getValue())) { if (valueEquals(newValues.get(v.getId()), v.getValue())) {
newValues.remove(v.getId()); newValues.remove(v.getId());

View File

@ -37,7 +37,6 @@ import org.thingsboard.server.queue.util.TbLwM2mTransportComponent;
import org.thingsboard.server.transport.lwm2m.config.LwM2MTransportServerConfig; import org.thingsboard.server.transport.lwm2m.config.LwM2MTransportServerConfig;
import org.thingsboard.server.transport.lwm2m.secure.TbLwM2MSecurityInfo; import org.thingsboard.server.transport.lwm2m.secure.TbLwM2MSecurityInfo;
import org.thingsboard.server.transport.lwm2m.server.LwM2mTransportContext; import org.thingsboard.server.transport.lwm2m.server.LwM2mTransportContext;
import org.thingsboard.server.transport.lwm2m.server.LwM2mVersionedModelProvider;
import org.thingsboard.server.transport.lwm2m.server.ota.LwM2MOtaUpdateService; import org.thingsboard.server.transport.lwm2m.server.ota.LwM2MOtaUpdateService;
import org.thingsboard.server.transport.lwm2m.server.session.LwM2MSessionManager; import org.thingsboard.server.transport.lwm2m.server.session.LwM2MSessionManager;
import org.thingsboard.server.transport.lwm2m.server.store.TbLwM2MClientStore; import org.thingsboard.server.transport.lwm2m.server.store.TbLwM2MClientStore;
@ -71,7 +70,6 @@ public class LwM2mClientContextImpl implements LwM2mClientContext {
private final TbLwM2MClientStore clientStore; private final TbLwM2MClientStore clientStore;
private final LwM2MSessionManager sessionManager; private final LwM2MSessionManager sessionManager;
private final TransportDeviceProfileCache deviceProfileCache; private final TransportDeviceProfileCache deviceProfileCache;
private final LwM2mVersionedModelProvider modelProvider;
@Autowired @Autowired
@Lazy @Lazy
@ -229,10 +227,7 @@ public class LwM2mClientContextImpl implements LwM2mClientContext {
throw new LwM2MClientStateException(client.getState(), "Client is in invalid state."); throw new LwM2MClientStateException(client.getState(), "Client is in invalid state.");
} }
client.setRegistration(registration); client.setRegistration(registration);
onUplink(client); if (!awake(client)) {
if (compareAndSetSleepFlag(client, false)) {
sendMsgsAfterSleeping(client);
} else {
clientStore.put(client); clientStore.put(client);
} }
} finally { } finally {
@ -419,7 +414,7 @@ public class LwM2mClientContextImpl implements LwM2mClientContext {
powerMode = PowerMode.DRX; powerMode = PowerMode.DRX;
} }
} }
if (PowerMode.DRX.equals(powerMode)) { if (PowerMode.DRX.equals(powerMode) || otaUpdateService.isOtaDownloading(client)) {
return true; return true;
} }
client.lock(); client.lock();
@ -503,7 +498,7 @@ public class LwM2mClientContextImpl implements LwM2mClientContext {
sleepTask.cancel(false); sleepTask.cancel(false);
} }
Future<Void> task = context.getScheduler().schedule(() -> { Future<Void> task = context.getScheduler().schedule(() -> {
if (uplinkTime == client.getLastUplinkTime()) { if (uplinkTime == client.getLastUplinkTime() && !otaUpdateService.isOtaDownloading(client)) {
asleep(client); asleep(client);
} }
return null; return null;

View File

@ -300,14 +300,13 @@ public class DefaultLwM2mDownlinkMsgHandler extends LwM2MExecutorAwareService im
String msgError = ""; String msgError = "";
if (resourceModelWrite.multiple) { if (resourceModelWrite.multiple) {
try { try {
Map value = convertMultiResourceValuesFromRpcBody(request.getValue(), resourceModelWrite.type, request.getObjectId()); Map<Integer, Object> value = convertMultiResourceValuesFromRpcBody(request.getValue(), resourceModelWrite.type, request.getObjectId());
downlink = new WriteRequest(contentFormat, resultIds.getObjectId(), resultIds.getObjectInstanceId(), resultIds.getResourceId(), downlink = new WriteRequest(contentFormat, resultIds.getObjectId(), resultIds.getObjectInstanceId(), resultIds.getResourceId(),
value, resourceModelWrite.type); value, resourceModelWrite.type);
} catch (Exception e) { } catch (Exception e) {
msgError = "Resource id=" + resultIds.toString() + ", value = " + request.getValue() +
", class = " + request.getValue().getClass().getSimpleName() + ". Format value is bad. Value for this Multi-Instance Resource must be in Json format!";
} }
} else { }
if (downlink == null) {
try { try {
downlink = this.getWriteRequestSingleResource(resourceModelWrite.type, contentFormat, downlink = this.getWriteRequestSingleResource(resourceModelWrite.type, contentFormat,
resultIds.getObjectId(), resultIds.getObjectInstanceId(), resultIds.getResourceId(), request.getValue()); resultIds.getObjectId(), resultIds.getObjectInstanceId(), resultIds.getResourceId(), request.getValue());
@ -319,15 +318,11 @@ public class DefaultLwM2mDownlinkMsgHandler extends LwM2MExecutorAwareService im
if (downlink != null) { if (downlink != null) {
sendSimpleRequest(client, downlink, request.getTimeout(), callback); sendSimpleRequest(client, downlink, request.getTimeout(), callback);
} else { } else {
if (msgError.isEmpty()) {
msgError = "WriteRequest is null.";
}
callback.onValidationError(toString(request), msgError); callback.onValidationError(toString(request), msgError);
} }
} catch (Exception e) { } catch (Exception e) {
callback.onError(toString(request), e); callback.onError(toString(request), e);
} }
} else { } else {
callback.onValidationError(toString(request), "Resource " + request.getVersionedId() + " is not configured in the device profile!"); callback.onValidationError(toString(request), "Resource " + request.getVersionedId() + " is not configured in the device profile!");
} }
@ -378,7 +373,7 @@ public class DefaultLwM2mDownlinkMsgHandler extends LwM2MExecutorAwareService im
if (resourceModelWrite != null) { if (resourceModelWrite != null) {
if (resourceModelWrite.multiple) { if (resourceModelWrite.multiple) {
try { try {
Map value = convertMultiResourceValuesFromRpcBody(request.getValue(), resourceModelWrite.type, request.getObjectId()); Map<Integer, Object> value = convertMultiResourceValuesFromRpcBody(request.getValue(), resourceModelWrite.type, request.getObjectId());
downlink = new WriteRequest(WriteRequest.Mode.UPDATE, contentFormat, resultIds.getObjectId(), downlink = new WriteRequest(WriteRequest.Mode.UPDATE, contentFormat, resultIds.getObjectId(),
resultIds.getObjectInstanceId(), resultIds.getResourceId(), resultIds.getObjectInstanceId(), resultIds.getResourceId(),
value, resourceModelWrite.type); value, resourceModelWrite.type);
@ -608,7 +603,7 @@ public class DefaultLwM2mDownlinkMsgHandler extends LwM2MExecutorAwareService im
LwM2mPath pathIds = new LwM2mPath(fromVersionedIdToObjectId(versionedId)); LwM2mPath pathIds = new LwM2mPath(fromVersionedIdToObjectId(versionedId));
if (pathIds.isResource() || pathIds.isResourceInstance()) { if (pathIds.isResource() || pathIds.isResourceInstance()) {
ResourceModel resourceModel = client.getResourceModel(versionedId, modelProvider); ResourceModel resourceModel = client.getResourceModel(versionedId, modelProvider);
if (resourceModel!= null && (pathIds.isResourceInstance() || (pathIds.isResource() && !resourceModel.multiple))) { if (resourceModel != null && (pathIds.isResourceInstance() || (pathIds.isResource() && !resourceModel.multiple))) {
if (OBJLNK.equals(resourceModel.type)) { if (OBJLNK.equals(resourceModel.type)) {
return ContentFormat.LINK; return ContentFormat.LINK;
} else if (OPAQUE.equals(resourceModel.type)) { } else if (OPAQUE.equals(resourceModel.type)) {

View File

@ -182,8 +182,8 @@ public class DefaultLwM2MOtaUpdateService extends LwM2MExecutorAwareService impl
} }
var clientSettings = clientContext.getProfile(client.getProfileId()).getClientLwM2mSettings(); var clientSettings = clientContext.getProfile(client.getProfileId()).getClientLwM2mSettings();
onFirmwareStrategyUpdate(client, clientSettings); initFwStrategy(client, clientSettings);
onCurrentSoftwareStrategyUpdate(client, clientSettings); initSwStrategy(client, clientSettings);
if (!attributesToFetch.isEmpty()) { if (!attributesToFetch.isEmpty()) {
var future = attributesService.getSharedAttributes(client, attributesToFetch); var future = attributesService.getSharedAttributes(client, attributesToFetch);
@ -193,7 +193,7 @@ public class DefaultLwM2MOtaUpdateService extends LwM2MExecutorAwareService impl
Optional<String> newFwVersion = getAttributeValue(attrs, FIRMWARE_VERSION); Optional<String> newFwVersion = getAttributeValue(attrs, FIRMWARE_VERSION);
Optional<String> newFwTag = getAttributeValue(attrs, FIRMWARE_TAG); Optional<String> newFwTag = getAttributeValue(attrs, FIRMWARE_TAG);
Optional<String> newFwUrl = getAttributeValue(attrs, FIRMWARE_URL); Optional<String> newFwUrl = getAttributeValue(attrs, FIRMWARE_URL);
if (newFwTitle.isPresent() && newFwVersion.isPresent()) { if (newFwTitle.isPresent() && newFwVersion.isPresent() && !isOtaDownloading(client) && !UPDATING.equals(fwInfo.status)) {
onTargetFirmwareUpdate(client, newFwTitle.get(), newFwVersion.get(), newFwUrl, newFwTag); onTargetFirmwareUpdate(client, newFwTitle.get(), newFwVersion.get(), newFwUrl, newFwTag);
} }
} }
@ -245,19 +245,27 @@ public class DefaultLwM2MOtaUpdateService extends LwM2MExecutorAwareService impl
@Override @Override
public void onFirmwareStrategyUpdate(LwM2mClient client, OtherConfiguration configuration) { public void onFirmwareStrategyUpdate(LwM2mClient client, OtherConfiguration configuration) {
log.debug("[{}] Current fw strategy: {}", client.getEndpoint(), configuration.getFwUpdateStrategy()); log.debug("[{}] Current fw strategy: {}", client.getEndpoint(), configuration.getFwUpdateStrategy());
startFirmwareUpdateIfNeeded(client, initFwStrategy(client, configuration));
}
private LwM2MClientFwOtaInfo initFwStrategy(LwM2mClient client, OtherConfiguration configuration) {
LwM2MClientFwOtaInfo fwInfo = getOrInitFwInfo(client); LwM2MClientFwOtaInfo fwInfo = getOrInitFwInfo(client);
fwInfo.setStrategy(LwM2MFirmwareUpdateStrategy.fromStrategyFwByCode(configuration.getFwUpdateStrategy())); fwInfo.setStrategy(LwM2MFirmwareUpdateStrategy.fromStrategyFwByCode(configuration.getFwUpdateStrategy()));
fwInfo.setBaseUrl(configuration.getFwUpdateResource()); fwInfo.setBaseUrl(configuration.getFwUpdateResource());
startFirmwareUpdateIfNeeded(client, fwInfo); return fwInfo;
} }
@Override @Override
public void onCurrentSoftwareStrategyUpdate(LwM2mClient client, OtherConfiguration configuration) { public void onCurrentSoftwareStrategyUpdate(LwM2mClient client, OtherConfiguration configuration) {
log.debug("[{}] Current sw strategy: {}", client.getEndpoint(), configuration.getSwUpdateStrategy()); log.debug("[{}] Current sw strategy: {}", client.getEndpoint(), configuration.getSwUpdateStrategy());
startSoftwareUpdateIfNeeded(client, initSwStrategy(client, configuration));
}
private LwM2MClientSwOtaInfo initSwStrategy(LwM2mClient client, OtherConfiguration configuration) {
LwM2MClientSwOtaInfo swInfo = getOrInitSwInfo(client); LwM2MClientSwOtaInfo swInfo = getOrInitSwInfo(client);
swInfo.setStrategy(LwM2MSoftwareUpdateStrategy.fromStrategySwByCode(configuration.getSwUpdateStrategy())); swInfo.setStrategy(LwM2MSoftwareUpdateStrategy.fromStrategySwByCode(configuration.getSwUpdateStrategy()));
swInfo.setBaseUrl(configuration.getSwUpdateResource()); swInfo.setBaseUrl(configuration.getSwUpdateResource());
startSoftwareUpdateIfNeeded(client, swInfo); return swInfo;
} }
@Override @Override
@ -308,6 +316,7 @@ public class DefaultLwM2MOtaUpdateService extends LwM2MExecutorAwareService impl
if (FirmwareUpdateResult.INITIAL.equals(result) && OtaPackageUpdateStatus.UPDATING.equals(fwInfo.getStatus())) { if (FirmwareUpdateResult.INITIAL.equals(result) && OtaPackageUpdateStatus.UPDATING.equals(fwInfo.getStatus())) {
status = Optional.of(UPDATED); status = Optional.of(UPDATED);
fwInfo.setRetryAttempts(0); fwInfo.setRetryAttempts(0);
fwInfo.setFailedPackageId(null);
} }
status.ifPresent(otaStatus -> { status.ifPresent(otaStatus -> {
@ -388,6 +397,22 @@ public class DefaultLwM2MOtaUpdateService extends LwM2MExecutorAwareService impl
startSoftwareUpdateIfNeeded(client, fwInfo); startSoftwareUpdateIfNeeded(client, fwInfo);
} }
@Override
public boolean isOtaDownloading(LwM2mClient client) {
String endpoint = client.getEndpoint();
LwM2MClientFwOtaInfo fwInfo = fwStates.get(endpoint);
LwM2MClientSwOtaInfo swInfo = swStates.get(endpoint);
if (fwInfo != null && (DOWNLOADING.equals(fwInfo.getStatus()))) {
return true;
}
if (swInfo != null && (DOWNLOADING.equals(swInfo.getStatus()))) {
return true;
}
return false;
}
private void startFirmwareUpdateIfNeeded(LwM2mClient client, LwM2MClientFwOtaInfo fwInfo) { private void startFirmwareUpdateIfNeeded(LwM2mClient client, LwM2MClientFwOtaInfo fwInfo) {
try { try {
if (!fwInfo.isSupported() && fwInfo.isAssigned()) { if (!fwInfo.isSupported() && fwInfo.isAssigned()) {

View File

@ -55,4 +55,6 @@ public interface LwM2MOtaUpdateService {
void onCurrentSoftwareStateUpdate(LwM2mClient lwM2MClient, Long value); void onCurrentSoftwareStateUpdate(LwM2mClient lwM2MClient, Long value);
void onCurrentSoftwareResultUpdate(LwM2mClient client, Long result); void onCurrentSoftwareResultUpdate(LwM2mClient client, Long result);
boolean isOtaDownloading(LwM2mClient client);
} }

View File

@ -278,11 +278,9 @@ public class DefaultLwM2MRpcRequestHandler implements LwM2MRpcRequestHandler {
ResourceModel resourceModel = client.getResourceModel(versionedId, modelProvider); ResourceModel resourceModel = client.getResourceModel(versionedId, modelProvider);
if (resourceModel != null && resourceModel.multiple) { if (resourceModel != null && resourceModel.multiple) {
try { try {
Map value = convertMultiResourceValuesFromRpcBody(requestBody.getValue(), resourceModel.type, versionedId); Map<Integer, Object> value = convertMultiResourceValuesFromRpcBody(requestBody.getValue(), resourceModel.type, versionedId);
requestBody.setValue(value); requestBody.setValue(value);
} catch (Exception e) { } catch (Exception e) {
throw new IllegalArgumentException("Resource id=" + versionedId + ", class = " +
requestBody.getValue().getClass().getSimpleName() + ", value = " + requestBody.getValue() + " is bad. Value of Multi-Instance Resource must be in Json format!");
} }
} }
} }
@ -304,7 +302,7 @@ public class DefaultLwM2MRpcRequestHandler implements LwM2MRpcRequestHandler {
*/ */
private void sendWriteCompositeRequest(LwM2mClient client, TransportProtos.ToDeviceRpcRequestMsg requestMsg, ContentFormat contentFormatComposite) { private void sendWriteCompositeRequest(LwM2mClient client, TransportProtos.ToDeviceRpcRequestMsg requestMsg, ContentFormat contentFormatComposite) {
RpcWriteCompositeRequest rpcWriteCompositeRequest = JacksonUtil.fromString(requestMsg.getParams(), RpcWriteCompositeRequest.class); RpcWriteCompositeRequest rpcWriteCompositeRequest = JacksonUtil.fromString(requestMsg.getParams(), RpcWriteCompositeRequest.class);
Map validNodes = validateNodes(client, rpcWriteCompositeRequest.getNodes()); Map<String, Object> validNodes = validateNodes(client, rpcWriteCompositeRequest.getNodes());
if (validNodes.size() > 0) { if (validNodes.size() > 0) {
rpcWriteCompositeRequest.setNodes(validNodes); rpcWriteCompositeRequest.setNodes(validNodes);
var mainCallback = new TbLwM2MWriteResponseCompositeCallback(uplinkHandler, logService, client, null); var mainCallback = new TbLwM2MWriteResponseCompositeCallback(uplinkHandler, logService, client, null);
@ -315,22 +313,21 @@ public class DefaultLwM2MRpcRequestHandler implements LwM2MRpcRequestHandler {
} }
} }
private Map validateNodes(LwM2mClient client, Map nodes) { private Map<String, Object> validateNodes(LwM2mClient client, Map<String, Object> nodes) {
Map newNodes = new LinkedHashMap(); Map<String, Object> newNodes = new LinkedHashMap<>();
nodes.forEach((key, value) -> { nodes.forEach((key, value) -> {
String versionedId; String versionedId;
try { try {
// validate key.toString() LwM2mPath path = new LwM2mPath(fromVersionedIdToObjectId(key));
LwM2mPath path = new LwM2mPath(fromVersionedIdToObjectId(key.toString()));
if (path.isResource() || path.isResourceInstance()) { if (path.isResource() || path.isResourceInstance()) {
versionedId = key.toString(); versionedId = key;
} }
else { else {
throw new IllegalArgumentException(String.format("nodes: %s is not validate value. " + throw new IllegalArgumentException(String.format("nodes: %s is not validate value. " +
"The WriteComposite operation is only used for SingleResources or/and ResourceInstance.", nodes.toString())); "The WriteComposite operation is only used for SingleResources or/and ResourceInstance.", nodes.toString()));
} }
} catch (Exception e) { } catch (Exception e) {
versionedId = clientContext.getObjectIdByKeyNameFromProfile(client, key.toString()); versionedId = clientContext.getObjectIdByKeyNameFromProfile(client, key);
} }
// validate value. Must be only primitive, not JsonObject or JsonArray // validate value. Must be only primitive, not JsonObject or JsonArray
try { try {

View File

@ -351,14 +351,14 @@ public class LwM2MTransportUtil {
} }
} }
public static Map convertMultiResourceValuesFromRpcBody(Object value, ResourceModel.Type type, String versionedId) throws Exception { public static Map<Integer, Object> convertMultiResourceValuesFromRpcBody(Object value, ResourceModel.Type type, String versionedId) throws Exception {
String valueJsonStr = JsonUtils.writeValueAsString(value); String valueJsonStr = JsonUtils.writeValueAsString(value);
JsonElement element = JsonUtils.parse(valueJsonStr); JsonElement element = JsonUtils.parse(valueJsonStr);
return convertMultiResourceValuesFromJson(element, type, versionedId); return convertMultiResourceValuesFromJson(element, type, versionedId);
} }
public static Map convertMultiResourceValuesFromJson(JsonElement newValProto, ResourceModel.Type type, String versionedId) throws Exception{ public static Map<Integer, Object> convertMultiResourceValuesFromJson(JsonElement newValProto, ResourceModel.Type type, String versionedId) {
Map newValues = equalsMultiResourceValuesResourceType(type); Map<Integer, Object> newValues = new HashMap<>();
newValProto.getAsJsonObject().entrySet().forEach((obj) -> { newValProto.getAsJsonObject().entrySet().forEach((obj) -> {
newValues.put(Integer.valueOf(obj.getKey()), LwM2mValueConverterImpl.getInstance().convertValue(obj.getValue().getAsString(), newValues.put(Integer.valueOf(obj.getKey()), LwM2mValueConverterImpl.getInstance().convertValue(obj.getValue().getAsString(),
STRING, type, new LwM2mPath(fromVersionedIdToObjectId(versionedId)))); STRING, type, new LwM2mPath(fromVersionedIdToObjectId(versionedId))));
@ -366,27 +366,6 @@ public class LwM2MTransportUtil {
return newValues; return newValues;
} }
public static Map equalsMultiResourceValuesResourceType(ResourceModel.Type type) {
switch (type) {
case FLOAT:
return new HashMap<Integer, Float>();
case INTEGER:
return new HashMap<Integer, Integer>();
case STRING:
return new HashMap<Integer, String>();
case BOOLEAN:
return new HashMap<Integer, Boolean>();
case OPAQUE:
return new HashMap<Integer, byte[]>();
case TIME:
return new HashMap<Integer, Date>();
case OBJLNK:
return new HashMap<Integer, ObjectLink>();
default:
return null;
}
}
public static Object convertWriteAttributes(String type, Object value, DefaultLwM2mUplinkMsgHandler serviceImpl, String target) { public static Object convertWriteAttributes(String type, Object value, DefaultLwM2mUplinkMsgHandler serviceImpl, String target) {
switch (type) { switch (type) {
/** Integer [0:255]; */ /** Integer [0:255]; */