Skip to content

Commit

Permalink
eclipse-leshanGH-534:Add support of pmin,pmax,lt,gt,st for simple obs…
Browse files Browse the repository at this point in the history
…erve to client.

Co-authored-by: Magdalena Kundera <[email protected]>
  • Loading branch information
sbernard31 and mgdlkundera committed Apr 18, 2024
1 parent 57d0cb5 commit 60bc085
Show file tree
Hide file tree
Showing 44 changed files with 3,831 additions and 122 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
import org.eclipse.leshan.client.endpoint.ClientEndpointToolbox;
import org.eclipse.leshan.client.endpoint.LwM2mClientEndpoint;
import org.eclipse.leshan.client.endpoint.LwM2mClientEndpointsProvider;
import org.eclipse.leshan.client.notification.NotificationManager;
import org.eclipse.leshan.client.request.DownlinkRequestReceiver;
import org.eclipse.leshan.client.resource.LwM2mObjectTree;
import org.eclipse.leshan.client.servers.LwM2mServer;
Expand Down Expand Up @@ -146,7 +147,7 @@ public LwM2mServer extractIdentity(Exchange exchange, IpPeer foreignPeer) {

@Override
public void init(LwM2mObjectTree objectTree, DownlinkRequestReceiver requestReceiver,
ClientEndpointToolbox toolbox) {
NotificationManager notificationManager, ClientEndpointToolbox toolbox) {
this.objectTree = objectTree;

// create coap server
Expand All @@ -160,7 +161,7 @@ protected Resource createRoot() {

// create resources
List<Resource> resources = messagetranslator.createResources(coapServer, identityHandlerProvider,
identityExtrator, requestReceiver, toolbox, objectTree);
identityExtrator, requestReceiver, notificationManager, toolbox, objectTree);
coapServer.add(resources.toArray(new Resource[resources.size()]));
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
import org.eclipse.leshan.client.californium.request.CoapRequestBuilder;
import org.eclipse.leshan.client.californium.request.LwM2mResponseBuilder;
import org.eclipse.leshan.client.endpoint.ClientEndpointToolbox;
import org.eclipse.leshan.client.notification.NotificationManager;
import org.eclipse.leshan.client.request.DownlinkRequestReceiver;
import org.eclipse.leshan.client.resource.LwM2mObjectEnabler;
import org.eclipse.leshan.client.resource.LwM2mObjectTree;
Expand Down Expand Up @@ -89,24 +90,24 @@ public void resourceChanged(LwM2mPath... paths) {

public List<Resource> createResources(CoapServer coapServer, IdentityHandlerProvider identityHandlerProvider,
ServerIdentityExtractor identityExtrator, DownlinkRequestReceiver requestReceiver,
ClientEndpointToolbox toolbox, LwM2mObjectTree objectTree) {
NotificationManager notificationManager, ClientEndpointToolbox toolbox, LwM2mObjectTree objectTree) {
ArrayList<Resource> resources = new ArrayList<>();

// create bootstrap resource
resources.add(new BootstrapResource(identityHandlerProvider, identityExtrator, requestReceiver));

// create object resources
for (LwM2mObjectEnabler enabler : objectTree.getObjectEnablers().values()) {
resources.add(
createObjectResource(enabler, identityHandlerProvider, identityExtrator, requestReceiver, toolbox));
resources.add(createObjectResource(enabler, identityHandlerProvider, identityExtrator, requestReceiver,
notificationManager, toolbox));
}

// link resource to object tree
objectTree.addListener(new ObjectsListenerAdapter() {
@Override
public void objectAdded(LwM2mObjectEnabler object) {
CoapResource clientObject = createObjectResource(object, identityHandlerProvider, identityExtrator,
requestReceiver, toolbox);
requestReceiver, notificationManager, toolbox);
coapServer.add(clientObject);
}

Expand All @@ -124,9 +125,10 @@ public void objectRemoved(LwM2mObjectEnabler object) {

public CoapResource createObjectResource(LwM2mObjectEnabler objectEnabler,
IdentityHandlerProvider identityHandlerProvider, ServerIdentityExtractor identityExtractor,
DownlinkRequestReceiver requestReceiver, ClientEndpointToolbox toolbox) {
DownlinkRequestReceiver requestReceiver, NotificationManager notificationManager,
ClientEndpointToolbox toolbox) {
ObjectResource objectResource = new ObjectResource(objectEnabler.getId(), identityHandlerProvider,
identityExtractor, requestReceiver, toolbox);
identityExtractor, requestReceiver, notificationManager, toolbox);
objectEnabler.addListener(objectResource);
return objectResource;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,17 +28,23 @@
import org.eclipse.californium.core.coap.CoAP.ResponseCode;
import org.eclipse.californium.core.coap.MediaTypeRegistry;
import org.eclipse.californium.core.coap.Request;
import org.eclipse.californium.core.coap.Response;
import org.eclipse.californium.core.observe.ObserveRelation;
import org.eclipse.californium.core.server.resources.CoapExchange;
import org.eclipse.californium.core.server.resources.Resource;
import org.eclipse.californium.core.server.resources.ResourceObserverAdapter;
import org.eclipse.leshan.client.californium.LwM2mClientCoapResource;
import org.eclipse.leshan.client.californium.endpoint.ServerIdentityExtractor;
import org.eclipse.leshan.client.endpoint.ClientEndpointToolbox;
import org.eclipse.leshan.client.notification.NotificationManager;
import org.eclipse.leshan.client.request.DownlinkRequestReceiver;
import org.eclipse.leshan.client.resource.LwM2mObjectEnabler;
import org.eclipse.leshan.client.resource.NotificationSender;
import org.eclipse.leshan.client.resource.listener.ObjectListener;
import org.eclipse.leshan.client.servers.LwM2mServer;
import org.eclipse.leshan.core.californium.identity.IdentityHandlerProvider;
import org.eclipse.leshan.core.link.attributes.InvalidAttributeException;
import org.eclipse.leshan.core.link.lwm2m.attributes.InvalidAttributesException;
import org.eclipse.leshan.core.link.lwm2m.attributes.LwM2mAttributeSet;
import org.eclipse.leshan.core.node.InvalidLwM2mPathException;
import org.eclipse.leshan.core.node.LwM2mNode;
Expand Down Expand Up @@ -75,22 +81,57 @@
import org.eclipse.leshan.core.response.ReadResponse;
import org.eclipse.leshan.core.response.WriteAttributesResponse;
import org.eclipse.leshan.core.response.WriteResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
* A CoAP {@link Resource} in charge of handling requests targeting a lwM2M Object.
*/
public class ObjectResource extends LwM2mClientCoapResource implements ObjectListener {

private static final Logger LOG = LoggerFactory.getLogger(ObjectResource.class);

protected DownlinkRequestReceiver requestReceiver;
protected ClientEndpointToolbox toolbox;
protected NotificationManager notificationManager;

public ObjectResource(int objectId, IdentityHandlerProvider identityHandlerProvider,
ServerIdentityExtractor serverIdentityExtractor, DownlinkRequestReceiver requestReceiver,
ClientEndpointToolbox toolbox) {
NotificationManager notificationManager, ClientEndpointToolbox toolbox) {
super(Integer.toString(objectId), identityHandlerProvider, serverIdentityExtractor);
this.requestReceiver = requestReceiver;
this.notificationManager = notificationManager;
this.toolbox = toolbox;
setObservable(true);

this.addObserver(new ResourceObserverAdapter() {

@Override
public void removedObserveRelation(ObserveRelation relation) {
// Get object URI
Request request = relation.getExchange().getRequest();
String URI = request.getOptions().getUriPathString();
// we don't manage observation on root path
if (URI == null)
return;

// Get Server identity
LwM2mServer extractIdentity = extractIdentity(relation.getExchange(), request);

// handle content format for Read and Observe Request
ContentFormat requestedContentFormat = null;
if (request.getOptions().hasAccept()) {
// If an request ask for a specific content format, use it (if we support it)
requestedContentFormat = ContentFormat.fromCode(request.getOptions().getAccept());
}

// Create Observe request
ObserveRequest observeRequest = new ObserveRequest(requestedContentFormat, URI, request);

// Remove notification data for this request
notificationManager.clear(extractIdentity, observeRequest);
}
});
}

@Override
Expand Down Expand Up @@ -143,16 +184,44 @@ public void handleGET(CoapExchange exchange) {
// Manage Observe Request
if (exchange.getRequestOptions().hasObserve()) {
ObserveRequest observeRequest = new ObserveRequest(requestedContentFormat, URI, coapRequest);
ObserveResponse response = requestReceiver.requestReceived(server, observeRequest).getResponse();
if (response.getCode() == org.eclipse.leshan.core.ResponseCode.CONTENT) {
LwM2mPath path = getPath(URI);
LwM2mNode content = response.getContent();
ContentFormat format = getContentFormat(observeRequest, requestedContentFormat);
exchange.respond(ResponseCode.CONTENT,
toolbox.getEncoder().encode(content, format, path, toolbox.getModel()), format.getCode());
return;

boolean isObserveRelationEstablishement = coapRequest.isObserve()
&& (exchange.advanced().getRelation() == null
|| !exchange.advanced().getRelation().isEstablished());
boolean isActiveObserveCancellation = coapRequest.isObserveCancel();
if (isObserveRelationEstablishement || isActiveObserveCancellation) {
// Handle observe request
ObserveResponse response = requestReceiver.requestReceived(server, observeRequest).getResponse();
if (response.getCode() == org.eclipse.leshan.core.ResponseCode.CONTENT) {
LwM2mPath path = getPath(URI);
LwM2mNode content = response.getContent();
ContentFormat format = getContentFormat(observeRequest, requestedContentFormat);

// change notification manager state
if (isObserveRelationEstablishement) {
try {
notificationManager.initRelation(server, observeRequest, content,
createNotificationSender(exchange, server, observeRequest,
requestedContentFormat));
} catch (InvalidAttributesException e) {
exchange.respond(
toCoapResponseCode(org.eclipse.leshan.core.ResponseCode.INTERNAL_SERVER_ERROR),
"Invalid Attributes state : " + e.getMessage());
}
}

// send response
exchange.respond(ResponseCode.CONTENT,
toolbox.getEncoder().encode(content, format, path, toolbox.getModel()),
format.getCode());
} else {
exchange.respond(toCoapResponseCode(response.getCode()), response.getErrorMessage());
return;
}
} else {
exchange.respond(toCoapResponseCode(response.getCode()), response.getErrorMessage());
// Handle notifications
notificationManager.notificationTriggered(server, observeRequest,
createNotificationSender(exchange, server, observeRequest, requestedContentFormat));
return;
}
} else {
Expand Down Expand Up @@ -194,6 +263,39 @@ public void handleGET(CoapExchange exchange) {
}
}

protected NotificationSender createNotificationSender(CoapExchange exchange, LwM2mServer server,
ObserveRequest observeRequest, ContentFormat requestedContentFormat) {
return new NotificationSender() {
@Override
public boolean sendNotification(ObserveResponse response) {
try {
if (exchange.advanced().getRelation() != null && !exchange.advanced().getRelation().isCanceled()) {
if (response.getCode() == org.eclipse.leshan.core.ResponseCode.CONTENT) {
LwM2mPath path = observeRequest.getPath();
LwM2mNode content = response.getContent();
ContentFormat format = getContentFormat(observeRequest, requestedContentFormat);
Response coapResponse = new Response(ResponseCode.CONTENT);
coapResponse
.setPayload(toolbox.getEncoder().encode(content, format, path, toolbox.getModel()));
coapResponse.getOptions().setContentFormat(format.getCode());
exchange.respond(coapResponse);
return true;
} else {
exchange.respond(toCoapResponseCode(response.getCode()), response.getErrorMessage());
return false;
}
}
return false;
} catch (Exception e) {
LOG.error("Exception while sending notification [{}] for [{}] to {}", response, observeRequest,
server, e);
exchange.respond(ResponseCode.INTERNAL_SERVER_ERROR, "failure sending notification");
return false;
}
}
};
}

protected ContentFormat getContentFormat(DownlinkRequest<?> request, ContentFormat requestedContentFormat) {
if (requestedContentFormat != null) {
// we already check before this content format is supported.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,10 @@
import org.eclipse.leshan.client.endpoint.LwM2mClientEndpointsProvider;
import org.eclipse.leshan.client.engine.RegistrationEngine;
import org.eclipse.leshan.client.engine.RegistrationEngineFactory;
import org.eclipse.leshan.client.notification.DefaultNotificationStrategy;
import org.eclipse.leshan.client.notification.NotificationDataStore;
import org.eclipse.leshan.client.notification.NotificationManager;
import org.eclipse.leshan.client.notification.NotificationStrategy;
import org.eclipse.leshan.client.observer.LwM2mClientObserver;
import org.eclipse.leshan.client.observer.LwM2mClientObserverAdapter;
import org.eclipse.leshan.client.observer.LwM2mClientObserverDispatcher;
Expand All @@ -56,6 +60,7 @@
import org.eclipse.leshan.core.node.LwM2mPath;
import org.eclipse.leshan.core.node.codec.LwM2mDecoder;
import org.eclipse.leshan.core.node.codec.LwM2mEncoder;
import org.eclipse.leshan.core.request.BootstrapRequest;
import org.eclipse.leshan.core.request.ContentFormat;
import org.eclipse.leshan.core.response.ErrorCallback;
import org.eclipse.leshan.core.response.ResponseCallback;
Expand All @@ -82,6 +87,7 @@ public class LeshanClient implements LwM2mClient {
private final RegistrationEngine engine;
private final LwM2mClientObserverDispatcher observers;
private final DataSenderManager dataSenderManager;
private final NotificationManager notificationManager;

public LeshanClient(String endpoint, List<? extends LwM2mObjectEnabler> objectEnablers,
List<DataSender> dataSenders, List<Certificate> trustStore, RegistrationEngineFactory engineFactory,
Expand Down Expand Up @@ -120,7 +126,29 @@ public LeshanClient(String endpoint, List<? extends LwM2mObjectEnabler> objectEn
engine);
createRegistrationUpdateHandler(engine, endpointsManager, bootstrapHandler, objectTree, linkFormatHelper);

endpointsProvider.init(objectTree, requestReceiver, toolbox);
notificationManager = createNotificationManager(objectTree, requestReceiver, sharedExecutor);
endpointsProvider.init(objectTree, requestReceiver, notificationManager, toolbox);
}

protected NotificationManager createNotificationManager(LwM2mObjectTree objectTree,
DownlinkRequestReceiver requestReceiver, ScheduledExecutorService sharedExecutor) {
final NotificationManager notificationManager = new NotificationManager(objectTree, requestReceiver,
createNotificationStore(), createNotificationStrategy(), sharedExecutor);
this.addObserver(new LwM2mClientObserverAdapter() {
@Override
public void onBootstrapStarted(LwM2mServer bsserver, BootstrapRequest request) {
notificationManager.clear();
}
});
return notificationManager;
}

protected NotificationDataStore createNotificationStore() {
return new NotificationDataStore();
}

protected NotificationStrategy createNotificationStrategy() {
return new DefaultNotificationStrategy();
}

protected LwM2mRootEnabler createRootEnabler(LwM2mObjectTree tree) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import java.util.Collections;
import java.util.List;

import org.eclipse.leshan.client.notification.NotificationManager;
import org.eclipse.leshan.client.request.DownlinkRequestReceiver;
import org.eclipse.leshan.client.resource.LwM2mObjectTree;
import org.eclipse.leshan.client.servers.LwM2mServer;
Expand All @@ -46,9 +47,9 @@ public DefaultCompositeClientEndpointsProvider(Collection<LwM2mClientEndpointsPr

@Override
public void init(LwM2mObjectTree objectTree, DownlinkRequestReceiver requestReceiver,
ClientEndpointToolbox toolbox) {
NotificationManager notificationManager, ClientEndpointToolbox toolbox) {
for (LwM2mClientEndpointsProvider provider : providers) {
provider.init(objectTree, requestReceiver, toolbox);
provider.init(objectTree, requestReceiver, notificationManager, toolbox);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,16 @@
import java.util.Collection;
import java.util.List;

import org.eclipse.leshan.client.notification.NotificationManager;
import org.eclipse.leshan.client.request.DownlinkRequestReceiver;
import org.eclipse.leshan.client.resource.LwM2mObjectTree;
import org.eclipse.leshan.client.servers.LwM2mServer;
import org.eclipse.leshan.client.servers.ServerInfo;

public interface LwM2mClientEndpointsProvider {

void init(LwM2mObjectTree objectTree, DownlinkRequestReceiver requestReceiver, ClientEndpointToolbox toolbox);
void init(LwM2mObjectTree objectTree, DownlinkRequestReceiver requestReceiver,
NotificationManager notificationManager, ClientEndpointToolbox toolbox);

LwM2mServer createEndpoint(ServerInfo serverInfo, boolean clientInitiatedOnly, List<Certificate> trustStore,
ClientEndpointToolbox toolbox);
Expand Down
Loading

0 comments on commit 60bc085

Please sign in to comment.