Floodlight控制器实践——为模块加入Service和REST API,利用REST接口分析JSON输入并构造JSON输出

创建类

  1. 创建一个实现了IFloodlightModule和IOFMessageListener接口的类。其中IFloodlightModule表示这是一个floodlight模块。IOFMessageListener接口用于监听OF消息。

  2. 声明成员变量floodlightProvider。
    protected IFloodlightProviderService floodlightProvider;
    FloodlightProvider作为核心模块,负责将收到的OF包转换为一个个事件,而其他模块向FloodlightProvider注册,注册后成为service,然后就可以处理相应的事件。

  3. 在getModuleDependencies()中我们告诉module loader我们这个模块依赖于 IFloodlightProviderService.class
  4. 在init()中初始化
    floodlightProvider =context.getServiceImpl(IFloodlightProviderService.class);
  5. 在startUp()中告诉floodlightProvider我们想要处理packetIn消息:floodlightProvider.addOFMessageListener(OFType.PACKET_IN, this);

加入service

  1. 创建一个继承了IFloodlightService的XXXservice接口,在这个接口里定义要实现的功能,然后让这个类实现这个接口。
  2. 为了告诉 module system我们提供XXXService这个服务,我们修改 getModuleServices() 和 getServiceImpls() 方法。
    在getModuleServices()中:
    Collection> l
    l.add(XXXService.class);
    return l;

    在getServiceImpls()中:
    Map, IFloodlightService> m
    m.put(XXXService.class, this);
    return m;

    getServiceImpls() 告诉 module system我们就是提供service的类

为模块加入service后,模块就具有实现特定功能的方法,就能够对外提供特定的服务。

加入REST API

  1. 添加一个REST API服务的引用:
    声明变量protected IRestApiService restApi;
    IRestApiService是一个Floodlight服务,它依靠于Restlet。每一个模块只需要简单的注册IRestApiService就可以实现REST API。IRestApiService为我们处理底层的细节。
  2. 在getModuleDependencies()中我们告诉module loader我们这个模块依赖于 IRestApiService.class
    Collection> l
    l.add(IRestApiService.class);
    return l;
  3. 在init()中初始化
    restApi = context.getServiceImpl(IRestApiService.class);
  4. 为我们的模块定义想要的URI。定义我们实际想暴露的REST接口,只有这些URI才能被使用。否则Restlet无法向我们路由请求。第一步就是创建一个类实现Restlet的RestletRoutable接口,复写basePath() 和 getRestlet()两个方法。例如:
public class PktInHistoryWebRoutable implements RestletRoutable {
    @Override
    public Restlet getRestlet(Context context) {
        Router router = new Router(context);
        router.attach("/history/json", PktInHistoryResource.class);//attach将URI和PktInHistoryResource 类捆绑在了一起,第5步实现这个类
        return router;
    }

    @Override
    public String basePath() {
        return "/wm/pktinhistory";
    }

5.实现模块中所定义的URI。编写类实现上面getRestlet函数中所定义的所有URI。每一个类都会处理相应URI收到的http请求(GET、POST、PUT、DELETE)。所有的URI-handler类必须继承ServerResource,可以在其中随意定义方法,而不需要通过特殊方式复写任何方法。但是必须用http指令注释 (@Get, @Post, @Put, @Delete)处理这个http指令的方法。例如:

    public class PktInHistoryResource extends ServerResource {
    @Get("json")
    //@Get告诉编译器将此方法retrieve(),和任何发送到"/wm/pktinhistory/history/json"的HTTP GET消息相关
    public List retrieve() {
        IPktinHistoryService pihr = (IPktinHistoryService)getContext().getAttributes().get(IPktinHistoryService.class.getCanonicalName());
        //IPktinHistoryService是某个模块实现的service
        List l = new ArrayList();
        l.addAll(java.util.Arrays.asList(pihr.getBuffer().snapshot()));
        //IPktinHistoryService中定义了getBuffer这个方法
        return l;
    }
}

与JSON相关

  1. 分析JSON输入
    我们可以利用Jackson中的很多方法,来帮助分析任何作为HTTP PUT和POST输入的JSON。具体方法可以去学习Jackson。

  2. 构造JSON输出
    可以使用Jackson来将数据序列化(serialize)为REST格式。可以利用Jackson组装JSON消息,将其从HTTP命令处理函数(带有 @Get(“json”)注释)中返回。

举例说明:
首先看代码

@Get("json")
    public OFFlowModMap ListStaticFlowEntries() {
        ...
        return new OFFlowModMap(sfpService.getFlows());
        ...
}

这个方法说明收到HTTP GET消息后,URI-handler会返回OFFlowModMap对象。查看OFFlowModMap类:

@JsonSerialize(using=OFFlowModMapSerializer.class) 
public class OFFlowModMap {
          //详细代码省略
}

第一行注释中指定了一个类,把任何OFFlowModMap类型的对象转化为JSON。这个类就是OFFlowModMapSerializer,再来看OFFlowModMapSerializer类的代码:

public class OFFlowModMapSerializer extends JsonSerializer<OFFlowModMap> {
    @Override
    public void serialize(OFFlowModMap fmm, JsonGenerator jGen, SerializerProvider serializer)
            throws IOException, JsonProcessingException {
        //详细代码省略
        }
}

如上所示,要想构造JSON输出(即将某个类型的对象转换为JSON)
1。我们要么必须在我们的类中继承(extend)JsonSerializer;
2。或者像上面例子所示,想要将OFFlowModMap类型的对象转换为JSON的话,就使用 OFFlowModMapSerializer,它继承了JsonSerializer。(这个serializer是Floodlight自带的,专门用来将OFFlowModMap类型的对象转换为JSON)

3。另外一种方式是,你可以自己写一个自定义serializer类,然后将自定义的serializer加入到net.floodlightcontroller.web.serialzers包中,再通过修改相应的注释来达到。自定义serializer类中,必须 覆盖serialize()方法,这允许我们调用自定义的JSON serializer。例如你想针对IOFSwitch类型写一个serializer:

  • 首先自定义一个类继承JsonSerializer,并且将这个类加入到net.floodlightcontroller.web.serialzers包中
public class IOFSwitchJSONSerializer extends JsonSerializer<IOFSwitch> {
//覆盖(override)serialize方法
    public void serialize(IOFSwitch theSwitch, JsonGenerator jGen,
                          SerializerProvider arg2) throws IOException,
                                                  JsonProcessingException {  //具体代码省略                                        
                                                   }
  • 然后找到IOFSwitch类,修改IOFSwitch注释:

    @JsonSerialize(using=IOFSwitchJSONSerializer.class)
    public interface IOFSwitch extends IOFMessageWriter {
    }

    原注释本应该是@JsonSerialize(using=IOFSwitchSerializer.class)
    这里被我们用自定义的Serializer替换掉了。这样Jackson就知道要用我们自定义的IOFSwitchJSONSerializer类。

你可能感兴趣的:(SDN)