Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Californium CoAP path parameters

Tags:

eclipse

iot

coap

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}
like image 475
yasithlokuge Avatar asked Jul 13 '15 15:07

yasithlokuge


2 Answers

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!

like image 145
alextunyk Avatar answered Oct 11 '22 02:10

alextunyk


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.

like image 34
Dirk Fauth Avatar answered Oct 11 '22 02:10

Dirk Fauth