10000 Add Observe-Composite support. by sbernard31 · Pull Request #1083 · eclipse-leshan/leshan · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content

Add Observe-Composite support. #1083

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 8 commits into from
Sep 2, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
/*******************************************************************************
* Copyright (c) 2021 Orange.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v2.0
* and Eclipse Distribution License v1.0 which accompany this distribution.
*
* The Eclipse Public License is available at
* http://www.eclipse.org/legal/epl-v20.html
* and the Eclipse Distribution License is available at
* http://www.eclipse.org/org/documents/edl-v10.html.
*
* Contributors:
* Michał Wadowski (Orange) - Add Observe-Composite feature.
*******************************************************************************/
package org.eclipse.leshan.client.californium;

import java.util.Arrays;
import java.util.List;

import org.eclipse.californium.core.coap.CoAP;
import org.eclipse.californium.core.coap.Request;
import org.eclipse.californium.core.observe.ObserveRelation;
import org.eclipse.californium.core.observe.ObserveRelationFilter;
import org.eclipse.leshan.core.californium.ObserveUtil;
import org.eclipse.leshan.core.node.LwM2mPath;

/**
* An {@link ObserveRelationFilter} which select {@link ObserveRelation} based on one of resource URIs.
*/
class ObserveCompositeRelationFilter implements ObserveRelationFilter {

private final List<LwM2mPath> paths;

/**
* Instantiates {@link ObserveCompositeRelationFilter} basing on resource URIs.
*
* @param paths the list of {@link LwM2mPath}
*/
public ObserveCompositeRelationFilter(LwM2mPath... paths) {
this.paths = Arrays.asList(paths);
}

@Override
public boolean accept(ObserveRelation relation) {
Request request = getRequest(relation);

if (!isValidObserveCompositeRequest(request)) {
return false;
}

List<LwM2mPath> observationPaths = getObserveRequestPaths(request);

if (observationPaths != null) {
for (LwM2mPath observePath : observationPaths) {
for (LwM2mPath path : paths) {
if (path.startWith(observePath)) {
return true;
}
}
}
}

return false;
}

private boolean isValidObserveCompositeRequest(Request request) {
if (!request.getCode().equals(CoAP.Code.FETCH)) {
return false;
}
if (!request.getOptions().hasContentFormat()) {
return false;
}
return true;
}

private Request getRequest(ObserveRelation relation) {
return relation.getExchange().getRequest();
}

private List<LwM2mPath> getObserveRequestPaths(Request request) {
return ObserveUtil.getPathsFromContext(request.getUserContext());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,13 @@
* Contributors:
* Sierra Wireless - initial API and implementation
* Achim Kraus (Bosch Software Innovations GmbH) - use ServerIdentity
* Michał Wadowski (Orange) - Add Observe-Composite feature.
*******************************************************************************/
package org.eclipse.leshan.client.californium;

import static org.eclipse.leshan.core.californium.ResponseCodeUtil.toCoapResponseCode;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

Expand All @@ -30,19 +32,23 @@
import org.eclipse.leshan.client.bootstrap.BootstrapHandler;
import org.eclipse.leshan.client.engine.RegistrationEngine;
import org.eclipse.leshan.client.resource.LwM2mRootEnabler;
import org.eclipse.leshan.client.resource.listener.ObjectsListenerAdapter;
import org.eclipse.leshan.client.servers.ServerIdentity;
import org.eclipse.leshan.core.Link;
import org.eclipse.leshan.core.californium.ObserveUtil;
import org.eclipse.leshan.core.node.LwM2mNode;
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.BootstrapDeleteRequest;
import org.eclipse.leshan.core.request.BootstrapDiscoverRequest;
import org.eclipse.leshan.core.request.ContentFormat;
import org.eclipse.leshan.core.request.ObserveCompositeRequest;
import org.eclipse.leshan.core.request.ReadCompositeRequest;
import org.eclipse.leshan.core.request.WriteCompositeRequest;
import org.eclipse.leshan.core.response.BootstrapDeleteResponse;
import org.eclipse.leshan.core.response.BootstrapDiscoverResponse;
import org.eclipse.leshan.core.response.ObserveCompositeResponse;
import org.eclipse.leshan.core.response.ReadCompositeResponse;
import org.eclipse.leshan.core.response.WriteCompositeResponse;
import org.eclipse.leshan.core.util.StringUtils;
Expand All @@ -64,10 +70,13 @@ public RootResource(RegistrationEngine registrationEngine, CaliforniumEndpointsM
super("", registrationEngine, endpointsManager);
this.bootstrapHandler = bootstrapHandler;
setVisible(false);
setObservable(true);
this.coapServer = coapServer;
this.rootEnabler = rootEnabler;
this.encoder = encoder;
this.decoder = decoder;

addListeners();
}

@Override
Expand Down Expand Up @@ -97,7 +106,6 @@ public void handleFETCH(CoapExchange exchange) {
if (identity == null)
return;

// Manage Read Composite request
Request coapRequest = exchange.advanced().getRequest();

// Handle content format for the response
Expand All @@ -119,18 +127,47 @@ public void handleFETCH(CoapExchange exchange) {
ContentFormat requestContentFormat = ContentFormat.fromCode(exchange.getRequestOptions().getContentFormat());
List<LwM2mPath> paths = decoder.decodePaths(coapRequest.getPayload(), requestContentFormat);

ReadCompositeResponse response = rootEnabler.read(identity,
new ReadCompositeRequest(paths, requestContentFormat, responseContentFormat, coapRequest));
if (response.getCode().isError()) {
exchange.respond(toCoapResponseCode(response.getCode()), response.getErrorMessage());
if (exchange.getRequestOptions().hasObserve()) {
// Manage Observe Composite request
ObserveCompositeRequest observeRequest = new ObserveCompositeRequest(requestContentFormat,
responseContentFormat, paths, coapRequest);
ObserveCompositeResponse response = rootEnabler.observe(identity, observeRequest);

updateUserContextWithPaths(coapRequest, paths);

if (response.getCode().isError()) {
exchange.respond(toCoapResponseCode(response.getCode()), response.getErrorMessage());
return;
} else {
exchange.respond(toCoapResponseCode(response.getCode()),
encoder.encodeNodes(response.getContent(), responseContentFormat, rootEnabler.getModel()),
responseContentFormat.getCode());
return;
}
} else {
// TODO we could maybe face some race condition if an objectEnabler is removed from LwM2mObjectTree between
// rootEnabler.read() and rootEnabler.getModel()
exchange.respond(toCoapResponseCode(response.getCode()),
encoder.encodeNodes(response.getContent(), responseContentFormat, rootEnabler.getModel()),
responseContentFormat.getCode());
// Manage Read Composite request
ReadCompositeResponse response = rootEnabler.read(identity,
new ReadCompositeRequest(paths, requestContentFormat, responseContentFormat, coapRequest));
if (response.getCode().isError()) {
exchange.respond(toCoapResponseCode(response.getCode()), response.getErrorMessage());
} else {
// TODO we could maybe face some race condition if an objectEnabler is removed from LwM2mObjectTree
// between rootEnabler.read() and rootEnabler.getModel()
exchange.respond(toCoapResponseCode(response.getCode()),
encoder.encodeNodes(response.getContent(), responseContentFormat, rootEnabler.getModel()),
responseContentFormat.getCode());
}
return;
}
return;
}

private void updateUserContextWithPaths(Request coapRequest, List<LwM2mPath> paths) {
HashMap<String, String> userContext = new HashMap<>();
if (coapRequest.getUserContext() != null) {
userContext.putAll(coapRequest.getUserContext());
}
ObserveUtil.addPathsIntoContext(userContext, paths);
coapRequest.setUserContext(userContext);
}

@Override
Expand Down Expand Up @@ -180,4 +217,13 @@ public void handleDELETE(CoapExchange exchange) {
exchange.respond(toCoapResponseCode(response.getCode()), response.getErrorMessage());
}

private void addListeners() {
rootEnabler.addListener(new ObjectsListenerAdapter() {

@Override
public void resourceChanged(LwM2mPath... paths) {
changed(new ObserveCompositeRelationFilter(paths));
}
});
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
* Achim Kraus (Bosch Software Innovations GmbH) - use ServerIdentity
* Achim Kraus (Bosch Software Innovations GmbH) - implement POST "/oid/iid"
* as UPDATE instance
* Michał Wadowski (Orange) - Add Observe-Composite feature.
*******************************************************************************/
package org.eclipse.leshan.client.californium.object;

Expand Down Expand Up @@ -153,9 +154,7 @@ public void handleGET(CoapExchange exchange) {
exchange.respond(toCoapResponseCode(response.getCode()), response.getErrorMessage());
return;
}
}

else {
} else {
if (identity.isLwm2mBootstrapServer()) {
// Manage Bootstrap Read Request
BootstrapReadRequest readRequest = new BootstrapReadRequest(requestedContentFormat, URI,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ public void addListener(ObjectsListener listener) {
listeners.add(listener);
}

public void removedListener(ObjectsListener listener) {
public void removeListener(ObjectsListener listener) {
listeners.remove(listener);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,17 @@
*
* Contributors:
* Sierra Wireless - initial API and implementation
* Michał Wadowski (Orange) - Add Observe-Composite feature.
*******************************************************************************/
package org.eclipse.leshan.client.resource;

import org.eclipse.leshan.client.resource.listener.ObjectsListener;
import org.eclipse.leshan.client.servers.ServerIdentity;
import org.eclipse.leshan.core.model.LwM2mModel;
import org.eclipse.leshan.core.request.ObserveCompositeRequest;
import org.eclipse.leshan.core.request.ReadCompositeRequest;
import org.eclipse.leshan.core.request.WriteCompositeRequest;
import org.eclipse.leshan.core.response.ObserveCompositeResponse;
import org.eclipse.leshan.core.response.ReadCompositeResponse;
import org.eclipse.leshan.core.response.WriteCompositeResponse;

Expand All @@ -32,4 +36,10 @@ public interface LwM2mRootEnabler {
WriteCompositeResponse write(ServerIdentity identity, WriteCompositeRequest request);

LwM2mModel getModel();

ObserveCompositeResponse observe(ServerIdentity identity, ObserveCompositeRequest request);

void addListener(ObjectsListener listener);

void removeListener(ObjectsListener listener);
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
*
* Contributors:
* Sierra Wireless - initial API and implementation
* Michał Wadowski (Orange) - Add Observe-Composite feature.
*******************************************************************************/
package org.eclipse.leshan.client.resource;

Expand All @@ -20,6 +21,7 @@
import java.util.Map;
import java.util.Map.Entry;

import org.eclipse.leshan.client.resource.listener.ObjectsListener;
import org.eclipse.leshan.client.servers.ServerIdentity;
import org.eclipse.leshan.core.model.LwM2mModel;
import org.eclipse.leshan.core.model.ObjectModel;
Expand All @@ -31,11 +33,14 @@
import org.eclipse.leshan.core.node.LwM2mResource;
import org.eclipse.leshan.core.node.LwM2mResourceInstance;
import org.eclipse.leshan.core.node.LwM2mSingleResource;
import org.eclipse.leshan.core.request.ObserveCompositeRequest;
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.WriteCompositeRequest;
import org.eclipse.leshan.core.request.WriteRequest;
import org.eclipse.leshan.core.request.WriteRequest.Mode;
import org.eclipse.leshan.core.response.ObserveCompositeResponse;
import org.eclipse.leshan.core.response.ReadCompositeResponse;
import org.eclipse.leshan.core.response.ReadResponse;
import org.eclipse.leshan.core.response.WriteCompositeResponse;
Expand All @@ -56,6 +61,16 @@ public RootEnabler(final LwM2mObjectTree tree) {
this.tree = tree;
}

@Override
public void addListener(ObjectsListener listener) {
tree.addListener(listener);
}

@Override
public void removeListener(ObjectsListener listener) {
tree.removeListener(listener);
}

@Override
public ReadCompositeResponse read(ServerIdentity identity, ReadCompositeRequest request) {
List<LwM2mPath> paths = request.getPaths();
Expand Down Expand Up @@ -193,6 +208,46 @@ public WriteCompositeResponse write(ServerIdentity identity, WriteCompositeReque

}

@Override
public synchronized ObserveCompositeResponse observe(ServerIdentity identity, ObserveCompositeRequest request) {
List<LwM2mPath> paths = request.getPaths();

// Read Nodes
Map<LwM2mPath, LwM2mNode> content = new HashMap<>();
boolean isEmpty = true; // true if don't succeed to read any of requested path
for (LwM2mPath path : paths) {
// Get corresponding object enabler
Integer objectId = path.getObjectId();
LwM2mObjectEnabler objectEnabler = tree.getObjectEnabler(objectId);

LwM2mNode node = null;
if (objectEnabler != null) {
ReadResponse response = objectEnabler.observe(identity,
new ObserveRequest(request.getResponseContentFormat(), path, request.getCoapRequest())
);
if (response.isSuccess()) {
node = response.getContent();
isEmpty = false;
} else {
LOG.debug("Server {} try to read node {} in a Observe-Composite Request {} but it failed for {} " +
"{}", identity, path, paths, response.getCode(), response.getErrorMessage()
);
}
} else {
LOG.debug("Server {} try to read node {} in a Observe-Composite Request {} but it failed because " +
"Object {} is not supported", identity, path, paths, objectId
);
}

content.put(path, node);
}
if (isEmpty) {
return ObserveCompositeResponse.notFound();
} else {
return ObserveCompositeResponse.success(content);
}
}

@Override
public LwM2mModel getModel() {
return tree.getModel();
Expand Down
Loading
0