Browse Source

Merge remote-tracking branch 'origin/Lwm2m_OPAQUE'

pull/4844/head
Andrii Shvaika 5 years ago
parent
commit
307aeaf57e
  1. 9
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/config/LwM2mVersion.java
  2. 81
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClient.java
  3. 12
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/ResourceValue.java
  4. 35
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/DefaultLwM2mDownlinkMsgHandler.java
  5. 7
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/LwM2mDownlinkMsgHandler.java
  6. 49
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/DefaultLwM2MRpcRequestHandler.java
  7. 13
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/RpcReadResponseCallback.java
  8. 3
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/composite/RpcReadResponseCompositeCallback.java

9
common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/config/LwM2mVersion.java

@ -20,8 +20,8 @@ import org.eclipse.leshan.core.LwM2m.Version;
import org.eclipse.leshan.core.request.ContentFormat;
public enum LwM2mVersion {
VERSION_1_0(0, Version.V1_0, ContentFormat.TLV),
VERSION_1_1(1, Version.V1_1, ContentFormat.TEXT);
VERSION_1_0(0, Version.V1_0, ContentFormat.TLV, false),
VERSION_1_1(1, Version.V1_1, ContentFormat.TEXT, true);
@Getter
private final int code;
@ -29,11 +29,14 @@ public enum LwM2mVersion {
private final Version version;
@Getter
private final ContentFormat contentFormat;
@Getter
private final boolean composite;
LwM2mVersion(int code, Version version, ContentFormat contentFormat) {
LwM2mVersion(int code, Version version, ContentFormat contentFormat, boolean composite) {
this.code = code;
this.version = version;
this.contentFormat = contentFormat;
this.composite = composite;
}
public static LwM2mVersion fromVersion(Version version) {

81
common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClient.java

@ -21,13 +21,13 @@ import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import org.eclipse.leshan.core.model.ObjectModel;
import org.eclipse.leshan.core.model.ResourceModel;
import org.eclipse.leshan.core.node.LwM2mObject;
import org.eclipse.leshan.core.node.LwM2mObjectInstance;
import org.eclipse.leshan.core.node.LwM2mMultipleResource;
import org.eclipse.leshan.core.node.LwM2mPath;
import org.eclipse.leshan.core.node.LwM2mResource;
import org.eclipse.leshan.core.node.LwM2mSingleResource;
import org.eclipse.leshan.core.node.codec.LwM2mValueConverter;
import org.eclipse.leshan.core.request.ContentFormat;
import org.eclipse.leshan.core.util.Hex;
import org.eclipse.leshan.server.model.LwM2mModelProvider;
import org.eclipse.leshan.server.registration.Registration;
import org.thingsboard.server.common.data.Device;
@ -44,6 +44,7 @@ import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.Serializable;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
@ -53,6 +54,7 @@ import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.stream.Collectors;
import static org.eclipse.leshan.core.model.ResourceModel.Type.OPAQUE;
import static org.thingsboard.server.common.data.lwm2m.LwM2mConstants.LWM2M_SEPARATOR_PATH;
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LWM2M_OBJECT_VERSION_DEFAULT;
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.convertObjectIdToVersionedId;
@ -241,36 +243,73 @@ public class LwM2mClient implements Serializable {
.getObjectModel(pathIds.getObjectId()) : null;
}
public String objectToString(LwM2mObject lwM2mObject) {
public Optional<String> contentToString(Object content) {
String value = null;
LwM2mResource resource = null;
String key = null;
if (content instanceof HashMap && ((HashMap) content).size() == 1) {
key = ((HashMap) content).keySet().toArray()[0].toString();
if (((HashMap) content).values().toArray()[0] != null) {
if (((HashMap) content).values().toArray()[0] instanceof LwM2mResource) {
resource = (LwM2mResource) ((HashMap) content).values().toArray()[0];
}
}
} else if (content instanceof LwM2mResource) {
resource = (LwM2mResource) content;
}
if (resource != null && resource.getType() == OPAQUE) {
value = this.resourceToString(resource, key);
}
value = value == null ? content.toString() : value;
return Optional.of(String.format("%s", value));
}
public String resourceToString(LwM2mResource resource, String key) {
String value = null;
StringBuilder builder = new StringBuilder();
builder.append("LwM2mObject [id=").append(lwM2mObject.getId()).append(", instances={");
lwM2mObject.getInstances().forEach((instId, inst) -> {
builder.append(instId).append("=").append(this.instanceToString(inst)).append(", ");
});
int startInd = builder.lastIndexOf(", ");
if (startInd > 0) {
builder.delete(startInd, startInd + 2);
if (resource instanceof LwM2mSingleResource) {
builder.append("LwM2mSingleResource");
if (key == null) {
builder.append(" id=").append(String.valueOf(resource.getId()));
} else {
builder.append(" key=").append(key);
}
builder.append(" value=").append(opaqueToString((byte[]) resource.getValue()));
builder.append(" type=").append(OPAQUE.toString());
value = builder.toString();
} else if (resource instanceof LwM2mMultipleResource) {
builder.append("LwM2mMultipleResource");
if (key == null) {
builder.append(" id=").append(String.valueOf(resource.getId()));
} else {
builder.append(" key=").append(key);
}
builder.append(" values={");
if (resource.getInstances().size() > 0) {
builder.append(multiInstanceOpaqueToString((LwM2mMultipleResource) resource));
}
builder.append("}");
builder.append(" type=").append(OPAQUE.toString());
value = builder.toString();
}
builder.append("}]");
return builder.toString();
return value;
}
public String instanceToString(LwM2mObjectInstance objectInstance) {
private String multiInstanceOpaqueToString(LwM2mMultipleResource resource) {
StringBuilder builder = new StringBuilder();
builder.append("LwM2mObjectInstance [id=").append(objectInstance.getId()).append(", resources={");
objectInstance.getResources().forEach((resId, res) -> {
builder.append(resId).append("=").append(this.resourceToString(res)).append(", ");
resource.getInstances().values().stream().map(v -> {
return builder.append(" id=").append(v.getId()).append(" value=").append(Hex.encodeHexString((byte[]) v.getValue())).append(", ");
});
int startInd = builder.lastIndexOf(", ");
if (startInd > 0) {
builder.delete(startInd, startInd + 2);
}
builder.append("}]");
return builder.toString();
}
public String resourceToString(LwM2mResource lwM2mResource) {
return lwM2mResource.isMultiInstances() ? lwM2mResource.getInstances().toString() : lwM2mResource.getValue().toString();
private String opaqueToString(byte[] value) {
String opaque = Hex.encodeHexString(value);
return opaque.length() > 1024 ? opaque.substring(0, 1024) : opaque;
}
public Collection<LwM2mResource> getNewResourceForInstance(String pathRezIdVer, Object params, LwM2mModelProvider modelProvider,
@ -368,5 +407,9 @@ public class LwM2mClient implements Serializable {
this.lock = new ReentrantLock();
}
public boolean isComposite (LwM2mClientContext clientContext) {
return LwM2mVersion.fromVersionStr(registration.getLwM2mVersion()).isComposite() &
clientContext.getProfile(this.profileId).getClientLwM2mSettings().isCompositeOperationsSupport();
}
}

12
common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/ResourceValue.java

@ -21,6 +21,7 @@ import org.eclipse.leshan.core.node.LwM2mResource;
import org.eclipse.leshan.core.node.LwM2mResourceInstance;
import java.io.Serializable;
import java.util.stream.Collectors;
@Data
public class ResourceValue implements Serializable {
@ -45,9 +46,14 @@ public class ResourceValue implements Serializable {
private static TbLwM2MResource toTbLwM2MResource(LwM2mResource lwM2mResource) {
if (lwM2mResource.isMultiInstances()) {
TbLwM2MResourceInstance[] instances = (TbLwM2MResourceInstance[]) lwM2mResource.getInstances().values().stream().map(ResourceValue::toTbLwM2MResourceInstance).toArray();
return new TbLwM2MMultipleResource(lwM2mResource.getId(), lwM2mResource.getType(), instances);
} else {
if ( lwM2mResource.getInstances().values().size() > 0) {
TbLwM2MResourceInstance [] instances = lwM2mResource.getInstances().values().stream().map(ResourceValue::toTbLwM2MResourceInstance).collect(Collectors.toSet()).toArray(new TbLwM2MResourceInstance[0]);
return new TbLwM2MMultipleResource(lwM2mResource.getId(), lwM2mResource.getType(), instances);
}
else {
return new TbLwM2MMultipleResource(lwM2mResource.getId(), lwM2mResource.getType(), new TbLwM2MResourceInstance[0]);
}
} else {
return new TbLwM2MSingleResource(lwM2mResource.getId(), lwM2mResource.getValue(), lwM2mResource.getType());
}
}

35
common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/DefaultLwM2mDownlinkMsgHandler.java

@ -61,9 +61,8 @@ import org.thingsboard.server.transport.lwm2m.server.LwM2mTransportContext;
import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient;
import org.thingsboard.server.transport.lwm2m.server.common.LwM2MExecutorAwareService;
import org.thingsboard.server.transport.lwm2m.server.downlink.composite.TbLwM2MReadCompositeRequest;
import org.thingsboard.server.transport.lwm2m.server.downlink.composite.TbLwM2MWriteResponseCompositeCallback;
import org.thingsboard.server.transport.lwm2m.server.log.LwM2MTelemetryLogService;
import org.thingsboard.server.transport.lwm2m.server.uplink.DefaultLwM2MUplinkMsgHandler;
import org.thingsboard.server.transport.lwm2m.server.rpc.composite.RpcWriteCompositeRequest;
import org.thingsboard.server.transport.lwm2m.utils.LwM2mValueConverterImpl;
import javax.annotation.PostConstruct;
@ -73,7 +72,6 @@ import java.util.Collection;
import java.util.Date;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.Function;
import java.util.function.Predicate;
@ -136,19 +134,6 @@ public class DefaultLwM2mDownlinkMsgHandler extends LwM2MExecutorAwareService im
sendCompositeRequest(client, downlink, this.config.getTimeout(), callback);
}
@Override
public void sendWriteCompositeRequest(LwM2mClient client, Map<String, Object> nodes, DefaultLwM2MUplinkMsgHandler handler) {
// ResourceModel resourceModelWrite = client.getResourceModel(request.getVersionedId(), this.config.getModelProvider());
TbLwM2MWriteResponseCompositeCallback callback = new TbLwM2MWriteResponseCompositeCallback(handler, logService, client, null);
ContentFormat contentFormat = ContentFormat.SENML_JSON;
try {
WriteCompositeRequest downlink = new WriteCompositeRequest(contentFormat, nodes);
sendWriteCompositeRequest(client, downlink, this.config.getTimeout(), callback);
} catch (Exception e) {
callback.onError(JacksonUtil.toString(nodes), e);
}
}
@Override
public void sendObserveRequest(LwM2mClient client, TbLwM2MObserveRequest request, DownlinkRequestCallback<ObserveRequest, ObserveResponse> callback) {
validateVersionedId(client, request);
@ -258,6 +243,17 @@ public class DefaultLwM2mDownlinkMsgHandler extends LwM2MExecutorAwareService im
}
}
@Override
public void sendWriteCompositeRequest(LwM2mClient client, RpcWriteCompositeRequest rpcWriteCompositeRequest, DownlinkRequestCallback<WriteCompositeRequest, WriteCompositeResponse> callback) {
ContentFormat contentFormat = ContentFormat.SENML_JSON;
try {
WriteCompositeRequest downlink = new WriteCompositeRequest(contentFormat, rpcWriteCompositeRequest.getNodes());
sendWriteCompositeRequest(client, downlink, this.config.getTimeout(), callback);
} catch (Exception e) {
callback.onError(JacksonUtil.toString(rpcWriteCompositeRequest), e);
}
}
@Override
public void sendWriteUpdateRequest(LwM2mClient client, TbLwM2MWriteUpdateRequest request, DownlinkRequestCallback<WriteRequest, WriteResponse> callback) {
LwM2mPath resultIds = new LwM2mPath(request.getObjectId());
@ -330,7 +326,12 @@ public class DefaultLwM2mDownlinkMsgHandler extends LwM2MExecutorAwareService im
context.getServer().send(registration, request, timeoutInMs, response -> {
executor.submit(() -> {
try {
callback.onSuccess(request, response);
if (response.isSuccess()) {
callback.onSuccess(request, response);
}
else {
callback.onValidationError(request.getNodes().values().toString(), response.getErrorMessage());
}
} catch (Exception e) {
log.error("[{}] failed to process successful response [{}] ", registration.getEndpoint(), response, e);
}

7
common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/LwM2mDownlinkMsgHandler.java

@ -23,6 +23,7 @@ import org.eclipse.leshan.core.request.ObserveRequest;
import org.eclipse.leshan.core.request.ReadCompositeRequest;
import org.eclipse.leshan.core.request.ReadRequest;
import org.eclipse.leshan.core.request.WriteAttributesRequest;
import org.eclipse.leshan.core.request.WriteCompositeRequest;
import org.eclipse.leshan.core.request.WriteRequest;
import org.eclipse.leshan.core.response.DeleteResponse;
import org.eclipse.leshan.core.response.DiscoverResponse;
@ -31,13 +32,13 @@ import org.eclipse.leshan.core.response.ObserveResponse;
import org.eclipse.leshan.core.response.ReadCompositeResponse;
import org.eclipse.leshan.core.response.ReadResponse;
import org.eclipse.leshan.core.response.WriteAttributesResponse;
import org.eclipse.leshan.core.response.WriteCompositeResponse;
import org.eclipse.leshan.core.response.WriteResponse;
import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient;
import org.thingsboard.server.transport.lwm2m.server.downlink.composite.TbLwM2MReadCompositeRequest;
import org.thingsboard.server.transport.lwm2m.server.uplink.DefaultLwM2MUplinkMsgHandler;
import org.thingsboard.server.transport.lwm2m.server.rpc.composite.RpcWriteCompositeRequest;
import java.util.List;
import java.util.Map;
import java.util.Set;
public interface LwM2mDownlinkMsgHandler {
@ -66,7 +67,7 @@ public interface LwM2mDownlinkMsgHandler {
void sendWriteReplaceRequest(LwM2mClient client, TbLwM2MWriteReplaceRequest request, DownlinkRequestCallback<WriteRequest, WriteResponse> callback);
void sendWriteCompositeRequest(LwM2mClient client, Map<String, Object> nodes, DefaultLwM2MUplinkMsgHandler handler);
void sendWriteCompositeRequest(LwM2mClient client, RpcWriteCompositeRequest nodes, DownlinkRequestCallback<WriteCompositeRequest, WriteCompositeResponse> callback);
void sendWriteUpdateRequest(LwM2mClient client, TbLwM2MWriteUpdateRequest request, DownlinkRequestCallback<WriteRequest, WriteResponse> callback);

49
common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/DefaultLwM2MRpcRequestHandler.java

@ -52,6 +52,7 @@ import org.thingsboard.server.transport.lwm2m.server.downlink.TbLwM2MWriteRespon
import org.thingsboard.server.transport.lwm2m.server.downlink.TbLwM2MWriteUpdateRequest;
import org.thingsboard.server.transport.lwm2m.server.downlink.composite.TbLwM2MReadCompositeCallback;
import org.thingsboard.server.transport.lwm2m.server.downlink.composite.TbLwM2MReadCompositeRequest;
import org.thingsboard.server.transport.lwm2m.server.downlink.composite.TbLwM2MWriteResponseCompositeCallback;
import org.thingsboard.server.transport.lwm2m.server.log.LwM2MTelemetryLogService;
import org.thingsboard.server.transport.lwm2m.server.rpc.composite.RpcReadCompositeRequest;
import org.thingsboard.server.transport.lwm2m.server.rpc.composite.RpcReadResponseCompositeCallback;
@ -97,7 +98,7 @@ public class DefaultLwM2MRpcRequestHandler implements LwM2MRpcRequestHandler {
return;
}
try {
if (operationType.isHasObjectId()) {
if (operationType.isHasObjectId()) {
String objectId = getIdFromParameters(client, rpcRequst);
switch (operationType) {
case READ:
@ -131,16 +132,23 @@ public class DefaultLwM2MRpcRequestHandler implements LwM2MRpcRequestHandler {
throw new IllegalArgumentException("Unsupported operation: " + operationType.name());
}
} else if (operationType.isComposite()) {
switch (operationType) {
case READ_COMPOSITE:
sendReadCompositeRequest(client, rpcRequst);
break;
case WRITE_COMPOSITE:
sendWriteCompositeRequest(client, rpcRequst);
break;
default:
throw new IllegalArgumentException("Unsupported operation: " + operationType.name());
}
if (client.isComposite(clientContext)) {
switch (operationType) {
case READ_COMPOSITE:
sendReadCompositeRequest(client, rpcRequst);
break;
case WRITE_COMPOSITE:
sendWriteCompositeRequest(client, rpcRequst);
break;
default:
throw new IllegalArgumentException("Unsupported operation: " + operationType.name());
}
}
else {
this.sendErrorRpcResponse(sessionInfo, rpcRequst.getRequestId(),
ResponseCode.INTERNAL_SERVER_ERROR.getName(), "This device does not support Composite Operation");
return;
}
} else {
switch (operationType) {
case OBSERVE_CANCEL_ALL:
@ -239,14 +247,19 @@ public class DefaultLwM2MRpcRequestHandler implements LwM2MRpcRequestHandler {
downlinkHandler.sendWriteReplaceRequest(client, request, rpcCallback);
}
/**
* WriteComposite {"nodes":{"/3/0/14":"+04", "/1/0/2":100, "/5/0/1":"coap://localhost:5685"}}
* {"result":"CHANGED"}
* Map<String, Object> nodes = new HashMap<>();
* nodes.put("/3/0/14", "+02");
* nodes.put("/1/0/2", 100);
* nodes.put("/5/0/1", "coap://localhost:5685");
*/
private void sendWriteCompositeRequest(LwM2mClient client, TransportProtos.ToDeviceRpcRequestMsg requestMsg) {
RpcWriteCompositeRequest nodes = JacksonUtil.fromString(requestMsg.getParams(), RpcWriteCompositeRequest.class);
// TbLwM2MWriteReplaceRequest request = TbLwM2MWriteReplaceRequest.builder().versionedId(versionedId)
// .value(requestBody.getValue())
// .timeout(this.config.getTimeout()).build();
// var mainCallback = new TbLwM2MWriteResponseCallback(uplinkHandler, logService, client, versionedId);
// var rpcCallback = new RpcEmptyResponseCallback<>(transportService, client, requestMsg, mainCallback);
// downlinkHandler.sendWriteReplaceRequest(client, request, rpcCallback);
RpcWriteCompositeRequest rpcWriteCompositeRequest = JacksonUtil.fromString(requestMsg.getParams(), RpcWriteCompositeRequest.class);
var mainCallback = new TbLwM2MWriteResponseCompositeCallback(uplinkHandler, logService, client, null);
var rpcCallback = new RpcEmptyResponseCallback<>(transportService, client, requestMsg, mainCallback);
downlinkHandler.sendWriteCompositeRequest(client, rpcWriteCompositeRequest, rpcCallback);
}
private void sendCancelObserveRequest(LwM2mClient client, TransportProtos.ToDeviceRpcRequestMsg requestMsg, String versionedId) {

13
common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/RpcReadResponseCallback.java

@ -15,9 +15,6 @@
*/
package org.thingsboard.server.transport.lwm2m.server.rpc;
import org.eclipse.leshan.core.node.LwM2mObject;
import org.eclipse.leshan.core.node.LwM2mObjectInstance;
import org.eclipse.leshan.core.node.LwM2mResource;
import org.eclipse.leshan.core.request.LwM2mRequest;
import org.eclipse.leshan.core.response.ReadResponse;
import org.thingsboard.server.common.transport.TransportService;
@ -35,14 +32,6 @@ public class RpcReadResponseCallback<R extends LwM2mRequest<T>, T extends ReadRe
@Override
protected Optional<String> serializeSuccessfulResponse(T response) {
Object value = null;
if (response.getContent() instanceof LwM2mObject) {
value = client.objectToString((LwM2mObject) response.getContent());
} else if (response.getContent() instanceof LwM2mObjectInstance) {
value = client.instanceToString((LwM2mObjectInstance) response.getContent());
} else if (response.getContent() instanceof LwM2mResource) {
value = client.resourceToString((LwM2mResource) response.getContent());
}
return Optional.of(String.format("%s", value));
return client.contentToString (response.getContent());
}
}

3
common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/composite/RpcReadResponseCompositeCallback.java

@ -16,7 +16,6 @@
package org.thingsboard.server.transport.lwm2m.server.rpc.composite;
import org.eclipse.leshan.core.request.LwM2mRequest;
import org.eclipse.leshan.core.request.ReadCompositeRequest;
import org.eclipse.leshan.core.response.ReadCompositeResponse;
import org.thingsboard.server.common.transport.TransportService;
import org.thingsboard.server.gen.transport.TransportProtos;
@ -34,6 +33,6 @@ public class RpcReadResponseCompositeCallback<R extends LwM2mRequest<T>, T exten
@Override
protected Optional<String> serializeSuccessfulResponse(T response) {
return Optional.of(String.format("%s", response.getContent().toString()));
return client.contentToString (response.getContent());
}
}

Loading…
Cancel
Save