Skip to content

Commit

Permalink
Read Response
Browse files Browse the repository at this point in the history
  • Loading branch information
mgdlkundera committed Apr 19, 2024
1 parent 089f2da commit fdf802c
Show file tree
Hide file tree
Showing 11 changed files with 229 additions and 58 deletions.
Expand Up @@ -316,7 +316,7 @@ public ErrorResponseCreator(ResponseCode code, String errorMessage) {

@Override
public void visit(ReadRequest request) {
response = new ReadResponse(code, null, errorMessage);
response = new ReadResponse(code, null, null, errorMessage);
}

@Override
Expand Down
Expand Up @@ -40,8 +40,9 @@ public ObserveResponse(ResponseCode code, LwM2mNode content, List<TimestampedLwM

public ObserveResponse(ResponseCode code, LwM2mNode content, List<TimestampedLwM2mNode> timestampedValues,
SingleObservation observation, String errorMessage, Object coapResponse) {
super(code, timestampedValues != null && !timestampedValues.isEmpty() ? timestampedValues.get(0).getNode()
: content, errorMessage, coapResponse);
super(code, content,
timestampedValues != null && !timestampedValues.isEmpty() ? timestampedValues.get(0) : null,
errorMessage, coapResponse);

// CHANGED is out of spec but is supported for backward compatibility. (previous draft version)
if (ResponseCode.CHANGED.equals(code)) {
Expand All @@ -53,7 +54,7 @@ public ObserveResponse(ResponseCode code, LwM2mNode content, List<TimestampedLwM
this.timestampedValues = timestampedValues;
}

public List<TimestampedLwM2mNode> getTimestampedLwM2mNode() {
public List<TimestampedLwM2mNode> getTimestampedLwM2mNodes() {
return timestampedValues;
}

Expand Down
Expand Up @@ -25,20 +25,27 @@
import org.eclipse.leshan.core.node.LwM2mNode;
import org.eclipse.leshan.core.node.LwM2mSingleResource;
import org.eclipse.leshan.core.node.ObjectLink;
import org.eclipse.leshan.core.node.TimestampedLwM2mNode;
import org.eclipse.leshan.core.request.exception.InvalidResponseException;
import org.eclipse.leshan.core.util.datatype.ULong;

public class ReadResponse extends AbstractLwM2mResponse {

protected final LwM2mChildNode content;

public ReadResponse(ResponseCode code, LwM2mNode content, String errorMessage) {
this(code, content, errorMessage, null);
protected final TimestampedLwM2mNode timestampedValue;

public ReadResponse(ResponseCode code, LwM2mNode content, TimestampedLwM2mNode timestampedValue,
String errorMessage) {
this(code, content, timestampedValue, errorMessage, null);
}

public ReadResponse(ResponseCode code, LwM2mNode content, String errorMessage, Object coapResponse) {
public ReadResponse(ResponseCode code, LwM2mNode content, TimestampedLwM2mNode timestampedValue,
String errorMessage, Object coapResponse) {
super(code, errorMessage, coapResponse);

content = timestampedValue != null ? timestampedValue.getNode() : content;

if (ResponseCode.CONTENT.equals(code)) {
if (content == null)
throw new InvalidResponseException("Content is mandatory for successful response");
Expand All @@ -48,6 +55,11 @@ public ReadResponse(ResponseCode code, LwM2mNode content, String errorMessage, O
content.getClass().getSimpleName());
}
this.content = (LwM2mChildNode) content;
this.timestampedValue = timestampedValue;
}

public TimestampedLwM2mNode getTimestampedLwM2mNode() {
return timestampedValue;
}

@Override
Expand Down Expand Up @@ -94,65 +106,76 @@ public static ReadResponse success(LwM2mNode content) {
return new ReadResponse(ResponseCode.CONTENT, content, null, null);
}

public static ReadResponse success(TimestampedLwM2mNode timestampedValue) {
return new ReadResponse(ResponseCode.CONTENT, null, timestampedValue, null, null);
}

public static ReadResponse success(int resourceId, String value) {
return new ReadResponse(ResponseCode.CONTENT, LwM2mSingleResource.newStringResource(resourceId, value), null);
return new ReadResponse(ResponseCode.CONTENT, LwM2mSingleResource.newStringResource(resourceId, value), null,
null);
}

public static ReadResponse success(int resourceId, Date value) {
return new ReadResponse(ResponseCode.CONTENT, LwM2mSingleResource.newDateResource(resourceId, value), null);
return new ReadResponse(ResponseCode.CONTENT, LwM2mSingleResource.newDateResource(resourceId, value), null,
null);
}

public static ReadResponse success(int resourceId, long value) {
return new ReadResponse(ResponseCode.CONTENT, LwM2mSingleResource.newIntegerResource(resourceId, value), null);
return new ReadResponse(ResponseCode.CONTENT, LwM2mSingleResource.newIntegerResource(resourceId, value), null,
null);
}

public static ReadResponse success(int resourceId, ULong value) {
return new ReadResponse(ResponseCode.CONTENT, LwM2mSingleResource.newUnsignedIntegerResource(resourceId, value),
null);
null, null);
}

public static ReadResponse success(int resourceId, ObjectLink value) {
return new ReadResponse(ResponseCode.CONTENT, LwM2mSingleResource.newObjectLinkResource(resourceId, value),
null);
null, null);
}

public static ReadResponse success(int resourceId, double value) {
return new ReadResponse(ResponseCode.CONTENT, LwM2mSingleResource.newFloatResource(resourceId, value), null);
return new ReadResponse(ResponseCode.CONTENT, LwM2mSingleResource.newFloatResource(resourceId, value), null,
null);
}

public static ReadResponse success(int resourceId, boolean value) {
return new ReadResponse(ResponseCode.CONTENT, LwM2mSingleResource.newBooleanResource(resourceId, value), null);
return new ReadResponse(ResponseCode.CONTENT, LwM2mSingleResource.newBooleanResource(resourceId, value), null,
null);
}

public static ReadResponse success(int resourceId, byte[] value) {
return new ReadResponse(ResponseCode.CONTENT, LwM2mSingleResource.newBinaryResource(resourceId, value), null);
return new ReadResponse(ResponseCode.CONTENT, LwM2mSingleResource.newBinaryResource(resourceId, value), null,
null);
}

public static ReadResponse success(int resourceId, Map<Integer, ?> value, Type type) {
return new ReadResponse(ResponseCode.CONTENT, LwM2mMultipleResource.newResource(resourceId, value, type), null);
return new ReadResponse(ResponseCode.CONTENT, LwM2mMultipleResource.newResource(resourceId, value, type), null,
null);
}

public static ReadResponse notFound() {
return new ReadResponse(ResponseCode.NOT_FOUND, null, null);
return new ReadResponse(ResponseCode.NOT_FOUND, null, null, null);
}

public static ReadResponse unauthorized() {
return new ReadResponse(ResponseCode.UNAUTHORIZED, null, null);
return new ReadResponse(ResponseCode.UNAUTHORIZED, null, null, null);
}

public static ReadResponse methodNotAllowed() {
return new ReadResponse(ResponseCode.METHOD_NOT_ALLOWED, null, null);
return new ReadResponse(ResponseCode.METHOD_NOT_ALLOWED, null, null, null);
}

public static ReadResponse notAcceptable() {
return new ReadResponse(ResponseCode.NOT_ACCEPTABLE, null, null);
return new ReadResponse(ResponseCode.NOT_ACCEPTABLE, null, null, null);
}

public static ReadResponse badRequest(String errorMessage) {
return new ReadResponse(ResponseCode.BAD_REQUEST, null, errorMessage);
return new ReadResponse(ResponseCode.BAD_REQUEST, null, null, errorMessage);
}

public static ReadResponse internalServerError(String errorMessage) {
return new ReadResponse(ResponseCode.INTERNAL_SERVER_ERROR, null, errorMessage);
return new ReadResponse(ResponseCode.INTERNAL_SERVER_ERROR, null, null, errorMessage);
}
}
Expand Up @@ -74,7 +74,7 @@ public void should_not_throw_exception_if_has_content(ResponseCode responseCode)

// then
assertEquals(exampleResource, response.getContent());
assertNull(response.getTimestampedLwM2mNode());
assertNull(response.getTimestampedLwM2mNodes());
}

@TestAllResponseCode
Expand All @@ -91,6 +91,6 @@ public void should_get_content_from_first_of_timestamped_values(ResponseCode res

// then
assertEquals(timestampedValues.get(0).getNode(), response.getContent());
assertEquals(timestampedValues, response.getTimestampedLwM2mNode());
assertEquals(timestampedValues, response.getTimestampedLwM2mNodes());
}
}
Expand Up @@ -109,4 +109,8 @@ public Token sendCoapRequest(Request coapReq) {
public String getEndpointName() {
return endpointName;
}

public LwM2mModel getLwM2mModel() {
return model;
}
}
Expand Up @@ -35,6 +35,7 @@
import java.net.InetSocketAddress;
import java.net.URI;
import java.time.Duration;
import java.time.Instant;
import java.util.EnumSet;
import java.util.Set;
import java.util.concurrent.Callable;
Expand All @@ -54,6 +55,11 @@
import org.eclipse.leshan.core.endpoint.Protocol;
import org.eclipse.leshan.core.link.LinkParser;
import org.eclipse.leshan.core.link.lwm2m.DefaultLwM2mLinkParser;
import org.eclipse.leshan.core.node.LwM2mPath;
import org.eclipse.leshan.core.node.LwM2mSingleResource;
import org.eclipse.leshan.core.node.TimestampedLwM2mNodes;
import org.eclipse.leshan.core.node.codec.DefaultLwM2mEncoder;
import org.eclipse.leshan.core.node.codec.LwM2mEncoder;
import org.eclipse.leshan.core.observation.Observation;
import org.eclipse.leshan.core.request.BindingMode;
import org.eclipse.leshan.core.request.ContentFormat;
Expand Down Expand Up @@ -315,7 +321,7 @@ public ReadResponse call() throws Exception {

// Acknowledge the response
client.expectRequest().storeMID("R").go();
client.sendEmpty(Type.ACK).loadMID("R").go();
client.sendEmpty(Type.ACK, ContentFormat.TEXT).loadMID("R").go();

// Request should timedout in ~3s as we send the ACK
Thread.sleep(1500);
Expand Down Expand Up @@ -370,7 +376,7 @@ public void async_send_with_acknowleged_request_without_response(String givenSer

// Acknowledge the response
client.expectRequest().storeMID("R").go();
client.sendEmpty(Type.ACK).loadMID("R").go();
client.sendEmpty(Type.ACK, ContentFormat.TEXT).loadMID("R").go();

// Request should timedout in ~3s as we send a ack
Thread.sleep(1500);
Expand Down Expand Up @@ -418,8 +424,8 @@ public void register_deregister_observe(String givenServerEndpointProvider) thro
// with java-coap it failed transparently at response reception.
// TODO I don't know if this is the right behavior.
client.expectRequest().storeMID("R").storeToken("T").go();
client.sendResponse(Type.ACK, ResponseCode.CONTENT).payload("aaa").observe(2).loadMID("R").loadToken("T")
.go();
client.sendResponse(Type.ACK, ResponseCode.CONTENT, ContentFormat.TEXT).payload("aaa").observe(2)
.loadMID("R").loadToken("T").go();
}

// ensure we don't get answer and there is no observation in store.
Expand All @@ -428,4 +434,47 @@ public void register_deregister_observe(String givenServerEndpointProvider) thro
Set<Observation> observations = server.getObservationService().getObservations(registration);
assertThat(observations).isEmpty();
}

@TestAllTransportLayer
public void read_timestamped(String givenServerEndpointProvider) throws Exception {

// -------------------------------------------REGISTER
// CLIENT----------------------------------------------------
LockStepLwM2mClient client = new LockStepLwM2mClient(server.getEndpoint(Protocol.COAP).getURI());
Token token = client
.sendLwM2mRequest(new RegisterRequest(client.getEndpointName(), 60l, "1.1", EnumSet.of(BindingMode.U),
null, null, linkParser.parseCoreLinkFormat("</1>,</2>,</3>".getBytes()), null));
client.expectResponse().token(token).go();
server.waitForNewRegistrationOf(client.getEndpointName());
Registration registration = server.getRegistrationService().getByEndpoint(client.getEndpointName());
// --------------------------------------------------------------------------------------------------------------

// ----------------------------------------------TIMESTAMP-------------------------------------------------------
LwM2mEncoder encoder = new DefaultLwM2mEncoder();
TimestampedLwM2mNodes.Builder builder = new TimestampedLwM2mNodes.Builder();
Instant t1 = Instant.now();
builder.put(t1, new LwM2mPath("/1/0/1"), LwM2mSingleResource.newIntegerResource(1, 3600));
TimestampedLwM2mNodes timestampedNodes = builder.build();
byte[] payload = encoder.encodeTimestampedNodes(timestampedNodes, ContentFormat.SENML_JSON,
client.getLwM2mModel());
// --------------------------------------------------------------------------------------------------------------

// Send read REQUEST
Future<ReadResponse> future = Executors.newSingleThreadExecutor().submit(new Callable<ReadResponse>() {
@Override
public ReadResponse call() throws Exception {
// send a request with 3 seconds timeout
return server.send(registration, new ReadRequest(ContentFormat.SENML_JSON, 1), 2000);
}
});

client.expectRequest().storeToken("TKN").storeMID("MID").go();

client.sendResponse(Type.ACK, ResponseCode.CONTENT, ContentFormat.SENML_JSON).loadMID("MID").loadToken("TKN")
.payload(payload).go();

ReadResponse response = future.get(2000, TimeUnit.MILLISECONDS);
assertThat(response.getTimestampedLwM2mNode()).isNotNull();
}

}
Expand Up @@ -153,7 +153,7 @@ public void can_observe_timestamped_resource(ContentFormat contentFormat, String
ObserveResponse response = server.waitForNotificationOf(observation);
assertThat(response).hasContentFormat(contentFormat, givenServerEndpointProvider);
assertThat(response.getContent()).isEqualTo(mostRecentNode.getNode());
assertThat(response.getTimestampedLwM2mNode()).isEqualTo(timestampedNodes);
assertThat(response.getTimestampedLwM2mNodes()).isEqualTo(timestampedNodes);
}

@TestAllCases
Expand Down Expand Up @@ -194,7 +194,7 @@ public void can_observe_timestamped_instance(ContentFormat contentFormat, String
ObserveResponse response = server.waitForNotificationOf(observation);
assertThat(response).hasContentFormat(contentFormat, givenServerEndpointProvider);
assertThat(response.getContent()).isEqualTo(mostRecentNode.getNode());
assertThat(response.getTimestampedLwM2mNode()).isEqualTo(timestampedNodes);
assertThat(response.getTimestampedLwM2mNodes()).isEqualTo(timestampedNodes);
}

@TestAllCases
Expand Down Expand Up @@ -235,6 +235,6 @@ public void can_observe_timestamped_object(ContentFormat contentFormat, String g
ObserveResponse response = server.waitForNotificationOf(observation);
assertThat(response).hasContentFormat(contentFormat, givenServerEndpointProvider);
assertThat(response.getContent()).isEqualTo(mostRecentNode.getNode());
assertThat(response.getTimestampedLwM2mNode()).isEqualTo(timestampedNodes);
assertThat(response.getTimestampedLwM2mNodes()).isEqualTo(timestampedNodes);
}
}

0 comments on commit fdf802c

Please sign in to comment.