From 16a520cd80f03a31e6092663333daeed315f14da Mon Sep 17 00:00:00 2001 From: nickAS21 Date: Fri, 17 Sep 2021 19:20:05 +0300 Subject: [PATCH] Lwm2m Fix bug review last --- .../DefaultLwM2MAttributesService.java | 2 +- .../lwm2m/server/client/LwM2mClient.java | 36 ++++++------- .../server/client/LwM2mClientContext.java | 5 +- .../server/client/LwM2mClientContextImpl.java | 24 ++++----- .../DefaultLwM2mDownlinkMsgHandler.java | 50 +++++++++---------- .../server/downlink/TbLwM2MCreateRequest.java | 5 +- .../server/downlink/TbLwM2MReadCallback.java | 20 ++++++++ .../downlink/TbLwM2MTargetedCallback.java | 47 +++++------------ .../rpc/DefaultLwM2MRpcRequestHandler.java | 39 +++++++++++---- .../lwm2m/utils/LwM2mTransportUtil.java | 11 +--- .../thingsboard/common/util/JacksonUtil.java | 21 ++++++-- .../dao/device/DeviceProfileServiceImpl.java | 3 -- 12 files changed, 130 insertions(+), 133 deletions(-) diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/attributes/DefaultLwM2MAttributesService.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/attributes/DefaultLwM2MAttributesService.java index f7df2ee658..e54277060a 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/attributes/DefaultLwM2MAttributesService.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/attributes/DefaultLwM2MAttributesService.java @@ -194,7 +194,7 @@ public class DefaultLwM2MAttributesService implements LwM2MAttributesService { Map attributesUpdate = new ConcurrentHashMap<>(); tsKvProtos.forEach(tsKvProto -> { try { - String pathIdVer = clientContext.getObjectIdByKeyNameFromProfile(lwM2MClient, tsKvProto.getKv().getKey(), false); + String pathIdVer = clientContext.getObjectIdByKeyNameFromProfile(lwM2MClient, tsKvProto.getKv().getKey()); if (pathIdVer != null) { // #1.1 if (lwM2MClient.getSharedAttributes().containsKey(pathIdVer)) { 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 33b1972fa9..2cc69f2c58 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 @@ -61,7 +61,6 @@ import java.util.stream.Collectors; import java.util.stream.Stream; import static org.thingsboard.server.common.data.lwm2m.LwM2mConstants.LWM2M_SEPARATOR_PATH; -import static org.thingsboard.server.transport.lwm2m.utils.LwM2mTransportUtil.LWM2M_OBJECT_VERSION_DEFAULT; import static org.thingsboard.server.transport.lwm2m.utils.LwM2mTransportUtil.convertMultiResourceValuesFromRpcBody; import static org.thingsboard.server.transport.lwm2m.utils.LwM2mTransportUtil.convertObjectIdToVersionedId; import static org.thingsboard.server.transport.lwm2m.utils.LwM2mTransportUtil.equalsResourceTypeGetSimpleName; @@ -277,7 +276,7 @@ public class LwM2mClient implements Serializable { LwM2mPath pathIds = new LwM2mPath(fromVersionedIdToObjectId(pathIdVer)); String verSupportedObject = registration.getSupportedObject().get(pathIds.getObjectId()); String verRez = getVerFromPathIdVerOrId(pathIdVer); - return verRez == null || verRez.equals(verSupportedObject) ? modelProvider.getObjectModel(registration) + return verRez != null && verRez.equals(verSupportedObject) ? modelProvider.getObjectModel(registration) .getResourceModel(pathIds.getObjectId(), pathIds.getResourceId()) : null; } @@ -294,7 +293,7 @@ public class LwM2mClient implements Serializable { LwM2mPath pathIds = new LwM2mPath(fromVersionedIdToObjectId(pathIdVer)); String verSupportedObject = registration.getSupportedObject().get(pathIds.getObjectId()); String verRez = getVerFromPathIdVerOrId(pathIdVer); - return verRez == null || verRez.equals(verSupportedObject) ? modelProvider.getObjectModel(registration) + return verRez != null && verRez.equals(verSupportedObject) ? modelProvider.getObjectModel(registration) .getObjectModel(pathIds.getObjectId()) : null; } @@ -339,7 +338,7 @@ public class LwM2mClient implements Serializable { value.getClass().getSimpleName() + "is bad. Value of Multi-Instance Resource must be in Json format!"); } } else { - Object valueRez = value.getClass().getSimpleName().equals("Integer") ? ((Integer) value).longValue() : value; + Object valueRez = value instanceof Integer ? ((Integer) value).longValue() : value; resource = LwM2mSingleResource.newResource(resourceId, converter.convertValue(valueRez, equalsResourceTypeGetSimpleName(value), resourceModel.type, pathIds), resourceModel.type); } @@ -370,8 +369,7 @@ public class LwM2mClient implements Serializable { return String.format("Specified object id %s absent in the list supported objects of the client or is security object!", pathIds.getObjectId()); } else { String verRez = getVerFromPathIdVerOrId(path); - if ((verRez != null && !verRez.equals(verSupportedObject)) || - (verRez == null && !LWM2M_OBJECT_VERSION_DEFAULT.equals(verSupportedObject))) { + if (verRez == null || !verRez.equals(verSupportedObject)) { return String.format("Specified resource id %s is not valid version! Must be version: %s", path, verSupportedObject); } } @@ -425,23 +423,17 @@ public class LwM2mClient implements Serializable { } } - private Set clientSupportContentFormat(Registration registration) { + static private Set clientSupportContentFormat(Registration registration) { Set contentFormats = new HashSet<>(); - if (registration == null) { - contentFormats.add(ContentFormat.DEFAULT); - } else { - String code = Arrays.stream(registration.getObjectLinks()).filter(link -> link.getUrl().equals("/")). - findFirst().get().getAttributes().get("ct"); - if (code != null) { - Set codes = Stream.of(code.replaceAll("\"", "").split(" ", -1)) - .map(String::trim) - .map(Integer::parseInt) - .map(ContentFormat::fromCode) - .collect(Collectors.toSet()); - contentFormats.addAll(codes); - } else { - contentFormats.add(ContentFormat.DEFAULT); - } + contentFormats.add(ContentFormat.DEFAULT); + String code = Arrays.stream(registration.getObjectLinks()).filter(link -> link.getUrl().equals("/")).findFirst().get().getAttributes().get("ct"); + if (code != null) { + Set codes = Stream.of(code.replaceAll("\"", "").split(" ", -1)) + .map(String::trim) + .map(Integer::parseInt) + .map(ContentFormat::fromCode) + .collect(Collectors.toSet()); + contentFormats.addAll(codes); } return contentFormats; } 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 5b720a8b66..8d97e775c6 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 @@ -15,7 +15,6 @@ */ package org.thingsboard.server.transport.lwm2m.server.client; -import org.eclipse.leshan.core.request.ContentFormat; import org.eclipse.leshan.server.registration.Registration; import org.thingsboard.server.common.data.DeviceProfile; import org.thingsboard.server.common.data.device.profile.Lwm2mDeviceProfileTransportConfiguration; @@ -52,7 +51,7 @@ public interface LwM2mClientContext { LwM2mClient getClientByDeviceId(UUID deviceId); - String getObjectIdByKeyNameFromProfile(LwM2mClient lwM2mClient, String keyName, boolean isCompositeOperation); + String getObjectIdByKeyNameFromProfile(LwM2mClient lwM2mClient, String keyName); void registerClient(Registration registration, ValidateDeviceCredentialsResponse credentials); @@ -62,8 +61,6 @@ public interface LwM2mClientContext { void sendMsgsAfterSleeping(LwM2mClient lwM2MClient); - ContentFormat getContentFormatComposite(LwM2mClient client); - void onUplink(LwM2mClient client); Long getRequestTimeout(LwM2mClient client); 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 71f4a0058a..413629ebc1 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 @@ -19,7 +19,6 @@ import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.eclipse.leshan.core.SecurityMode; import org.eclipse.leshan.core.node.LwM2mPath; -import org.eclipse.leshan.core.request.ContentFormat; import org.eclipse.leshan.server.registration.Registration; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Lazy; @@ -58,7 +57,6 @@ import java.util.function.Predicate; import static org.eclipse.leshan.core.SecurityMode.NO_SEC; import static org.thingsboard.server.transport.lwm2m.utils.LwM2mTransportUtil.convertObjectIdToVersionedId; -import static org.thingsboard.server.transport.lwm2m.utils.LwM2mTransportUtil.getMsgException; @Slf4j @Service @@ -289,14 +287,16 @@ public class LwM2mClientContextImpl implements LwM2mClientContext { } @Override - public String getObjectIdByKeyNameFromProfile(LwM2mClient client, String keyName, boolean isCompositeOperation) { + public String getObjectIdByKeyNameFromProfile(LwM2mClient client, String keyName) { Lwm2mDeviceProfileTransportConfiguration profile = getProfile(client.getProfileId()); - Set msgException = ConcurrentHashMap.newKeySet(); - msgException.add(""); - return profile.getObserveAttr().getKeyName().entrySet().stream() - .filter(e -> e.getValue().equals(keyName) && (isCompositeOperation || !msgException.add(client.isValidObjectVersion(e.getKey())))).findFirst().orElseThrow( - () -> new IllegalArgumentException(getMsgException (keyName, msgException)) - ).getKey(); + for (Map.Entry entry : profile.getObserveAttr().getKeyName().entrySet()) { + String k = entry.getKey(); + String v = entry.getValue(); + if (v.equals(keyName) && client.isValidObjectVersion(k).isEmpty()) { + return k; + } + } + throw new IllegalArgumentException(keyName + " is not configured in the device profile!"); } public Registration getRegistration(String registrationId) { @@ -410,12 +410,6 @@ public class LwM2mClientContextImpl implements LwM2mClientContext { return lwM2mClientsByRegistrationId.values().stream().filter(e -> deviceId.equals(e.getDeviceId())).findFirst().orElse(null); } - @Override - public ContentFormat getContentFormatComposite(LwM2mClient client) { - return client.getClientSupportContentFormats().contains(ContentFormat.SENML_JSON) ? ContentFormat.SENML_JSON : - client.getClientSupportContentFormats().contains(ContentFormat.SENML_CBOR) ? ContentFormat.SENML_CBOR : null; - } - @Override public boolean isDownlinkAllowed(LwM2mClient client) { PowerMode powerMode = client.getPowerMode(); diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/DefaultLwM2mDownlinkMsgHandler.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/DefaultLwM2mDownlinkMsgHandler.java index bf475a6fb4..71a27def66 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/DefaultLwM2mDownlinkMsgHandler.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/DefaultLwM2mDownlinkMsgHandler.java @@ -147,9 +147,9 @@ public class DefaultLwM2mDownlinkMsgHandler extends LwM2MExecutorAwareService im @Override public void sendReadCompositeRequest(LwM2mClient client, TbLwM2MReadCompositeRequest request, - DownlinkRequestCallback callback, ContentFormat contentFormatComposite) { + DownlinkRequestCallback callback, ContentFormat compositeContentFormat) { try { - ReadCompositeRequest downlink = new ReadCompositeRequest(contentFormatComposite, contentFormatComposite, request.getObjectIds()); + ReadCompositeRequest downlink = new ReadCompositeRequest(compositeContentFormat, compositeContentFormat, request.getObjectIds()); sendCompositeRequest(client, downlink, this.config.getTimeout(), callback); } catch (InvalidRequestException e) { callback.onValidationError(request.toString(), e.getMessage()); @@ -207,13 +207,15 @@ public class DefaultLwM2mDownlinkMsgHandler extends LwM2MExecutorAwareService im } } if (resourceModelExecute == null) { - callback.onValidationError(request.toString(), "ResourceModel with " + request.getVersionedId() + " is absent in system. Need ddd Lwm2m Model with id=" + - pathIds.getObjectId() + " ver=" + getVerFromPathIdVerOrId(request.getVersionedId()) + " to profile."); + callback.onValidationError(request.toString(), "ResourceModel with " + request.getVersionedId() + + " is absent in system. Need ddd Lwm2m Model with id=" + pathIds.getObjectId() + " ver=" + + getVerFromPathIdVerOrId(request.getVersionedId()) + " to profile."); } else if (resourceModelExecute.operations.isExecutable()) { ExecuteRequest downlink; if (request.getParams() != null && !resourceModelExecute.multiple) { - downlink = new ExecuteRequest(request.getObjectId(), (String) this.converter.convertValue(request.getParams(), resourceModelExecute.type, ResourceModel.Type.STRING, new LwM2mPath(request.getObjectId()))); + downlink = new ExecuteRequest(request.getObjectId(), (String) this.converter.convertValue(request.getParams(), + resourceModelExecute.type, ResourceModel.Type.STRING, new LwM2mPath(request.getObjectId()))); } else { downlink = new ExecuteRequest(request.getObjectId()); } @@ -357,9 +359,11 @@ public class DefaultLwM2mDownlinkMsgHandler extends LwM2MExecutorAwareService im * int rscId = resultIds.getObjectInstanceId(); * contentFormat – Format of the payload (TLV or JSON). */ - Collection resources = client.getNewResourcesForInstance(request.getVersionedId(), request.getValue(), this.config.getModelProvider(), this.converter); + Collection resources = client.getNewResourcesForInstance(request.getVersionedId(), + request.getValue(), this.config.getModelProvider(), this.converter); if (resources.size() > 0) { - downlink = new WriteRequest(WriteRequest.Mode.UPDATE, contentFormat, resultIds.getObjectId(), resultIds.getObjectInstanceId(), resources); + downlink = new WriteRequest(WriteRequest.Mode.UPDATE, contentFormat, resultIds.getObjectId(), + resultIds.getObjectInstanceId(), resources); } else { callback.onValidationError(toString(request), "No resources to update!"); } @@ -370,24 +374,30 @@ public class DefaultLwM2mDownlinkMsgHandler extends LwM2MExecutorAwareService im if (resourceModelWrite.multiple) { try { Map value = convertMultiResourceValuesFromRpcBody(request.getValue(), resourceModelWrite.type, request.getObjectId()); - downlink = new WriteRequest(WriteRequest.Mode.UPDATE, contentFormat, resultIds.getObjectId(), resultIds.getObjectInstanceId(), resultIds.getResourceId(), + downlink = new WriteRequest(WriteRequest.Mode.UPDATE, contentFormat, resultIds.getObjectId(), + resultIds.getObjectInstanceId(), resultIds.getResourceId(), value, resourceModelWrite.type); } catch (Exception e1) { - callback.onValidationError(toString(request), "Resource id=" + resultIds.toString() + ", value = " + request.getValue() + ", class = " + request.getValue().getClass().getSimpleName() + "is bad. Value of Multi-Instance Resource must be in Json format!"); + callback.onValidationError(toString(request), "Resource id=" + resultIds.toString() + ", value = " + + request.getValue() + ", class = " + request.getValue().getClass().getSimpleName() + + "is bad. Value of Multi-Instance Resource must be in Json format!"); } } } 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!"); } } if (downlink != null) { sendSimpleRequest(client, downlink, request.getTimeout(), callback); } else { - callback.onValidationError(toString(request), "Resource " + request.getVersionedId() + ". This operation can only be used for ObjectInstance or Multi-Instance Resource !"); + callback.onValidationError(toString(request), "Resource " + request.getVersionedId() + + ". This operation can only be used for ObjectInstance or Multi-Instance Resource !"); } } else { - callback.onValidationError(toString(request), "Resource " + request.getVersionedId() + ". This operation can only be used for ObjectInstance or Resource (multiple)"); + callback.onValidationError(toString(request), "Resource " + request.getVersionedId() + + ". This operation can only be used for ObjectInstance or Resource (multiple)"); } } catch (Exception e) { callback.onValidationError(toString(request), e.getMessage()); @@ -406,7 +416,6 @@ public class DefaultLwM2mDownlinkMsgHandler extends LwM2MExecutorAwareService im if (resultIds.isObject() || resultIds.isObjectInstance()) { Collection resources; if (resultIds.isObject()) { -// contentFormat = ContentFormat.TLV; if (request.getValue() != null) { resources = client.getNewResourcesForInstance(request.getVersionedId(), request.getValue(), this.config.getModelProvider(), this.converter); downlink = new CreateRequest(contentFormat, resultIds.getObjectId(), resources); @@ -584,18 +593,9 @@ public class DefaultLwM2mDownlinkMsgHandler extends LwM2MExecutorAwareService im private static ContentFormat getRequestContentFormat(LwM2mClient client, String versionedId, LwM2mModelProvider modelProvider) { LwM2mPath pathIds = new LwM2mPath(fromVersionedIdToObjectId(versionedId)); - if (pathIds.isResourceInstance()) { + if (pathIds.isResource() || pathIds.isResourceInstance()) { ResourceModel resourceModel = client.getResourceModel(versionedId, modelProvider); - if (OBJLNK.equals(resourceModel.type)) { - return ContentFormat.LINK; - } else if (OPAQUE.equals(resourceModel.type)) { - return ContentFormat.OPAQUE; - } else { - return findFirst(client.getClientSupportContentFormats(), client.getDefaultContentFormat(), ContentFormat.CBOR, ContentFormat.SENML_CBOR, ContentFormat.SENML_JSON); - } - } else if (pathIds.isResource()) { - ResourceModel resourceModel = client.getResourceModel(versionedId, modelProvider); - if (resourceModel!= null && !resourceModel.multiple) { + if (resourceModel!= null && (pathIds.isResourceInstance() || (pathIds.isResource() && !resourceModel.multiple))) { if (OBJLNK.equals(resourceModel.type)) { return ContentFormat.LINK; } else if (OPAQUE.equals(resourceModel.type)) { @@ -639,7 +639,7 @@ public class DefaultLwM2mDownlinkMsgHandler extends LwM2MExecutorAwareService im try { return request != null ? request.toString() : ""; } catch (Exception e) { - log.trace("Failed to convert request to string", e); + log.debug("Failed to convert request to string", e); return request.getClass().getSimpleName(); } } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MCreateRequest.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MCreateRequest.java index 9eed9381a8..76e7ca845a 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MCreateRequest.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MCreateRequest.java @@ -30,7 +30,7 @@ public class TbLwM2MCreateRequest extends AbstractTbLwM2MTargetedDownlinkRequest @Getter private final ContentFormat objectContentFormat; @Getter - private final Map nodes;; + private final Map nodes; @Builder private TbLwM2MCreateRequest(String versionedId, long timeout, Object value, ContentFormat objectContentFormat, Map nodes) { @@ -44,7 +44,4 @@ public class TbLwM2MCreateRequest extends AbstractTbLwM2MTargetedDownlinkRequest public LwM2mOperationType getType() { return LwM2mOperationType.CREATE; } - - - } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MReadCallback.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MReadCallback.java index 59247b103b..0ae17ea449 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MReadCallback.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MReadCallback.java @@ -16,8 +16,10 @@ package org.thingsboard.server.transport.lwm2m.server.downlink; import lombok.extern.slf4j.Slf4j; +import org.eclipse.leshan.core.node.LwM2mSingleResource; import org.eclipse.leshan.core.request.ReadRequest; import org.eclipse.leshan.core.response.ReadResponse; +import org.eclipse.leshan.core.util.Hex; import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient; import org.thingsboard.server.transport.lwm2m.server.log.LwM2MTelemetryLogService; import org.thingsboard.server.transport.lwm2m.server.uplink.LwM2mUplinkMsgHandler; @@ -31,8 +33,26 @@ public class TbLwM2MReadCallback extends TbLwM2MUplinkTargetedCallback 0) { + int len = ((byte[])((LwM2mSingleResource) response.getContent()).getValue()).length; + String valueReplace = len + "Bytes"; + String valueStr = Hex.encodeHexString((byte[]) (((LwM2mSingleResource) response.getContent()).getValue())); + return response.toString().replace(valueReplace, valueStr); + } + } + return response.toString(); + } + else { + return response.toString(); + } + } + } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MTargetedCallback.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MTargetedCallback.java index c14527e3b1..8f7015a6fa 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MTargetedCallback.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MTargetedCallback.java @@ -17,10 +17,7 @@ package org.thingsboard.server.transport.lwm2m.server.downlink; import lombok.extern.slf4j.Slf4j; import org.eclipse.leshan.core.ResponseCode; -import org.eclipse.leshan.core.node.LwM2mSingleResource; import org.eclipse.leshan.core.response.LwM2mResponse; -import org.eclipse.leshan.core.response.ReadResponse; -import org.eclipse.leshan.core.util.Hex; import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient; import org.thingsboard.server.transport.lwm2m.server.log.LwM2MTelemetryLogService; @@ -50,40 +47,22 @@ public abstract class TbLwM2MTargetedCallback extends AbstractTbLwM2MReque @Override public void onSuccess(R request, T response) { //TODO convert camelCase to "camel case" using .split("(?= ResponseCode.BAD_REQUEST.getCode()) { - log.error("[{}] [{}] [{}] failed to process successful response [{}] ", client.getEndpoint(), requestName, versionedId != null ? versionedId : Arrays.toString(versionedIds), responseStr); - logService.log(client, String.format("[%s]: %s [%s] failed to process successful. Result: %s", LOG_LWM2M_ERROR, requestName, versionedId != null ? versionedId : Arrays.toString(versionedIds), responseStr)); - } - else { - log.trace("[{}] {} [{}] successful: {}", client.getEndpoint(), requestName, versionedId != null ? versionedId : versionedIds, responseStr); - logService.log(client, String.format("[%s]: %s [%s] successful. Result: %s", LOG_LWM2M_INFO, requestName, versionedId != null ? versionedId : Arrays.toString(versionedIds), responseStr)); + if (response instanceof LwM2mResponse) { + logForBadResponse(((LwM2mResponse) response).getCode().getCode(), response.toString(), request.getClass().getSimpleName()); } } - private String responseToString (ReadResponse response) { - if (response.getContent() instanceof LwM2mSingleResource) { - if (((LwM2mSingleResource) response.getContent()).getType().name().equals("OPAQUE")) { - if (((byte[])((LwM2mSingleResource) response.getContent()).getValue()).length > 0) { - int len = ((byte[])((LwM2mSingleResource) response.getContent()).getValue()).length; - String valueReplace = len + "Bytes"; - String valueStr = Hex.encodeHexString((byte[]) (((LwM2mSingleResource) response.getContent()).getValue())); - return response.toString().replace(valueReplace, valueStr); - } - } - return response.toString(); - } - else { - return response.toString(); + public void logForBadResponse(int code, String responseStr, String requestName) { + if (code > ResponseCode.CONTENT_CODE) { + log.error("[{}] [{}] [{}] failed to process successful response [{}] ", client.getEndpoint(), requestName, + versionedId != null ? versionedId : Arrays.toString(versionedIds), responseStr); + logService.log(client, String.format("[%s]: %s [%s] failed to process successful. Result: %s", LOG_LWM2M_ERROR, + requestName, versionedId != null ? versionedId : Arrays.toString(versionedIds), responseStr)); + } else { + log.trace("[{}] {} [{}] successful: {}", client.getEndpoint(), requestName, versionedId != null ? + versionedId : versionedIds, responseStr); + logService.log(client, String.format("[%s]: %s [%s] successful. Result: %s", LOG_LWM2M_INFO, requestName, + versionedId != null ? versionedId : Arrays.toString(versionedIds), responseStr)); } } } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/DefaultLwM2MRpcRequestHandler.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/DefaultLwM2MRpcRequestHandler.java index 12ee3581ac..a881047f91 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/DefaultLwM2MRpcRequestHandler.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/DefaultLwM2MRpcRequestHandler.java @@ -15,6 +15,7 @@ */ package org.thingsboard.server.transport.lwm2m.server.rpc; +import com.google.gson.JsonSyntaxException; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.eclipse.leshan.core.ResponseCode; @@ -25,6 +26,7 @@ import org.springframework.stereotype.Service; import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.server.common.data.StringUtils; import org.thingsboard.server.common.transport.TransportService; +import org.thingsboard.server.common.transport.util.JsonUtils; import org.thingsboard.server.gen.transport.TransportProtos; import org.thingsboard.server.queue.util.TbLwM2mTransportComponent; import org.thingsboard.server.transport.lwm2m.config.LwM2MTransportServerConfig; @@ -103,10 +105,6 @@ public class DefaultLwM2MRpcRequestHandler implements LwM2MRpcRequestHandler { if (operationType.isHasObjectId()) { LwM2MRpcRequestHeader header = JacksonUtil.fromString(rpcRequest.getParams(), LwM2MRpcRequestHeader.class); String objectId = getIdFromParameters(client, header); - ContentFormat contentFormat = null; - if (StringUtils.isNotEmpty(header.getContentFormat())) { - contentFormat = ContentFormat.fromName(header.getContentFormat()); - } switch (operationType) { case READ: sendReadRequest(client, rpcRequest, objectId); @@ -142,7 +140,7 @@ public class DefaultLwM2MRpcRequestHandler implements LwM2MRpcRequestHandler { throw new IllegalArgumentException("Unsupported operation: " + operationType.name()); } } else if (operationType.isComposite()) { - ContentFormat contentFormatComposite = clientContext.getContentFormatComposite(client); + ContentFormat contentFormatComposite = this.getContentFormatComposite(client); if (contentFormatComposite != null) { switch (operationType) { case READ_COMPOSITE: @@ -305,14 +303,21 @@ public class DefaultLwM2MRpcRequestHandler implements LwM2MRpcRequestHandler { new LwM2mPath(fromVersionedIdToObjectId(key.toString())); versionedId = key.toString(); } catch (Exception e) { - versionedId = clientContext.getObjectIdByKeyNameFromProfile(client, key.toString(), true); + versionedId = clientContext.getObjectIdByKeyNameFromProfile(client, key.toString()); } // validate value. Must be only primitive, not Json - if (value instanceof LinkedHashMap) { + try { + JsonUtils.parse(value.toString()); throw new IllegalArgumentException(String.format("nodes: %s is not validate value. " + "The WriteComposite operation is only used for SingleResources or/and ResourceInstance.", nodes.toString())); - } else { - newNodes.put(fromVersionedIdToObjectId(versionedId), value); + } catch (JsonSyntaxException jse) { +// if (value instanceof LinkedHashMap) { +// throw new IllegalArgumentException(String.format("nodes: %s is not validate value. " + +// "The WriteComposite operation is only used for SingleResources or/and ResourceInstance.", nodes.toString())); +// } + if (versionedId != null) { + newNodes.put(fromVersionedIdToObjectId(versionedId), value); + } } }); return newNodes; @@ -342,7 +347,7 @@ public class DefaultLwM2MRpcRequestHandler implements LwM2MRpcRequestHandler { private String getIdFromParameters(LwM2mClient client, LwM2MRpcRequestHeader header) { String targetId; if (StringUtils.isNotEmpty(header.getKey())) { - targetId = clientContext.getObjectIdByKeyNameFromProfile(client, header.getKey(), false); + targetId = clientContext.getObjectIdByKeyNameFromProfile(client, header.getKey()); } else if (StringUtils.isNotEmpty(header.getId())) { targetId = header.getId(); } else { @@ -356,7 +361,7 @@ public class DefaultLwM2MRpcRequestHandler implements LwM2MRpcRequestHandler { if (requestParams.getKeys() != null && requestParams.getKeys().length > 0) { Set targetIds = ConcurrentHashMap.newKeySet(); for (String key : requestParams.getKeys()) { - String targetId = clientContext.getObjectIdByKeyNameFromProfile(client, key, true); + String targetId = clientContext.getObjectIdByKeyNameFromProfile(client, key); if (targetId != null) { targetIds.add(targetId); } @@ -384,4 +389,16 @@ public class DefaultLwM2MRpcRequestHandler implements LwM2MRpcRequestHandler { public void onToServerRpcResponse(TransportProtos.ToServerRpcResponseMsg toServerResponse) { log.info("[{}] toServerRpcResponse", toServerResponse); } + + private ContentFormat getContentFormatComposite(LwM2mClient client) { + if (client.getClientSupportContentFormats().contains(ContentFormat.SENML_JSON)) { + return ContentFormat.SENML_JSON; + } + else if (client.getClientSupportContentFormats().contains(ContentFormat.SENML_CBOR)) { + return ContentFormat.SENML_CBOR; + } + else { + return null; + } + } } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/utils/LwM2mTransportUtil.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/utils/LwM2mTransportUtil.java index 76e5ce4d91..b04868c501 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/utils/LwM2mTransportUtil.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/utils/LwM2mTransportUtil.java @@ -63,7 +63,6 @@ import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Optional; -import java.util.Set; import static org.eclipse.leshan.core.attributes.Attribute.DIMENSION; import static org.eclipse.leshan.core.attributes.Attribute.GREATER_THAN; @@ -220,7 +219,7 @@ public class LwM2mTransportUtil { } catch (Exception e) { return null; } - return null; + return LWM2M_OBJECT_VERSION_DEFAULT; } public static String validPathIdVer(String pathIdVer, Registration registration) throws @@ -354,14 +353,6 @@ public class LwM2mTransportUtil { } } - public static String getMsgException(String keyName, Set msgException) { - if (msgException.size() == 1) { - msgException.add(" is not configured in the device profile!"); - } - msgException.remove(""); - return String.format("%s %s", keyName, String.join(",", msgException)).trim(); - } - public static Map convertMultiResourceValuesFromRpcBody(Object value, ResourceModel.Type type, String versionedId) throws Exception { String valueJsonStr = JsonUtils.riteValueAsString(value); return convertMultiResourceValuesFromJson((JsonObject) JsonUtils.parse(valueJsonStr), type, versionedId); diff --git a/common/util/src/main/java/org/thingsboard/common/util/JacksonUtil.java b/common/util/src/main/java/org/thingsboard/common/util/JacksonUtil.java index a71be5fe5f..ddd074fc6c 100644 --- a/common/util/src/main/java/org/thingsboard/common/util/JacksonUtil.java +++ b/common/util/src/main/java/org/thingsboard/common/util/JacksonUtil.java @@ -23,8 +23,8 @@ import com.fasterxml.jackson.databind.node.ObjectNode; import java.io.IOException; import java.util.Arrays; +import java.util.HashSet; import java.util.Set; -import java.util.concurrent.ConcurrentHashMap; /** * Created by Valerii Sosliuk on 5/12/2017. @@ -126,22 +126,35 @@ public class JacksonUtil { } + /** + * + * @param {bootstrap:client:host, client, client:port, client:endpoint} + * @param ":" + * @return + * - "bootstrap:client:host" + * -- if in nodeCredentialsValue is absent: + * --- "bootstrap" or "bootstrap:client" or "bootstrap:client:host" -> return "host" + * -- if in nodeCredentialsValue is absent: + * --- "client:port" -> return "port" + * -- if the nodeCredentialsValue contains: + * --- "client" and "client:port" -> "port" not add to Set + */ public static String validateFieldsToTree(JsonNode nodeCredentialsValue, String[] fields, String delimiter) { try { - Set msgSet = ConcurrentHashMap.newKeySet(); + StringBuilder msgSet = new StringBuilder(); for (String field : fields) { String[] keys = field.split(delimiter); JsonNode nodeVal = nodeCredentialsValue; for (String key : keys) { if (!nodeVal.hasNonNull(key)) { - msgSet.add(keys[keys.length - 1]); + msgSet.append(" " + keys[keys.length - 1]); break; } else { nodeVal = nodeVal.get(key); } } } - return String.join(", ", msgSet); + return msgSet.toString().trim(); } catch (Exception e) { throw new IllegalArgumentException(e); } diff --git a/dao/src/main/java/org/thingsboard/server/dao/device/DeviceProfileServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceProfileServiceImpl.java index adbaff5389..913ee19d1c 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/device/DeviceProfileServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceProfileServiceImpl.java @@ -133,9 +133,6 @@ public class DeviceProfileServiceImpl extends AbstractEntityService implements D @Autowired private DashboardService dashboardService; - @Autowired - private DeviceCredentialsService deviceCredentialsService; - private final Lock findOrCreateLock = new ReentrantLock(); @Cacheable(cacheNames = DEVICE_PROFILE_CACHE, key = "{#deviceProfileId.id}")