Californium CoAP 路径参数

Posted

技术标签:

【中文标题】Californium CoAP 路径参数【英文标题】:Californium CoAP path parameters 【发布时间】:2015-07-13 15:46:35 【问题描述】:

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

coap://localhost:5683/foo/fooID

【问题讨论】:

【参考方案1】:

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

如 JavaDocs 中所述

当请求到达服务器时,@link ServerMessageDeliverer 在资源树中搜索 目标资源。它通过查找沿着资源树向下移动 目标 URI 的一个元素一个接一个地调用 每个元素上的方法 @link #getChild(String)。是允许的 覆盖此方法并返回任意资源。这 允许例如使用通配符或委托请求服务 URI 到同一资源的任何子 URI。

所以基本上你必须重写 deliverRequest 并且可能在 org.eclipse.californium.core.server.ServerMessageDeliverer 中重写 findResource 方法,以便返回将处理请求的适当资源。此外,还需要分析 Exchange 请求 UriPath 作为资源句柄GET/PUT/POST/etc 的一部分以获取路径变量(这可以通过使用 CoapExchange.advanced().getRequest().getOptions() 来完成。 getUriPath())

根据 Californium 的源代码,应该很容易覆盖请求传递者的默认行为。

祝你好运!

【讨论】:

【参考方案2】:

您可以按照 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 ();

带步骤的完整答案代码在这里:Eclipse Californium CoAP wildcard as url path

【讨论】:

【参考方案3】:

就我目前所见,创建自定义ServerMessageDeliverer 似乎是更复杂的解决方案。实际上,正确的解决方案似乎是覆盖CoapResource#getChild(String),以便返回您希望与该名称关联的资源。 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 路径的每个部分都应返回与其父级相关的自己的资源,这使其成为每个定义的树结构,而不是简单地检查路径部分作为某种参数的平面列表。

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

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 的解决方案似乎有效,并且可能是某些场景的合适解决方案(例如,每个房子都有自己的服务器并且需要重定向请求),但对于一个相当简单的场景,它看起来不正确路要走。

【讨论】:

以上是关于Californium CoAP 路径参数的主要内容,如果未能解决你的问题,请参考以下文章

Californium 源码分析

CoAP协议学习——CoAP基础

coap杂谈

FastAPI上手指南(三):路径参数和查询参数

filter获得路径内置参数

为啥需要同时使用 oBIX 和 CoAP