5

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

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

3 回答 3

3

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

如 JavaDocs 中所述

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

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

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

祝你好运!

于 2015-11-02T21:56:48.447 回答
1

您可以按照亚历克斯的说法进行覆盖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

于 2016-05-20T00:48:17.743 回答
1

从我目前所见,创建自定义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可以动态解析可变子资源的实现来解决。下面的片段只是一个示例,当然这需要取决于房屋及其房间需要以某种方式注册的实际情况。

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

于 2017-03-17T12:21:56.200 回答