Browse Source

Implementation of LwM2M RPC commands

pull/4738/head
Andrii Shvaika 5 years ago
parent
commit
f862034f79
  1. 53
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mOperationType.java
  2. 25
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClient.java
  3. 6
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mFwSwUpdate.java
  4. 83
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/DefaultLwM2mDownlinkMsgHandler.java
  5. 4
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/LwM2mDownlinkMsgHandler.java
  6. 4
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MWriteResponseCallback.java
  7. 200
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/DefaultLwM2MRpcRequestHandler.java
  8. 32
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/LwM2MRpcResponseBody.java
  9. 41
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/RpcCancelObserveCallback.java
  10. 43
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/RpcDiscoverCallback.java
  11. 86
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/RpcDownlinkRequestCallbackProxy.java
  12. 38
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/RpcEmptyResponseCallback.java
  13. 41
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/RpcLinkSetCallback.java
  14. 50
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/RpcLwM2MDownlinkCallback.java
  15. 50
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/RpcReadResponseCallback.java
  16. 28
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/RpcWriteAttributesRequest.java
  17. 27
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/RpcWriteReplaceRequest.java
  18. 29
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/RpcWriteUpdateRequest.java
  19. 29
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/uplink/DefaultLwM2MUplinkMsgHandler.java

53
common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mOperationType.java

@ -15,56 +15,57 @@
*/
package org.thingsboard.server.transport.lwm2m.server;
import lombok.Getter;
/**
* Define the behavior of a write request.
*/
public enum LwM2mOperationType {
/**
* GET
*/
READ(0, "Read"),
DISCOVER(1, "Discover"),
DISCOVER_ALL(2, "DiscoverAll"),
OBSERVE_READ_ALL(3, "ObserveReadAll"),
/**
* POST
*/
OBSERVE(4, "Observe"),
OBSERVE_CANCEL(5, "ObserveCancel"),
OBSERVE_CANCEL_ALL(6, "ObserveCancelAll"),
EXECUTE(7, "Execute"),
READ(0, "Read", true),
DISCOVER(1, "Discover", true),
DISCOVER_ALL(2, "DiscoverAll", false),
OBSERVE_READ_ALL(3, "ObserveReadAll", false),
OBSERVE(4, "Observe", true),
OBSERVE_CANCEL(5, "ObserveCancel", true),
OBSERVE_CANCEL_ALL(6, "ObserveCancelAll", false),
EXECUTE(7, "Execute", true),
/**
* Replaces the Object Instance or the Resource(s) with the new value provided in the Write operation. (see
* section 5.3.3 of the LW M2M spec).
* if all resources are to be replaced
*/
WRITE_REPLACE(8, "WriteReplace"),
/*
PUT
*/
WRITE_REPLACE(8, "WriteReplace", true),
/**
* Adds or updates Resources provided in the new value and leaves other existing Resources unchanged. (see section
* 5.3.3 of the LW M2M spec).
* if this is a partial update request
*/
WRITE_UPDATE(9, "WriteUpdate"),
WRITE_ATTRIBUTES(10, "WriteAttributes"),
DELETE(11, "Delete"),
WRITE_UPDATE(9, "WriteUpdate", true),
WRITE_ATTRIBUTES(10, "WriteAttributes", true),
DELETE(11, "Delete", true),
// only for RPC
FW_UPDATE(12, "FirmwareUpdate");
// FW_READ_INFO(12, "FirmwareReadInfo"),
FW_UPDATE(12, "FirmwareUpdate", false);
// FW_READ_INFO(12, "FirmwareReadInfo"),
// SW_READ_INFO(15, "SoftwareReadInfo"),
// SW_UPDATE(16, "SoftwareUpdate"),
// SW_UNINSTALL(18, "SoftwareUninstall");
public int code;
public String type;
@Getter
private final int code;
@Getter
private final String type;
@Getter
private final boolean hasObjectId;
LwM2mOperationType(int code, String type) {
LwM2mOperationType(int code, String type, boolean hasObjectId) {
this.code = code;
this.type = type;
this.hasObjectId = hasObjectId;
}
public static LwM2mOperationType fromType(String type) {

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

@ -26,6 +26,7 @@ import org.eclipse.leshan.core.node.LwM2mObjectInstance;
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.server.model.LwM2mModelProvider;
import org.eclipse.leshan.server.registration.Registration;
@ -40,7 +41,6 @@ import org.thingsboard.server.gen.transport.TransportProtos.TsKvProto;
import org.thingsboard.server.transport.lwm2m.server.uplink.DefaultLwM2MUplinkMsgHandler;
import org.thingsboard.server.transport.lwm2m.server.LwM2mQueuedRequest;
import org.thingsboard.server.transport.lwm2m.server.uplink.LwM2mUplinkMsgHandler;
import org.thingsboard.server.transport.lwm2m.utils.LwM2mValueConverterImpl;
import java.util.Collection;
import java.util.List;
@ -257,7 +257,7 @@ public class LwM2mClient implements Cloneable {
.getObjectModel(pathIds.getObjectId()) : null;
}
public String objectToString(LwM2mObject lwM2mObject, LwM2mValueConverterImpl converter, String pathIdVer) {
public String objectToString(LwM2mObject lwM2mObject, LwM2mValueConverter converter, String pathIdVer) {
StringBuilder builder = new StringBuilder();
builder.append("LwM2mObject [id=").append(lwM2mObject.getId()).append(", instances={");
lwM2mObject.getInstances().forEach((instId, inst) -> {
@ -271,7 +271,7 @@ public class LwM2mClient implements Cloneable {
return builder.toString();
}
public String instanceToString(LwM2mObjectInstance objectInstance, LwM2mValueConverterImpl converter, String pathIdVer) {
public String instanceToString(LwM2mObjectInstance objectInstance, LwM2mValueConverter converter, String pathIdVer) {
StringBuilder builder = new StringBuilder();
builder.append("LwM2mObjectInstance [id=").append(objectInstance.getId()).append(", resources={");
objectInstance.getResources().forEach((resId, res) -> {
@ -285,19 +285,12 @@ public class LwM2mClient implements Cloneable {
return builder.toString();
}
public String resourceToString(LwM2mResource lwM2mResource, LwM2mValueConverterImpl converter, String pathIdVer) {
if (!OPAQUE.equals(lwM2mResource.getType())) {
return lwM2mResource.isMultiInstances() ? ((LwM2mMultipleResource) lwM2mResource).toString() :
((LwM2mSingleResource) lwM2mResource).toString();
} else {
return String.format("LwM2mSingleResource [id=%s, value=%s, type=%s]", lwM2mResource.getId(),
converter.convertValue(lwM2mResource.getValue(),
OPAQUE, STRING, new LwM2mPath(fromVersionedIdToObjectId(pathIdVer))), lwM2mResource.getType().name());
}
public String resourceToString(LwM2mResource lwM2mResource, LwM2mValueConverter converter, String pathIdVer) {
return lwM2mResource.getValue().toString();
}
public Collection<LwM2mResource> getNewResourceForInstance(String pathRezIdVer, Object params, LwM2mModelProvider modelProvider,
LwM2mValueConverterImpl converter) {
LwM2mValueConverter converter) {
LwM2mPath pathIds = new LwM2mPath(fromVersionedIdToObjectId(pathRezIdVer));
Collection<LwM2mResource> resources = ConcurrentHashMap.newKeySet();
Map<Integer, ResourceModel> resourceModels = modelProvider.getObjectModel(registration)
@ -313,7 +306,7 @@ public class LwM2mClient implements Cloneable {
}
public Collection<LwM2mResource> getNewResourcesForInstance(String pathRezIdVer, Object params, LwM2mModelProvider modelProvider,
LwM2mValueConverterImpl converter) {
LwM2mValueConverter converter) {
LwM2mPath pathIds = new LwM2mPath(fromVersionedIdToObjectId(pathRezIdVer));
Collection<LwM2mResource> resources = ConcurrentHashMap.newKeySet();
Map<Integer, ResourceModel> resourceModels = modelProvider.getObjectModel(registration)
@ -395,7 +388,7 @@ public class LwM2mClient implements Cloneable {
}
}
public LwM2mFwSwUpdate getFwUpdate(LwM2mUplinkMsgHandler handler, LwM2mClientContext clientContext) {
public LwM2mFwSwUpdate getFwUpdate(LwM2mUplinkMsgHandler handler, LwM2mClientContext clientContext) {
if (this.fwUpdate == null) {
var profile = clientContext.getProfile(this.getProfileId());
this.fwUpdate = new LwM2mFwSwUpdate(handler, this, OtaPackageType.FIRMWARE, profile.getClientLwM2mSettings().getFwUpdateStrategy());
@ -403,7 +396,7 @@ public class LwM2mClient implements Cloneable {
return this.fwUpdate;
}
public LwM2mFwSwUpdate getSwUpdate (LwM2mUplinkMsgHandler handler,LwM2mClientContext clientContext) {
public LwM2mFwSwUpdate getSwUpdate(LwM2mUplinkMsgHandler handler, LwM2mClientContext clientContext) {
if (this.swUpdate == null) {
var profile = clientContext.getProfile(this.getProfileId());
this.swUpdate = new LwM2mFwSwUpdate(handler, this, OtaPackageType.SOFTWARE, profile.getClientLwM2mSettings().getSwUpdateStrategy());

6
common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mFwSwUpdate.java

@ -33,7 +33,7 @@ import org.thingsboard.server.transport.lwm2m.server.downlink.TbLwM2MExecuteRequ
import org.thingsboard.server.transport.lwm2m.server.downlink.TbLwM2MExecuteCallback;
import org.thingsboard.server.transport.lwm2m.server.downlink.TbLwM2MObserveRequest;
import org.thingsboard.server.transport.lwm2m.server.downlink.TbLwM2MObserveCallback;
import org.thingsboard.server.transport.lwm2m.server.downlink.TbLwM2MWriteReplaceCallback;
import org.thingsboard.server.transport.lwm2m.server.downlink.TbLwM2MWriteResponseCallback;
import org.thingsboard.server.transport.lwm2m.server.downlink.TbLwM2MWriteReplaceRequest;
import java.util.ArrayList;
@ -201,14 +201,14 @@ public class LwM2mFwSwUpdate {
byte[] firmwareChunk = handler.otaPackageDataCache.get(this.currentId.toString(), chunkSize, chunk);
TbLwM2MWriteReplaceRequest downlink = TbLwM2MWriteReplaceRequest.builder().versionedId(targetIdVer).value(firmwareChunk).timeout(handler.config.getTimeout()).build();
request.sendWriteReplaceRequest(lwM2MClient, downlink, new TbLwM2MWriteReplaceCallback(handler, lwM2MClient, targetIdVer));
request.sendWriteReplaceRequest(lwM2MClient, downlink, new TbLwM2MWriteResponseCallback(handler, lwM2MClient, targetIdVer));
} else if (LwM2mTransportUtil.LwM2MFirmwareUpdateStrategy.OBJ_5_TEMP_URL.code == this.updateStrategy) {
String apiFont = "coap://176.36.143.9:5685";
String uri = apiFont + "/" + FIRMWARE_UPDATE_COAP_RECOURSE + "/" + this.currentId.toString();
log.warn("89) coapUri: [{}]", uri);
//TODO: user this.rpcRequest???
TbLwM2MWriteReplaceRequest downlink = TbLwM2MWriteReplaceRequest.builder().versionedId(targetIdVer).value(uri).timeout(handler.config.getTimeout()).build();
request.sendWriteReplaceRequest(lwM2MClient, downlink, new TbLwM2MWriteReplaceCallback(handler, lwM2MClient, targetIdVer));
request.sendWriteReplaceRequest(lwM2MClient, downlink, new TbLwM2MWriteResponseCallback(handler, lwM2MClient, targetIdVer));
} else if (LwM2mTransportUtil.LwM2MFirmwareUpdateStrategy.OBJ_19_BINARY.code == this.updateStrategy) {
}

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

@ -47,6 +47,7 @@ import org.eclipse.leshan.core.util.Hex;
import org.eclipse.leshan.core.util.NamedThreadFactory;
import org.eclipse.leshan.server.registration.Registration;
import org.springframework.stereotype.Service;
import org.thingsboard.common.util.JacksonUtil;
import org.thingsboard.server.common.data.device.data.lwm2m.ObjectAttributes;
import org.thingsboard.server.queue.util.TbLwM2mTransportComponent;
import org.thingsboard.server.transport.lwm2m.config.LwM2MTransportServerConfig;
@ -98,30 +99,30 @@ public class DefaultLwM2mDownlinkMsgHandler implements LwM2mDownlinkMsgHandler {
@Override
public void sendReadRequest(LwM2mClient client, TbLwM2MReadRequest request, DownlinkRequestCallback<ReadResponse> callback) {
if (request.getObjectId() != null && client.isValidObjectVersion(request.getVersionedId())) {
ReadRequest downlink = new ReadRequest(getContentFormat(client, request), request.getObjectId());
sendRequest(client, downlink, request.getTimeout(), callback);
}
validateVersionedId(client, request);
ReadRequest downlink = new ReadRequest(getContentFormat(client, request), request.getObjectId());
sendRequest(client, downlink, request.getTimeout(), callback);
}
@Override
public void sendObserveRequest(LwM2mClient client, TbLwM2MObserveRequest request, DownlinkRequestCallback<ObserveResponse> callback) {
if (request.getObjectId() != null && client.isValidObjectVersion(request.getVersionedId())) {
LwM2mPath resultIds = new LwM2mPath(request.getObjectId());
Set<Observation> observations = context.getServer().getObservationService().getObservations(client.getRegistration());
if (observations.stream().noneMatch(observation -> observation.getPath().equals(resultIds))) {
ObserveRequest downlink;
ContentFormat contentFormat = getContentFormat(client, request);
if (resultIds.isResource()) {
downlink = new ObserveRequest(contentFormat, resultIds.getObjectId(), resultIds.getObjectInstanceId(), resultIds.getResourceId());
} else if (resultIds.isObjectInstance()) {
downlink = new ObserveRequest(contentFormat, resultIds.getObjectId(), resultIds.getObjectInstanceId());
} else {
downlink = new ObserveRequest(contentFormat, resultIds.getObjectId());
}
log.info("[{}] Send observation: {}.", client.getEndpoint(), request.getVersionedId());
sendRequest(client, downlink, request.getTimeout(), callback);
validateVersionedId(client, request);
LwM2mPath resultIds = new LwM2mPath(request.getObjectId());
Set<Observation> observations = context.getServer().getObservationService().getObservations(client.getRegistration());
if (observations.stream().noneMatch(observation -> observation.getPath().equals(resultIds))) {
ObserveRequest downlink;
ContentFormat contentFormat = getContentFormat(client, request);
if (resultIds.isResource()) {
downlink = new ObserveRequest(contentFormat, resultIds.getObjectId(), resultIds.getObjectInstanceId(), resultIds.getResourceId());
} else if (resultIds.isObjectInstance()) {
downlink = new ObserveRequest(contentFormat, resultIds.getObjectId(), resultIds.getObjectInstanceId());
} else {
downlink = new ObserveRequest(contentFormat, resultIds.getObjectId());
}
log.info("[{}] Send observation: {}.", client.getEndpoint(), request.getVersionedId());
sendRequest(client, downlink, request.getTimeout(), callback);
} else {
throw new IllegalArgumentException("Observation is already registered!");
}
}
@ -133,10 +134,8 @@ public class DefaultLwM2mDownlinkMsgHandler implements LwM2mDownlinkMsgHandler {
}
@Override
public void sendDiscoverAllRequest(LwM2mClient client, TbLwM2MDiscoverAllRequest request, DownlinkRequestCallback<Set<String>> callback) {
Link[] objectLinks = client.getRegistration().getSortedObjectLinks();
Set<String> paths = Arrays.stream(objectLinks).map(Link::toString).collect(Collectors.toUnmodifiableSet());
callback.onSuccess(paths);
public void sendDiscoverAllRequest(LwM2mClient client, TbLwM2MDiscoverAllRequest request, DownlinkRequestCallback<List<Link>> callback) {
callback.onSuccess(Arrays.asList(client.getRegistration().getSortedObjectLinks()));
}
@Override
@ -172,27 +171,28 @@ public class DefaultLwM2mDownlinkMsgHandler implements LwM2mDownlinkMsgHandler {
@Override
public void sendDiscoverRequest(LwM2mClient client, TbLwM2MDiscoverRequest request, DownlinkRequestCallback<DiscoverResponse> callback) {
if (request.getObjectId() != null && client.isValidObjectVersion(request.getVersionedId())) {
sendRequest(client, new DiscoverRequest(request.getObjectId()), request.getTimeout(), callback);
}
validateVersionedId(client, request);
sendRequest(client, new DiscoverRequest(request.getObjectId()), request.getTimeout(), callback);
}
@Override
public void sendWriteAttributesRequest(LwM2mClient client, TbLwM2MWriteAttributesRequest request, DownlinkRequestCallback<WriteAttributesResponse> callback) {
if (request.getObjectId() != null && client.isValidObjectVersion(request.getVersionedId()) && request.getAttributes() != null) {
ObjectAttributes params = request.getAttributes();
List<Attribute> attributes = new LinkedList<>();
validateVersionedId(client, request);
if (request.getAttributes() == null) {
throw new IllegalArgumentException("Attributes to write are not specified!");
}
ObjectAttributes params = request.getAttributes();
List<Attribute> attributes = new LinkedList<>();
// Dimension and Object version are read only attributes.
// addAttribute(attributes, DIMENSION, params.getDim(), dim -> dim >= 0 && dim <= 255);
// addAttribute(attributes, OBJECT_VERSION, params.getVer(), StringUtils::isNotEmpty, Function.identity());
addAttribute(attributes, MAXIMUM_PERIOD, params.getPmax());
addAttribute(attributes, MINIMUM_PERIOD, params.getPmin());
addAttribute(attributes, GREATER_THAN, params.getGt());
addAttribute(attributes, LESSER_THAN, params.getLt());
addAttribute(attributes, STEP, params.getSt());
AttributeSet attributeSet = new AttributeSet(attributes);
sendRequest(client, new WriteAttributesRequest(request.getObjectId(), attributeSet), request.getTimeout(), callback);
}
addAttribute(attributes, MAXIMUM_PERIOD, params.getPmax());
addAttribute(attributes, MINIMUM_PERIOD, params.getPmin());
addAttribute(attributes, GREATER_THAN, params.getGt());
addAttribute(attributes, LESSER_THAN, params.getLt());
addAttribute(attributes, STEP, params.getSt());
AttributeSet attributeSet = new AttributeSet(attributes);
sendRequest(client, new WriteAttributesRequest(request.getObjectId(), attributeSet), request.getTimeout(), callback);
}
@Override
@ -642,7 +642,14 @@ public class DefaultLwM2mDownlinkMsgHandler implements LwM2mDownlinkMsgHandler {
// handler.sentRpcResponse(rpcRequest, CONTENT.name(), null, LOG_LW2M_INFO);
// }
// }
private void validateVersionedId(LwM2mClient client, HasVersionedId request) {
if (!client.isValidObjectVersion(request.getVersionedId())) {
throw new IllegalArgumentException("Specified resource id is not configured in the device profile!");
}
if (request.getObjectId() == null) {
throw new IllegalArgumentException("Specified object id is null!");
}
}
private static <T> void addAttribute(List<Attribute> attributes, String attributeName, T value) {
addAttribute(attributes, attributeName, value, null, null);

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

@ -15,6 +15,7 @@
*/
package org.thingsboard.server.transport.lwm2m.server.downlink;
import org.eclipse.leshan.core.Link;
import org.eclipse.leshan.core.response.DeleteResponse;
import org.eclipse.leshan.core.response.DiscoverResponse;
import org.eclipse.leshan.core.response.ExecuteResponse;
@ -24,6 +25,7 @@ import org.eclipse.leshan.core.response.WriteAttributesResponse;
import org.eclipse.leshan.core.response.WriteResponse;
import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient;
import java.util.List;
import java.util.Set;
public interface LwM2mDownlinkMsgHandler {
@ -44,7 +46,7 @@ public interface LwM2mDownlinkMsgHandler {
void sendDiscoverRequest(LwM2mClient client, TbLwM2MDiscoverRequest request, DownlinkRequestCallback<DiscoverResponse> callback);
void sendDiscoverAllRequest(LwM2mClient client, TbLwM2MDiscoverAllRequest request, DownlinkRequestCallback<Set<String>> callback);
void sendDiscoverAllRequest(LwM2mClient client, TbLwM2MDiscoverAllRequest request, DownlinkRequestCallback<List<Link>> callback);
void sendWriteAttributesRequest(LwM2mClient client, TbLwM2MWriteAttributesRequest request, DownlinkRequestCallback<WriteAttributesResponse> callback);

4
common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MWriteReplaceCallback.java → common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/TbLwM2MWriteResponseCallback.java

@ -19,11 +19,11 @@ import org.eclipse.leshan.core.response.WriteResponse;
import org.thingsboard.server.transport.lwm2m.server.uplink.LwM2mUplinkMsgHandler;
import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient;
public class TbLwM2MWriteReplaceCallback extends AbstractTbLwM2MRequestCallback<WriteResponse> {
public class TbLwM2MWriteResponseCallback extends AbstractTbLwM2MRequestCallback<WriteResponse> {
private final String targetId;
public TbLwM2MWriteReplaceCallback(LwM2mUplinkMsgHandler handler, LwM2mClient client, String targetId) {
public TbLwM2MWriteResponseCallback(LwM2mUplinkMsgHandler handler, LwM2mClient client, String targetId) {
super(handler, client);
this.targetId = targetId;
}

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

@ -5,7 +5,7 @@
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
@ -29,8 +29,27 @@ import org.thingsboard.server.transport.lwm2m.server.LwM2mOperationType;
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.downlink.LwM2mDownlinkMsgHandler;
import org.thingsboard.server.transport.lwm2m.server.downlink.TbLwM2MCancelAllObserveCallback;
import org.thingsboard.server.transport.lwm2m.server.downlink.TbLwM2MCancelAllRequest;
import org.thingsboard.server.transport.lwm2m.server.downlink.TbLwM2MCancelObserveCallback;
import org.thingsboard.server.transport.lwm2m.server.downlink.TbLwM2MCancelObserveRequest;
import org.thingsboard.server.transport.lwm2m.server.downlink.TbLwM2MDeleteCallback;
import org.thingsboard.server.transport.lwm2m.server.downlink.TbLwM2MDeleteRequest;
import org.thingsboard.server.transport.lwm2m.server.downlink.TbLwM2MDiscoverAllRequest;
import org.thingsboard.server.transport.lwm2m.server.downlink.TbLwM2MDiscoverCallback;
import org.thingsboard.server.transport.lwm2m.server.downlink.TbLwM2MDiscoverRequest;
import org.thingsboard.server.transport.lwm2m.server.downlink.TbLwM2MExecuteCallback;
import org.thingsboard.server.transport.lwm2m.server.downlink.TbLwM2MExecuteRequest;
import org.thingsboard.server.transport.lwm2m.server.downlink.TbLwM2MObserveAllRequest;
import org.thingsboard.server.transport.lwm2m.server.downlink.TbLwM2MObserveCallback;
import org.thingsboard.server.transport.lwm2m.server.downlink.TbLwM2MObserveRequest;
import org.thingsboard.server.transport.lwm2m.server.downlink.TbLwM2MReadCallback;
import org.thingsboard.server.transport.lwm2m.server.downlink.TbLwM2MReadRequest;
import org.thingsboard.server.transport.lwm2m.server.downlink.TbLwM2MWriteAttributesCallback;
import org.thingsboard.server.transport.lwm2m.server.downlink.TbLwM2MWriteAttributesRequest;
import org.thingsboard.server.transport.lwm2m.server.downlink.TbLwM2MWriteReplaceRequest;
import org.thingsboard.server.transport.lwm2m.server.downlink.TbLwM2MWriteResponseCallback;
import org.thingsboard.server.transport.lwm2m.server.downlink.TbLwM2MWriteUpdateRequest;
import org.thingsboard.server.transport.lwm2m.server.uplink.LwM2mUplinkMsgHandler;
import java.util.Map;
@ -57,62 +76,167 @@ public class DefaultLwM2MRpcRequestHandler implements LwM2MRpcRequestHandler {
private final LwM2mDownlinkMsgHandler downlinkHandler;
private final Map<UUID, Long> rpcSubscriptions = new ConcurrentHashMap<>();
@Override
public void onToDeviceRpcRequest(TransportProtos.ToDeviceRpcRequestMsg rpcRequst, TransportProtos.SessionInfoProto sessionInfo) {
this.cleanupOldSessions();
UUID requestUUID = new UUID(rpcRequst.getRequestIdMSB(), rpcRequst.getRequestIdLSB());
log.warn("Received params: {}", rpcRequst.getParams());
// TODO: We use this map to protect from browser issue that the same command is sent twice. This is probably not the best place and should be moved to DeviceActor
// We use this map to protect from browser issue that the same command is sent twice.
// TODO: This is probably not the best place and should be moved to DeviceActor
if (!this.rpcSubscriptions.containsKey(requestUUID)) {
LwM2mOperationType operationType = LwM2mOperationType.fromType(rpcRequst.getMethodName());
if (operationType == null) {
this.sendErrorRpcResponse(sessionInfo, rpcRequst.getRequestId(), ResponseCode.METHOD_NOT_ALLOWED.getName(), "Unsupported operation type: " + rpcRequst.getMethodName());
return;
}
LwM2mClient client = clientContext.getClientBySessionInfo(sessionInfo);
if (client.getRegistration() == null) {
this.sendErrorRpcResponse(sessionInfo, rpcRequst.getRequestId(), ResponseCode.INTERNAL_SERVER_ERROR.getName(), "Registration is empty");
return;
}
switch (operationType) {
case READ:
sendReadRequest(client, rpcRequst);
break;
try {
if (operationType.isHasObjectId()) {
String objectId = getIdFromParameters(client, rpcRequst);
switch (operationType) {
case READ:
sendReadRequest(client, rpcRequst, objectId);
break;
case OBSERVE:
sendObserveRequest(client, rpcRequst, objectId);
break;
case DISCOVER:
sendDiscoverRequest(client, rpcRequst, objectId);
break;
case EXECUTE:
sendExecuteRequest(client, rpcRequst, objectId);
break;
case WRITE_ATTRIBUTES:
sendWriteAttributesRequest(client, rpcRequst, objectId);
break;
case OBSERVE_CANCEL:
sendCancelObserveRequest(client, rpcRequst, objectId);
break;
case DELETE:
sendDeleteRequest(client, rpcRequst, objectId);
break;
case WRITE_UPDATE:
sendWriteUpdateRequest(client, rpcRequst, objectId);
break;
case WRITE_REPLACE:
sendWriteReplaceRequest(client, rpcRequst, objectId);
break;
default:
throw new IllegalArgumentException("Unsupported operation: " + operationType.name());
}
} else {
switch (operationType) {
case OBSERVE_CANCEL_ALL:
sendCancelAllObserveRequest(client, rpcRequst);
break;
case OBSERVE_READ_ALL:
sendObserveAllRequest(client, rpcRequst);
break;
case DISCOVER_ALL:
sendDiscoverAllRequest(client, rpcRequst);
break;
case FW_UPDATE:
//TODO: implement and add break statement
default:
throw new IllegalArgumentException("Unsupported operation: " + operationType.name());
}
}
} catch (IllegalArgumentException e) {
this.sendErrorRpcResponse(sessionInfo, rpcRequst.getRequestId(), ResponseCode.BAD_REQUEST.getName(), e.getMessage());
}
}
}
private void sendReadRequest(LwM2mClient client, TransportProtos.ToDeviceRpcRequestMsg requestMsg, String versionedId) {
TbLwM2MReadRequest request = TbLwM2MReadRequest.builder().versionedId(versionedId).timeout(this.config.getTimeout()).build();
var mainCallback = new TbLwM2MReadCallback(uplinkHandler, client, versionedId);
var rpcCallback = new RpcReadResponseCallback<>(transportService, client, requestMsg, versionedId, mainCallback);
downlinkHandler.sendReadRequest(client, request, rpcCallback);
}
// log.warn("4) rpcRequst: [{}], sessionUUID: [{}]", rpcRequst, new UUID(sessionInfo.getSessionIdMSB(), sessionInfo.getSessionIdLSB()));
// String bodyParams = StringUtils.trimToNull(rpcRequst.getParams()) != null ? rpcRequst.getParams() : "null";
// LwM2mOperationType lwM2mTypeOper = setValidTypeOper(rpcRequst.getMethodName());
// this.rpcSubscriptions.put(requestUUID, rpcRequst.getExpirationTime());
// LwM2mClientRpcRequest lwm2mClientRpcRequest = null;
// try {
// LwM2mClient client = clientContext.getClientBySessionInfo(sessionInfo);
// Registration registration = client.getRegistration();
// if (registration != null) {
// lwm2mClientRpcRequest = new LwM2mClientRpcRequest(lwM2mTypeOper, bodyParams, rpcRequst.getRequestId(), sessionInfo, registration, uplinkHandler);
// if (lwm2mClientRpcRequest.getErrorMsg() != null) {
// lwm2mClientRpcRequest.setResponseCode(BAD_REQUEST.name());
// this.onToDeviceRpcResponse(lwm2mClientRpcRequest.getDeviceRpcResponseResultMsg(), sessionInfo);
// } else {
// //TODO: use different methods and RPC callback wrapper.
//// defaultLwM2MDownlinkMsgHandler.sendAllRequest(client, lwm2mClientRpcRequest.getTargetIdVer(), lwm2mClientRpcRequest.getTypeOper(),
//// null,
//// lwm2mClientRpcRequest.getValue() == null ? lwm2mClientRpcRequest.getParams() : lwm2mClientRpcRequest.getValue(),
//// this.config.getTimeout(), lwm2mClientRpcRequest);
// }
// } else {
// this.sendErrorRpcResponse(lwm2mClientRpcRequest, "registration == null", sessionInfo);
// }
// } catch (Exception e) {
// this.sendErrorRpcResponse(lwm2mClientRpcRequest, e.getMessage(), sessionInfo);
// }
}
private void sendObserveRequest(LwM2mClient client, TransportProtos.ToDeviceRpcRequestMsg requestMsg, String versionedId) {
TbLwM2MObserveRequest request = TbLwM2MObserveRequest.builder().versionedId(versionedId).timeout(this.config.getTimeout()).build();
var mainCallback = new TbLwM2MObserveCallback(uplinkHandler, client, versionedId);
var rpcCallback = new RpcReadResponseCallback<>(transportService, client, requestMsg, versionedId, mainCallback);
downlinkHandler.sendObserveRequest(client, request, rpcCallback);
}
private void sendObserveAllRequest(LwM2mClient client, TransportProtos.ToDeviceRpcRequestMsg requestMsg) {
TbLwM2MObserveAllRequest request = TbLwM2MObserveAllRequest.builder().timeout(this.config.getTimeout()).build();
downlinkHandler.sendObserveAllRequest(client, request, new RpcLinkSetCallback(transportService, client, requestMsg, null));
}
private void sendDiscoverAllRequest(LwM2mClient client, TransportProtos.ToDeviceRpcRequestMsg requestMsg) {
TbLwM2MDiscoverAllRequest request = TbLwM2MDiscoverAllRequest.builder().timeout(this.config.getTimeout()).build();
downlinkHandler.sendDiscoverAllRequest(client, request, new RpcLinkSetCallback(transportService, client, requestMsg, null));
}
private void sendDiscoverRequest(LwM2mClient client, TransportProtos.ToDeviceRpcRequestMsg requestMsg, String versionedId) {
TbLwM2MDiscoverRequest request = TbLwM2MDiscoverRequest.builder().versionedId(versionedId).timeout(this.config.getTimeout()).build();
var mainCallback = new TbLwM2MDiscoverCallback(uplinkHandler, client, versionedId);
var rpcCallback = new RpcDiscoverCallback(transportService, client, requestMsg, mainCallback);
downlinkHandler.sendDiscoverRequest(client, request, rpcCallback);
}
private void sendExecuteRequest(LwM2mClient client, TransportProtos.ToDeviceRpcRequestMsg requestMsg, String versionedId) {
TbLwM2MExecuteRequest downlink = TbLwM2MExecuteRequest.builder().versionedId(versionedId).timeout(this.config.getTimeout()).build();
var mainCallback = new TbLwM2MExecuteCallback(uplinkHandler, client, versionedId);
var rpcCallback = new RpcEmptyResponseCallback<>(transportService, client, requestMsg, mainCallback);
downlinkHandler.sendExecuteRequest(client, downlink, rpcCallback);
}
private void sendWriteAttributesRequest(LwM2mClient client, TransportProtos.ToDeviceRpcRequestMsg requestMsg, String versionedId) {
RpcWriteAttributesRequest requestBody = JacksonUtil.fromString(requestMsg.getParams(), RpcWriteAttributesRequest.class);
TbLwM2MWriteAttributesRequest request = TbLwM2MWriteAttributesRequest.builder().versionedId(versionedId)
.attributes(requestBody.getAttributes())
.timeout(this.config.getTimeout()).build();
var mainCallback = new TbLwM2MWriteAttributesCallback(uplinkHandler, client, versionedId);
var rpcCallback = new RpcEmptyResponseCallback<>(transportService, client, requestMsg, mainCallback);
downlinkHandler.sendWriteAttributesRequest(client, request, rpcCallback);
}
private void sendWriteUpdateRequest(LwM2mClient client, TransportProtos.ToDeviceRpcRequestMsg requestMsg, String versionedId) {
RpcWriteUpdateRequest requestBody = JacksonUtil.fromString(requestMsg.getParams(), RpcWriteUpdateRequest.class);
TbLwM2MWriteUpdateRequest.TbLwM2MWriteUpdateRequestBuilder builder = TbLwM2MWriteUpdateRequest.builder().versionedId(versionedId);
builder.value(requestBody.getValue()).timeout(this.config.getTimeout());
var mainCallback = new TbLwM2MWriteResponseCallback(uplinkHandler, client, versionedId);
var rpcCallback = new RpcEmptyResponseCallback<>(transportService, client, requestMsg, mainCallback);
downlinkHandler.sendWriteUpdateRequest(client, builder.build(), rpcCallback);
}
private void sendWriteReplaceRequest(LwM2mClient client, TransportProtos.ToDeviceRpcRequestMsg requestMsg, String versionedId) {
RpcWriteUpdateRequest requestBody = JacksonUtil.fromString(requestMsg.getParams(), RpcWriteUpdateRequest.class);
TbLwM2MWriteReplaceRequest request = TbLwM2MWriteReplaceRequest.builder().versionedId(versionedId)
.value(requestBody.getValue())
.timeout(this.config.getTimeout()).build();
var mainCallback = new TbLwM2MWriteResponseCallback(uplinkHandler, client, versionedId);
var rpcCallback = new RpcEmptyResponseCallback<>(transportService, client, requestMsg, mainCallback);
downlinkHandler.sendWriteReplaceRequest(client, request, rpcCallback);
}
private void sendCancelObserveRequest(LwM2mClient client, TransportProtos.ToDeviceRpcRequestMsg requestMsg, String versionedId) {
TbLwM2MCancelObserveRequest downlink = TbLwM2MCancelObserveRequest.builder().versionedId(versionedId).timeout(this.config.getTimeout()).build();
var mainCallback = new TbLwM2MCancelObserveCallback(uplinkHandler, client, versionedId);
var rpcCallback = new RpcCancelObserveCallback(transportService, client, requestMsg, mainCallback);
downlinkHandler.sendCancelObserveRequest(client, downlink, rpcCallback);
}
private void sendDeleteRequest(LwM2mClient client, TransportProtos.ToDeviceRpcRequestMsg requestMsg, String versionedId) {
TbLwM2MDeleteRequest downlink = TbLwM2MDeleteRequest.builder().versionedId(versionedId).timeout(this.config.getTimeout()).build();
var mainCallback = new TbLwM2MDeleteCallback(uplinkHandler, client, versionedId);
var rpcCallback = new RpcEmptyResponseCallback<>(transportService, client, requestMsg, mainCallback);
downlinkHandler.sendDeleteRequest(client, downlink, rpcCallback);
}
private void sendReadRequest(LwM2mClient client, TransportProtos.ToDeviceRpcRequestMsg rpcRequst) {
String id = getIdFromParameters(client, rpcRequst);
TbLwM2MReadRequest request = TbLwM2MReadRequest.builder().versionedId(id).timeout(this.config.getTimeout()).build();
downlinkHandler.sendReadRequest(client, request, new TbLwM2MReadCallback(uplinkHandler, client, id));
private void sendCancelAllObserveRequest(LwM2mClient client, TransportProtos.ToDeviceRpcRequestMsg requestMsg) {
TbLwM2MCancelAllRequest downlink = TbLwM2MCancelAllRequest.builder().timeout(this.config.getTimeout()).build();
var mainCallback = new TbLwM2MCancelAllObserveCallback(uplinkHandler, client);
var rpcCallback = new RpcCancelObserveCallback(transportService, client, requestMsg, mainCallback);
downlinkHandler.sendCancelAllRequest(client, downlink, rpcCallback);
}
private String getIdFromParameters(LwM2mClient client, TransportProtos.ToDeviceRpcRequestMsg rpcRequst) {

32
common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/LwM2MRpcResponseBody.java

@ -0,0 +1,32 @@
/**
* Copyright © 2016-2021 The Thingsboard Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.transport.lwm2m.server.rpc;
import com.fasterxml.jackson.annotation.JsonInclude;
import lombok.Builder;
import lombok.Data;
@Data
@Builder
@JsonInclude(JsonInclude.Include.NON_NULL)
public class LwM2MRpcResponseBody {
private String result;
private String value;
private String error;
private String info;
}

41
common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/RpcCancelObserveCallback.java

@ -0,0 +1,41 @@
/**
* Copyright © 2016-2021 The Thingsboard Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.transport.lwm2m.server.rpc;
import org.eclipse.leshan.core.ResponseCode;
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.response.ReadResponse;
import org.thingsboard.server.common.data.StringUtils;
import org.thingsboard.server.common.transport.TransportService;
import org.thingsboard.server.gen.transport.TransportProtos;
import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient;
import org.thingsboard.server.transport.lwm2m.server.downlink.DownlinkRequestCallback;
import java.util.Optional;
public class RpcCancelObserveCallback extends RpcDownlinkRequestCallbackProxy<Integer> {
public RpcCancelObserveCallback(TransportService transportService, LwM2mClient client, TransportProtos.ToDeviceRpcRequestMsg requestMsg, DownlinkRequestCallback<Integer> callback) {
super(transportService, client, requestMsg, callback);
}
@Override
protected void sendRpcReplyOnSuccess(Integer response) {
reply(LwM2MRpcResponseBody.builder().result(ResponseCode.CONTENT.getName()).value(response.toString()).build());
}
}

43
common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/RpcDiscoverCallback.java

@ -0,0 +1,43 @@
/**
* Copyright © 2016-2021 The Thingsboard Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.transport.lwm2m.server.rpc;
import org.eclipse.leshan.core.Link;
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.response.DiscoverResponse;
import org.eclipse.leshan.core.response.ReadResponse;
import org.jetbrains.annotations.NotNull;
import org.thingsboard.server.common.data.StringUtils;
import org.thingsboard.server.common.transport.TransportService;
import org.thingsboard.server.gen.transport.TransportProtos;
import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient;
import org.thingsboard.server.transport.lwm2m.server.downlink.DownlinkRequestCallback;
import java.util.Optional;
public class RpcDiscoverCallback extends RpcLwM2MDownlinkCallback<DiscoverResponse> {
public RpcDiscoverCallback(TransportService transportService, LwM2mClient client, TransportProtos.ToDeviceRpcRequestMsg requestMsg, DownlinkRequestCallback<DiscoverResponse> callback) {
super(transportService, client, requestMsg, callback);
}
protected Optional<String> serializeSuccessfulResponse(DiscoverResponse response) {
return Optional.of(Link.serialize(response.getObjectLinks()));
}
}

86
common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/RpcDownlinkRequestCallbackProxy.java

@ -0,0 +1,86 @@
/**
* Copyright © 2016-2021 The Thingsboard Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.transport.lwm2m.server.rpc;
import org.eclipse.leshan.core.ResponseCode;
import org.eclipse.leshan.core.node.codec.LwM2mValueConverter;
import org.thingsboard.common.util.JacksonUtil;
import org.thingsboard.server.common.transport.TransportService;
import org.thingsboard.server.gen.transport.TransportProtos;
import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient;
import org.thingsboard.server.transport.lwm2m.server.downlink.DownlinkRequestCallback;
import org.thingsboard.server.transport.lwm2m.utils.LwM2mValueConverterImpl;
public abstract class RpcDownlinkRequestCallbackProxy<T> implements DownlinkRequestCallback<T> {
private final TransportService transportService;
private final TransportProtos.ToDeviceRpcRequestMsg request;
private final DownlinkRequestCallback<T> callback;
protected final LwM2mClient client;
protected final LwM2mValueConverter converter;
public RpcDownlinkRequestCallbackProxy(TransportService transportService, LwM2mClient client, TransportProtos.ToDeviceRpcRequestMsg requestMsg, DownlinkRequestCallback<T> callback) {
this.transportService = transportService;
this.client = client;
this.request = requestMsg;
this.callback = callback;
this.converter = LwM2mValueConverterImpl.getInstance();
}
@Override
public void onSuccess(T response) {
sendRpcReplyOnSuccess(response);
if (callback != null) {
callback.onSuccess(response);
}
}
@Override
public void onValidationError(String msg) {
sendRpcReplyOnValidationError(msg);
if (callback != null) {
callback.onValidationError(msg);
}
}
@Override
public void onError(Exception e) {
sendRpcReplyOnError(e);
if (callback != null) {
callback.onError(e);
}
}
protected void reply(LwM2MRpcResponseBody response) {
TransportProtos.ToDeviceRpcResponseMsg msg = TransportProtos.ToDeviceRpcResponseMsg.newBuilder()
.setPayload(JacksonUtil.toString(response))
.setRequestId(request.getRequestId())
.build();
transportService.process(client.getSession(), msg, null);
}
abstract protected void sendRpcReplyOnSuccess(T response);
protected void sendRpcReplyOnValidationError(String msg) {
reply(LwM2MRpcResponseBody.builder().result(ResponseCode.BAD_REQUEST.getName()).error(msg).build());
}
protected void sendRpcReplyOnError(Exception e) {
reply(LwM2MRpcResponseBody.builder().result(ResponseCode.INTERNAL_SERVER_ERROR.getName()).error(e.getMessage()).build());
}
}

38
common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/RpcEmptyResponseCallback.java

@ -0,0 +1,38 @@
/**
* Copyright © 2016-2021 The Thingsboard Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.transport.lwm2m.server.rpc;
import org.eclipse.leshan.core.Link;
import org.eclipse.leshan.core.response.DiscoverResponse;
import org.eclipse.leshan.core.response.LwM2mResponse;
import org.thingsboard.server.common.transport.TransportService;
import org.thingsboard.server.gen.transport.TransportProtos;
import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient;
import org.thingsboard.server.transport.lwm2m.server.downlink.DownlinkRequestCallback;
import java.util.Optional;
public class RpcEmptyResponseCallback<T extends LwM2mResponse> extends RpcLwM2MDownlinkCallback<T> {
public RpcEmptyResponseCallback(TransportService transportService, LwM2mClient client, TransportProtos.ToDeviceRpcRequestMsg requestMsg, DownlinkRequestCallback<T> callback) {
super(transportService, client, requestMsg, callback);
}
protected Optional<String> serializeSuccessfulResponse(T response) {
return Optional.empty();
}
}

41
common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/RpcLinkSetCallback.java

@ -0,0 +1,41 @@
/**
* Copyright © 2016-2021 The Thingsboard Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.transport.lwm2m.server.rpc;
import org.eclipse.leshan.core.Link;
import org.eclipse.leshan.core.ResponseCode;
import org.eclipse.leshan.core.response.DiscoverResponse;
import org.thingsboard.common.util.JacksonUtil;
import org.thingsboard.server.common.transport.TransportService;
import org.thingsboard.server.gen.transport.TransportProtos;
import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient;
import org.thingsboard.server.transport.lwm2m.server.downlink.DownlinkRequestCallback;
import java.util.Optional;
import java.util.Set;
public class RpcLinkSetCallback<T> extends RpcDownlinkRequestCallbackProxy<T> {
public RpcLinkSetCallback(TransportService transportService, LwM2mClient client, TransportProtos.ToDeviceRpcRequestMsg requestMsg, DownlinkRequestCallback<T> callback) {
super(transportService, client, requestMsg, callback);
}
@Override
protected void sendRpcReplyOnSuccess(T response) {
reply(LwM2MRpcResponseBody.builder().result(ResponseCode.CONTENT.getName()).value(JacksonUtil.toString(response)).build());
}
}

50
common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/RpcLwM2MDownlinkCallback.java

@ -0,0 +1,50 @@
/**
* Copyright © 2016-2021 The Thingsboard Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.transport.lwm2m.server.rpc;
import org.eclipse.leshan.core.response.LwM2mResponse;
import org.thingsboard.server.common.data.StringUtils;
import org.thingsboard.server.common.transport.TransportService;
import org.thingsboard.server.gen.transport.TransportProtos;
import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient;
import org.thingsboard.server.transport.lwm2m.server.downlink.DownlinkRequestCallback;
import java.util.Optional;
public abstract class RpcLwM2MDownlinkCallback<T extends LwM2mResponse> extends RpcDownlinkRequestCallbackProxy<T> {
public RpcLwM2MDownlinkCallback(TransportService transportService, LwM2mClient client, TransportProtos.ToDeviceRpcRequestMsg requestMsg, DownlinkRequestCallback<T> callback) {
super(transportService, client, requestMsg, callback);
}
@Override
protected void sendRpcReplyOnSuccess(T response) {
LwM2MRpcResponseBody.LwM2MRpcResponseBodyBuilder builder = LwM2MRpcResponseBody.builder().result(response.getCode().getName());
if (response.isSuccess()) {
Optional<String> responseValue = serializeSuccessfulResponse(response);
if (responseValue.isPresent() && StringUtils.isNotEmpty(responseValue.get())) {
builder.value(responseValue.get());
}
} else {
if (StringUtils.isNotEmpty(response.getErrorMessage())) {
builder.error(response.getErrorMessage());
}
}
reply(builder.build());
}
protected abstract Optional<String> serializeSuccessfulResponse(T response);
}

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

@ -0,0 +1,50 @@
/**
* Copyright © 2016-2021 The Thingsboard Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.transport.lwm2m.server.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.response.ReadResponse;
import org.thingsboard.server.common.transport.TransportService;
import org.thingsboard.server.gen.transport.TransportProtos;
import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient;
import org.thingsboard.server.transport.lwm2m.server.downlink.DownlinkRequestCallback;
import java.util.Optional;
public class RpcReadResponseCallback<T extends ReadResponse> extends RpcLwM2MDownlinkCallback<T> {
private final String versionedId;
public RpcReadResponseCallback(TransportService transportService, LwM2mClient client, TransportProtos.ToDeviceRpcRequestMsg requestMsg, String versionedId, DownlinkRequestCallback<T> callback) {
super(transportService, client, requestMsg, callback);
this.versionedId = versionedId;
}
@Override
protected Optional<String> serializeSuccessfulResponse(T response) {
Object value = null;
if (response.getContent() instanceof LwM2mObject) {
value = client.objectToString((LwM2mObject) response.getContent(), this.converter, versionedId);
} else if (response.getContent() instanceof LwM2mObjectInstance) {
value = client.instanceToString((LwM2mObjectInstance) response.getContent(), this.converter, versionedId);
} else if (response.getContent() instanceof LwM2mResource) {
value = client.resourceToString((LwM2mResource) response.getContent(), this.converter, versionedId);
}
return Optional.of(String.format("%s", value));
}
}

28
common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/RpcWriteAttributesRequest.java

@ -0,0 +1,28 @@
/**
* Copyright © 2016-2021 The Thingsboard Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.transport.lwm2m.server.rpc;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.thingsboard.server.common.data.device.data.lwm2m.ObjectAttributes;
@Data
@EqualsAndHashCode(callSuper = true)
public class RpcWriteAttributesRequest extends IdOrKeyRequest {
private ObjectAttributes attributes;
}

27
common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/RpcWriteReplaceRequest.java

@ -0,0 +1,27 @@
/**
* Copyright © 2016-2021 The Thingsboard Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.transport.lwm2m.server.rpc;
import lombok.Data;
import lombok.EqualsAndHashCode;
@Data
@EqualsAndHashCode(callSuper = true)
public class RpcWriteReplaceRequest extends IdOrKeyRequest {
private Object value;
}

29
common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/RpcWriteUpdateRequest.java

@ -0,0 +1,29 @@
/**
* Copyright © 2016-2021 The Thingsboard Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.transport.lwm2m.server.rpc;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.thingsboard.server.common.data.device.data.lwm2m.ObjectAttributes;
@Data
@EqualsAndHashCode(callSuper = true)
public class RpcWriteUpdateRequest extends IdOrKeyRequest {
private Object value;
private String contentFormat;
}

29
common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/uplink/DefaultLwM2MUplinkMsgHandler.java

@ -5,7 +5,7 @@
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
@ -80,7 +80,7 @@ import org.thingsboard.server.transport.lwm2m.server.downlink.TbLwM2MReadCallbac
import org.thingsboard.server.transport.lwm2m.server.downlink.TbLwM2MReadRequest;
import org.thingsboard.server.transport.lwm2m.server.downlink.TbLwM2MWriteAttributesCallback;
import org.thingsboard.server.transport.lwm2m.server.downlink.TbLwM2MWriteAttributesRequest;
import org.thingsboard.server.transport.lwm2m.server.downlink.TbLwM2MWriteReplaceCallback;
import org.thingsboard.server.transport.lwm2m.server.downlink.TbLwM2MWriteResponseCallback;
import org.thingsboard.server.transport.lwm2m.server.downlink.TbLwM2MWriteReplaceRequest;
import org.thingsboard.server.transport.lwm2m.server.rpc.LwM2MRpcRequestHandler;
import org.thingsboard.server.transport.lwm2m.server.rpc.LwM2mClientRpcRequest;
@ -115,7 +115,6 @@ import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.L
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LOG_LW2M_INFO;
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LOG_LW2M_TELEMETRY;
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LOG_LW2M_WARN;
import static org.thingsboard.server.transport.lwm2m.server.LwM2mOperationType.READ;
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.SW_ID;
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.convertOtaUpdateValueToString;
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.convertPathFromObjectIdToIdVer;
@ -333,29 +332,7 @@ public class DefaultLwM2MUplinkMsgHandler implements LwM2mUplinkMsgHandler {
this.updateResourcesValue(registration, lwM2mResource, path);
}
}
if (rpcRequest != null) {
//TODO: move this to separate callback.
this.sendRpcRequestAfterReadResponse(registration, lwM2MClient, path, response, rpcRequest);
}
}
}
private void sendRpcRequestAfterReadResponse(Registration registration, LwM2mClient lwM2MClient, String pathIdVer, ReadResponse response,
LwM2mClientRpcRequest rpcRequest) {
Object value = null;
if (response.getContent() instanceof LwM2mObject) {
value = lwM2MClient.objectToString((LwM2mObject) response.getContent(), this.converter, pathIdVer);
} else if (response.getContent() instanceof LwM2mObjectInstance) {
value = lwM2MClient.instanceToString((LwM2mObjectInstance) response.getContent(), this.converter, pathIdVer);
} else if (response.getContent() instanceof LwM2mResource) {
value = lwM2MClient.resourceToString((LwM2mResource) response.getContent(), this.converter, pathIdVer);
}
String msg = String.format("%s: type operation %s path - %s value - %s", LOG_LW2M_INFO,
READ, pathIdVer, value);
this.sendLogsToThingsboard(lwM2MClient, msg);
rpcRequest.setValueMsg(String.format("%s", value));
//TODO: refactor
// this.sentRpcResponse(rpcRequest, response.getCode().getName(), (String) value, LOG_LW2M_VALUE);
}
/**
@ -964,7 +941,7 @@ public class DefaultLwM2MUplinkMsgHandler implements LwM2mUplinkMsgHandler {
private void updateResourcesValueToClient(LwM2mClient lwM2MClient, Object valueOld, Object newValue, String versionedId) {
if (newValue != null && (valueOld == null || !newValue.toString().equals(valueOld.toString()))) {
TbLwM2MWriteReplaceRequest request = TbLwM2MWriteReplaceRequest.builder().versionedId(versionedId).value(newValue).timeout(this.config.getTimeout()).build();
defaultLwM2MDownlinkMsgHandler.sendWriteReplaceRequest(lwM2MClient, request, new TbLwM2MWriteReplaceCallback(this, lwM2MClient, versionedId));
defaultLwM2MDownlinkMsgHandler.sendWriteReplaceRequest(lwM2MClient, request, new TbLwM2MWriteResponseCallback(this, lwM2MClient, versionedId));
} else {
log.error("Failed update resource [{}] [{}]", versionedId, newValue);
String logMsg = String.format("%s: Failed update resource versionedId - %s value - %s. Value is not changed or bad",

Loading…
Cancel
Save