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

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

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

【问题讨论】:

    标签: eclipse iot coap


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

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2022-09-25
          • 1970-01-01
          • 1970-01-01
          • 2018-09-03
          • 1970-01-01
          相关资源
          最近更新 更多