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 路径参数的主要内容,如果未能解决你的问题,请参考以下文章