Browse Source

Lwm2m Fix bug review last

pull/5254/head
nickAS21 5 years ago
parent
commit
16a520cd80
  1. 2
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/attributes/DefaultLwM2MAttributesService.java
  2. 36
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClient.java
  3. 5
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClientContext.java
  4. 24
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClientContextImpl.java
  5. 50
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/DefaultLwM2mDownlinkMsgHandler.java
  6. 5
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MCreateRequest.java
  7. 20
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MReadCallback.java
  8. 47
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MTargetedCallback.java
  9. 39
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/DefaultLwM2MRpcRequestHandler.java
  10. 11
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/utils/LwM2mTransportUtil.java
  11. 21
      common/util/src/main/java/org/thingsboard/common/util/JacksonUtil.java
  12. 3
      dao/src/main/java/org/thingsboard/server/dao/device/DeviceProfileServiceImpl.java

2
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 <String, TransportProtos.TsKvProto> 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)) {

36
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<ContentFormat> clientSupportContentFormat(Registration registration) {
static private Set<ContentFormat> clientSupportContentFormat(Registration registration) {
Set<ContentFormat> 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<ContentFormat> 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<ContentFormat> codes = Stream.of(code.replaceAll("\"", "").split(" ", -1))
.map(String::trim)
.map(Integer::parseInt)
.map(ContentFormat::fromCode)
.collect(Collectors.toSet());
contentFormats.addAll(codes);
}
return contentFormats;
}

5
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);

24
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<String> 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<String, String> 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();

50
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<ReadCompositeRequest, ReadCompositeResponse> callback, ContentFormat contentFormatComposite) {
DownlinkRequestCallback<ReadCompositeRequest, ReadCompositeResponse> 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<LwM2mResource> resources = client.getNewResourcesForInstance(request.getVersionedId(), request.getValue(), this.config.getModelProvider(), this.converter);
Collection<LwM2mResource> 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<LwM2mResource> 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();
}
}

5
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<String, Object> nodes;;
private final Map<String, Object> nodes;
@Builder
private TbLwM2MCreateRequest(String versionedId, long timeout, Object value, ContentFormat objectContentFormat, Map<String, Object> nodes) {
@ -44,7 +44,4 @@ public class TbLwM2MCreateRequest extends AbstractTbLwM2MTargetedDownlinkRequest
public LwM2mOperationType getType() {
return LwM2mOperationType.CREATE;
}
}

20
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<ReadReque
@Override
public void onSuccess(ReadRequest request, ReadResponse response) {
logForBadResponse(response.getCode().getCode(), responseToString (response), request.getClass().getSimpleName());
super.onSuccess(request, response);
handler.onUpdateValueAfterReadResponse(client.getRegistration(), versionedId, response);
}
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();
}
}
}

47
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<R, T> extends AbstractTbLwM2MReque
@Override
public void onSuccess(R request, T response) {
//TODO convert camelCase to "camel case" using .split("(?<!(^|[A-Z]))(?=[A-Z])|(?<!^)(?=[A-Z][a-z])")
String requestName = request.getClass().getSimpleName();
String responseStr = response.toString();
int code = 0;
if (response instanceof ReadResponse) {
responseStr = responseToString ((ReadResponse) response);
code = ((ReadResponse) response).getCode().getCode();
}
else if (response instanceof LwM2mResponse) {
code = ((LwM2mResponse) response).getCode().getCode();
}
if (code >= 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));
}
}
}

39
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<String> 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;
}
}
}

11
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<String> 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);

21
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);
}

3
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}")

Loading…
Cancel
Save