Californium CoAP 路径参数

Californium CoAP path parameters

我正在使用 Eclipse Californium 开发 CoAP 应用程序,我需要使用 URL 传递参数,就像我们在 restful Web 服务中所做的那样。是否可以在 californium coap 实施中做到这一点,如果可以,请告诉我如何去做。 例如:

coap://localhost:5683/foo/{fooID}

简短的回答是你可以做到。

如 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.

所以基本上你必须覆盖 deliverRequest 并且也许 findResource org.eclipse.californium.core.server.ServerMessageDeliverer[=25 中的方法=] 以便 return 处理请求的适当资源。此外,还需要将 Exchange Request UriPath 作为资源 handleGET/PUT/POST/etc 的一部分进行分析以获取路径变量(这可以通过使用 CoapExchange.advanced().getRequest().getOptions( ).getUriPath())

基于 Californium 的源代码,覆盖请求传送器的默认行为应该非常容易。

祝你好运!

您可以按照 Alex 的说明覆盖 deliverRequest,但是我的方法是不预先注册资源树,我按资源注册资源而不维护层次结构。

public DynamicMessageDeliverer (List<ProxyRes> resources) {
    this.resources  = resources;
}

public void deliverRequest (final Exchange exchange) {
    Request request         = exchange.getRequest ();
    List<String> path       = request.getOptions ().getUriPath ();

    final Resource resource = registerResources (path);     
    if (resource != null) {
        executeResource (exchange, resource);           
    } else {
        exchange.sendResponse (new Response (ResponseCode.NOT_FOUND));
        throw new RuntimeException ("Did not find resource " + path.toString() + " requested by " + request.getSource()+":"+request.getSourcePort());
    }
}

private void executeResource (final Exchange exchange, final Resource resource) {
    // Get the executor and let it process the request
    Executor executor = resource.getExecutor ();
    if (executor != null) {
        exchange.setCustomExecutor ();
        executor.execute (new Runnable () {

            public void run () {
                resource.handleRequest (exchange);
            } 
        });
    } else {
        resource.handleRequest (exchange);
    }
}

private Resource registerResources (List<String> list) {
    LinkedList<String> path         = new LinkedList<String> (list);
    String flatRequestedEndpoint    = Arrays.toString (path.toArray ());
    LinkedList<String> wildcards    = new LinkedList <String> ();
    ProxyRes retainedResource       = null;

    for (ProxyRes proxyRes : resources) {
        String[] res = proxyRes.getPath ().replaceFirst ("/", "").split ("/");

        int length = res.length;
        if (length != path.size ()) {
            continue;
        }

        String flatResEndpoint = Arrays.toString (res);
        if (flatResEndpoint.equals (flatRequestedEndpoint)) {
            retainedResource = proxyRes;
            break;
        }

        boolean match = true;

        for (int i = 0; i < length; i ++) {
            String str = res[i];
            if (str.equals ("*")) {
                wildcards.add (path.get (i));
                continue;
            }

            if (!str.equals (path.get (i))) {
                match = false;
                break;
            }
        }

        if (!match) {
            wildcards.clear ();
            continue;
        }

        retainedResource = proxyRes;
        break;
    }

    if (retainedResource == null) {
        return null;
    }

    ((AbstractResource)retainedResource.getCoapRes ()).setWildcard (wildcards);
    return retainedResource.getCoapRes ();
}

带步骤的完整答案代码在这里:

据我目前所见,创建自定义 ServerMessageDeliverer 似乎是更复杂的解决方案。实际上,看起来正确的解决方案是覆盖 CoapResource#getChild(String),因此它 return 是您希望与该名称相关联的资源。 ServerMessageDeliverer 在我看来更像是在更复杂的环境中实现某种控制器来传递或分发请求的方法。

对于URI的最后一部分是参数的问题,解决方案可能是这样的:

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;
    }

}

关于@Copernic的回答,我个人认为不符合REST的思路。 URI 路径的每个部分都应该 return 自己的与其父级相关的资源,这使得它根据定义成为一个树结构,而不是一个简单地检查部分路径作为某种参数的平面列表。

恕我直言,甚至传感器示例也可以通过使用 CoapResource 实现来解决,其中可变子资源可以动态解析。下面的片段只是一个例子,当然这需要取决于房屋和房间需要以某种方式注册的实际情况。

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");
        }

    }
}

在该示例中,如果资源之前不存在,则会动态创建这些资源。这也可以与一些查找或注册机制交换(例如,通过 PUT 或 PUSH 注册房屋)。

不要误会我的意思。 @Copernic 的解决方案似乎有效,并且可能是某些场景的合适解决方案(例如,每个房子都有自己的服务器,需要重定向请求),但对于一个相当简单的场景,在我看来它是不正确的干得好。