I'm working on a CoAP application using Eclipse Californium and I need to pass parameters using the URL as we do in restful web services. Is it possible to do it in californium coap implementation, and if so please let me know how to do it. ex:
coap://localhost:5683/foo/{fooID}
The short answer is yes you can do it.
As stated in JavaDocs
- When a request arrives at the server, the {@link ServerMessageDeliverer} searches in the resource tree for the destination resource. It travels down the resource tree by looking for one element of the destination URI after another and by calling the method {@link #getChild(String)} on each element. It is allowed to override this method and to return an arbitrary resource. This allows for instance to serve URIs with wildcards or delegate requests to any sub-URI to the same resource.
So basically you have to override deliverRequest and maybe findResource methods in org.eclipse.californium.core.server.ServerMessageDeliverer in order to return appropriate resource which will handle the request. Also it will be required to analyse Exchange Request UriPath as a part of resource handleGET/PUT/POST/etc to fetch path variable (this can be done by using CoapExchange.advanced().getRequest().getOptions().getUriPath())
Based on the source code of Californium it should be pretty easy to override the default behaviour of a request deliverer.
Good luck with that!
From what I have seen so far, creating a custom ServerMessageDeliverer
seems to be the more complicated solution. Actually it looks like the correct solution is to override CoapResource#getChild(String)
so it returns the resource you want to be associated with that name. The ServerMessageDeliverer
looks to me more like the way to implement some sort of controller that delivers or distribute requests in a more complicated environment.
For the question where the last part of the URI is the parameter, the solution could look like this:
public class UriParameterResource extends CoapResource {
public UriParameterResource() {
super("foo");
}
@Override
public void handleGET(CoapExchange exchange) {
List<String> uriPath = exchange.getRequestOptions().getUriPath();
// check if there is a sub-resource given, and if so use it for processing
if (uriPath.size() > 1) {
exchange.respond("Process " + uriPath.get(1));
} else {
exchange.respond(ResponseCode.NOT_IMPLEMENTED);
}
}
@Override
public Resource getChild(String name) {
// even sub-resources will land in the GET of this resource
return this;
}
}
Regarding the the answer from @Copernic, I personally think it does not match the idea of REST. Each part of the URI path should return its own resource related to its parent, which makes it a tree structure per definition and not a flat list that simply inspects parts of the path as some sort of parameter.
IMHO even the sensors example could be resolved by using CoapResource
implementations where the variable child resource could be dynamically resolved. The snippet below is just an example, of course this would need to be dependent on the real situation where a house and its rooms would need to register somehow.
public class HousesResource extends CoapResource {
public HousesResource() {
super("houses");
}
@Override
public void handleGET(CoapExchange exchange) {
// could return a list of available houses
exchange.respond(ResponseCode.NOT_IMPLEMENTED);
}
@Override
public Resource getChild(String name) {
Resource child = super.getChild(name);
if (child == null) {
child = new HouseResource(name);
add(child);
}
return child;
}
class HouseResource extends CoapResource {
public HouseResource(String name) {
super(name);
add(new RoomsResource());
}
@Override
public void handleGET(CoapExchange exchange) {
exchange.respond(ResponseCode.NOT_IMPLEMENTED);
}
}
class RoomsResource extends CoapResource {
public RoomsResource() {
super("rooms");
}
@Override
public void handleGET(CoapExchange exchange) {
// could return a list of available rooms
exchange.respond(ResponseCode.NOT_IMPLEMENTED);
}
@Override
public Resource getChild(String name) {
Resource child = super.getChild(name);
if (child == null) {
child = new RoomResource(name);
add(child);
}
return child;
}
}
class RoomResource extends CoapResource {
public RoomResource(String roomName) {
super(roomName);
add(new SensorsResource());
}
@Override
public void handleGET(CoapExchange exchange) {
// could return a summary board about the room
exchange.respond(ResponseCode.NOT_IMPLEMENTED);
}
}
class SensorsResource extends CoapResource {
public SensorsResource() {
super("sensors");
add(new TemperatureResource());
}
@Override
public void handleGET(CoapExchange exchange) {
// this could return a list of registered sensors
exchange.respond(ResponseCode.NOT_IMPLEMENTED);
}
}
class TemperatureResource extends CoapResource {
public TemperatureResource() {
super("temperature");
}
@Override
public void handleGET(CoapExchange exchange) {
// as the structure is fixed we know that two levels up
// there is the room, and four levels up there is the house
String room = getParent().getParent().getName();
String house = getParent().getParent().getParent().getParent().getName();
exchange.respond("The temperature of the " + house + " in the " + room + " is : 25 degree");
}
}
}
In that example the resources are dynamically created if they did not exist before. This could be also exchanged with some lookup or register mechanism (e.g. a house is registered via PUT or PUSH).
Don't misunderstand me here. The solution by @Copernic seems to work and is probably a suitable solution for some scenarios (e.g. each house has its own server and the requests need to be redirected), but for a rather simple scenario it looks to me that it is not the correct way to go.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With