odl北向接口基本是通过yang文件来定义,而北向接收到请求先得经过转化成标准的yang模型的api,再调用md-sal相关接口

入口项目为netconf 项目的restconf-nb-rfc8040,之前老的restconf-nb-bierman02已经废弃

入口类为JSONRestconfServiceRfc8040Impl, 这个类作为总北向入口,通过ServiceWrapper 作为代理来分发Put,get,delete,patch,post

invokeRpc等操作

构造器

    @Injectpublic JSONRestconfServiceRfc8040Impl(final ServicesWrapper services,final DOMMountPointServiceHandler mountPointServiceHandler,final SchemaContextHandler schemaContextHandler) {this.services = services;this.mountPointServiceHandler = mountPointServiceHandler;this.schemaContextHandler = schemaContextHandler;}

invokeRpc

    @SuppressWarnings("checkstyle:IllegalCatch")@SuppressFBWarnings(value = "NP_NULL_PARAM_DEREF", justification = "Unrecognised NullableDecl")@Overridepublic Optional<String> invokeRpc(final String uriPath, final Optional<String> input)throws OperationFailedException {requireNonNull(uriPath, "uriPath can't be null");final String actualInput = input.isPresent() ? input.get() : null;LOG.debug("invokeRpc: uriPath: {}, input: {}", uriPath, actualInput);String output = null;try {# 将uripath转化成标准的yang模型相关的上下文final NormalizedNodeContext inputContext = toNormalizedNodeContext(uriPath, actualInput, true);LOG.debug("Parsed YangInstanceIdentifier: {}", inputContext.getInstanceIdentifierContext().getInstanceIdentifier());LOG.debug("Parsed NormalizedNode: {}", inputContext.getData());# 实际经过多层解析,会调用md-sal相关api来查找实际rpc地址,并调用 final NormalizedNodeContext outputContext =services.invokeRpc(uriPath, inputContext, new SimpleUriInfo(uriPath));if (outputContext.getData() != null) {output = toJson(outputContext);}} catch (RuntimeException | IOException e) {propagateExceptionAs(uriPath, e, "RPC");}return Optional.ofNullable(output);}

一.解析url

首先会先通过url找到对应yang schema然后转换成对应Yang对应的上下文, 再转化成标准Node 的上下文

    private NormalizedNodeContext toNormalizedNodeContext(final String uriPath, final @Nullable String payload,final boolean isPost) throws OperationFailedException {// 解析成yang模型上下文final InstanceIdentifierContext<?> instanceIdentifierContext = ParserIdentifier.toInstanceIdentifier(uriPath, schemaContextHandler.get(), Optional.of(mountPointServiceHandler.get()));if (payload == null) {return new NormalizedNodeContext(instanceIdentifierContext, null);}final InputStream entityStream = new ByteArrayInputStream(payload.getBytes(StandardCharsets.UTF_8));// 转换成标准请求的上下文实例return JsonNormalizedNodeBodyReader.readFrom(instanceIdentifierContext, entityStream, isPost);}

解析url,判断是否是mountPoint挂载点,如果是的话解析mountpoint yang id 和schemaContext,如果不是直接通过identifier 和schemaContext来解析生成yang模型标识,

schemaContext这个里面有所有yang文件定义解析出来的定义

    public static InstanceIdentifierContext<?> toInstanceIdentifier(final String identifier,final SchemaContext schemaContext,final Optional<DOMMountPointService> mountPointService) {if (identifier == null || !identifier.contains(RestconfConstants.MOUNT)) {return createIIdContext(schemaContext, identifier, null);}if (!mountPointService.isPresent()) {throw new RestconfDocumentedException("Mount point service is not available");}final Iterator<String> pathsIt = MP_SPLITTER.split(identifier).iterator();final String mountPointId = pathsIt.next();final YangInstanceIdentifier mountPath = IdentifierCodec.deserialize(mountPointId, schemaContext);final DOMMountPoint mountPoint = mountPointService.get().getMountPoint(mountPath).orElseThrow(() -> new RestconfDocumentedException("Mount point does not exist.",ErrorType.PROTOCOL, ErrorTag.DATA_MISSING));final SchemaContext mountSchemaContext = mountPoint.getSchemaContext();final String pathId = pathsIt.next().replaceFirst("/", "");return createIIdContext(mountSchemaContext, pathId, mountPoint);}

createIIdContext

    private static InstanceIdentifierContext<?> createIIdContext(final SchemaContext schemaContext, final String url,final @Nullable DOMMountPoint mountPoint) {final YangInstanceIdentifier urlPath = IdentifierCodec.deserialize(url, schemaContext);return new InstanceIdentifierContext<>(urlPath, getPathSchema(schemaContext, urlPath), mountPoint,schemaContext);}

IdentifierCodec.deserialize(url, schemaContext) 会查找schemaContext里面跟urlpath对应yang 具体定义,然后生成

YangInstanceIdentifier,感兴趣的伙伴可以伸入看一下源码,这里就不做过多介绍

解析出来YangInstanceIdentifier,下一步就是将utl 参数和input(http body 如果有的话)和YangInstanceIdentifier一一对应起来

返回一个NormalizedNodeContext

    public static NormalizedNodeContext readFrom(final InstanceIdentifierContext<?> path, final InputStream entityStream, final boolean isPost) {....final JsonParserStream jsonParser = JsonParserStream.create(writer,JSONCodecFactorySupplier.RFC7951.getShared(path.getSchemaContext()), parentSchema);final JsonReader reader = new JsonReader(new InputStreamReader(entityStream, StandardCharsets.UTF_8));jsonParser.parse(reader);NormalizedNode<?, ?> result = resultHolder.getResult();final List<YangInstanceIdentifier.PathArgument> iiToDataList = new ArrayList<>();InstanceIdentifierContext<? extends SchemaNode> newIIContext;while (result instanceof AugmentationNode || result instanceof ChoiceNode) {final Object childNode = ((DataContainerNode<?>) result).getValue().iterator().next();if (isPost) {iiToDataList.add(result.getIdentifier());}result = (NormalizedNode<?, ?>) childNode;}if (isPost) {if (result instanceof MapEntryNode) {iiToDataList.add(new YangInstanceIdentifier.NodeIdentifier(result.getNodeType()));iiToDataList.add(result.getIdentifier());} else {iiToDataList.add(result.getIdentifier());}} else {if (result instanceof MapNode) {result = Iterables.getOnlyElement(((MapNode) result).getValue());}}final YangInstanceIdentifier fullIIToData = YangInstanceIdentifier.create(Iterables.concat(path.getInstanceIdentifier().getPathArguments(), iiToDataList));newIIContext = new InstanceIdentifierContext<>(fullIIToData, path.getSchemaNode(), path.getMountPoint(),path.getSchemaContext());return new NormalizedNodeContext(newIIContext, result);}

二.调用实际rpc接口

解析完成后,会调用ServicesWrapper的对应put,get, post, patch, invokeRpc方法

下面为ServiceWrapper invokeRpc方法

    @Overridepublic NormalizedNodeContext invokeRpc(final String identifier, final NormalizedNodeContext payload,final UriInfo uriInfo) {return this.delegRestconfInvokeOpsService.invokeRpc(identifier, payload, uriInfo);}

而delegRestconfInvokeOpsService在ServiceWrapper构造器赋值

    public static ServicesWrapper newInstance(final SchemaContextHandler schemaCtxHandler,final DOMMountPointServiceHandler domMountPointServiceHandler,final TransactionChainHandler transactionChainHandler, final DOMDataBrokerHandler domDataBrokerHandler,final RpcServiceHandler rpcServiceHandler, final ActionServiceHandler actionServiceHandler,final NotificationServiceHandler notificationServiceHandler, final DOMSchemaService domSchemaService) {RestconfOperationsService restconfOpsService = new RestconfOperationsServiceImpl(schemaCtxHandler,domMountPointServiceHandler);final DOMYangTextSourceProvider yangTextSourceProvider = domSchemaService.getExtensions().getInstance(DOMYangTextSourceProvider.class);RestconfSchemaService restconfSchemaService = new RestconfSchemaServiceImpl(schemaCtxHandler,domMountPointServiceHandler, yangTextSourceProvider);RestconfStreamsSubscriptionService restconfSubscrService = new RestconfStreamsSubscriptionServiceImpl(domDataBrokerHandler, notificationServiceHandler, schemaCtxHandler, transactionChainHandler);RestconfDataService restconfDataService = new RestconfDataServiceImpl(schemaCtxHandler, transactionChainHandler,domMountPointServiceHandler, restconfSubscrService, actionServiceHandler);RestconfInvokeOperationsService restconfInvokeOpsService = new RestconfInvokeOperationsServiceImpl(rpcServiceHandler, schemaCtxHandler);RestconfService restconfService = new RestconfImpl(schemaCtxHandler);return new ServicesWrapper(restconfDataService, restconfInvokeOpsService, restconfSubscrService,restconfOpsService, restconfSchemaService, restconfService);}

ServiceWrapper几个成员变量作用

yang文件有关的查询接口

RestconfOperationsService 提供查询yang文件有哪些操作的接口

RestconfSchemaService 提供查询yang文件定义的接口

RestconfService 提供查询当前yang lib库版本的接口

datastore和rpc操作相关的接口

RestconfStreamsSubscriptionService 北向接口定阅

RestconfDataService 操作datastorestore接口

RestconfInvokeOperationsService operations相关操作接口

实际调用rpc

    public NormalizedNodeContext invokeRpc(final String identifier, final NormalizedNodeContext payload,final UriInfo uriInfo) {......if (mountPoint == null) {if (namespace.equals(RestconfStreamsConstants.SAL_REMOTE_NAMESPACE.getNamespace())) {if (identifier.contains(RestconfStreamsConstants.CREATE_DATA_SUBSCRIPTION)) {                   // 创建websocket监听流response = CreateStreamUtil.createDataChangeNotifiStream(payload, refSchemaCtx);} else {throw new RestconfDocumentedException("Not supported operation", ErrorType.RPC,ErrorTag.OPERATION_NOT_SUPPORTED);}} else {// 调用rpcresponse = RestconfInvokeOperationsUtil.invokeRpc(payload.getData(), schemaPath,this.rpcServiceHandler);}schemaContextRef = new SchemaContextRef(this.schemaContextHandler.get());} else {// 调用mountpoint rpcresponse = RestconfInvokeOperationsUtil.invokeRpcViaMountPoint(mountPoint, payload.getData(), schemaPath);schemaContextRef = new SchemaContextRef(mountPoint.getSchemaContext());}......}

到这里真正去调用md-sal来执行真正的rpc service

通过md-sal提供的DOMRpcService来调用

    public static DOMRpcResult invokeRpc(final NormalizedNode<?, ?> data, final SchemaPath schemaPath,final RpcServiceHandler rpcServiceHandler) {final DOMRpcService rpcService = rpcServiceHandler.get();if (rpcService == null) {throw new RestconfDocumentedException(Status.SERVICE_UNAVAILABLE);}final ListenableFuture<DOMRpcResult> rpc = rpcService.invokeRpc(schemaPath, data);return prepareResult(rpc);}

odl restconf大概执行流程就是这样,关于DOMRpcService怎样查找真正rpc 实现,以及某个rpc service如何注册到md-sal,下一期会讲一下

odl源码系列一restconf模块相关推荐

  1. 源码解读_入口开始解读Vue源码系列(二)——new Vue 的故事

    作者:muwoo 转发链接:https://github.com/muwoo/blogs/blob/master/src/Vue/2.md 目录 入口开始解读Vue源码系列(一)--造物创世 入口开始 ...

  2. [darknet源码系列-3] 在darknet中,如何根据解析出来的配置进行网络层构建

    [darknet源码系列-3] 在darknet中,如何根据解析出来的配置进行网络层构建 FesianXu 20201120 at UESTC 前言 笔者在[1,2]中已经对darknet如何进行配置 ...

  3. 大白话Vue源码系列(01):万事开头难

    阅读目录 Vue 的源码目录结构 预备知识 先捡软的捏 Angular 是 Google 亲儿子,React 是 Facebook 小正太,那咱为啥偏偏选择了 Vue 下手,一句话,Vue 是咱见过的 ...

  4. Android xUtils3源码解析之图片模块

    本文已授权微信公众号<非著名程序员>原创首发,转载请务必注明出处. xUtils3源码解析系列 一. Android xUtils3源码解析之网络模块 二. Android xUtils3 ...

  5. 源码系列第1弹 | 带你快速攻略Kafka源码之旅入门篇

    大家过年好,我是 华仔, 又跟大家见面了. 从今天开始我将为大家奉上 Kafka 源码剖析系列文章,正式开启 「Kafka的源码之旅」,跟我一起来掌握 Kafka 源码核心架构设计思想吧. 今天这篇我 ...

  6. Android xUtils3源码解析之注解模块

    本文已授权微信公众号<非著名程序员>原创首发,转载请务必注明出处. xUtils3源码解析系列 一. Android xUtils3源码解析之网络模块 二. Android xUtils3 ...

  7. Android xUtils3源码解析之数据库模块

    本文已授权微信公众号<非著名程序员>原创首发,转载请务必注明出处. xUtils3源码解析系列 一. Android xUtils3源码解析之网络模块 二. Android xUtils3 ...

  8. SpringMVC源码系列:HandlerMapping

    SpringMVC源码系列:HandlerMapping SpringMVC源码系列:AbstractHandlerMapping HandlerMapping接口是用来查找Handler的.在Spr ...

  9. elasticsearch源码分析之search模块(server端)

    elasticsearch源码分析之search模块(server端) 继续接着上一篇的来说啊,当client端将search的请求发送到某一个node之后,剩下的事情就是server端来处理了,具体 ...

  10. elasticsearch源码分析之search模块(client端)

    elasticsearch源码分析之search模块(client端) 注意,我这里所说的都是通过rest api来做的搜索,所以对于接收到请求的节点,我姑且将之称之为client端,其主要的功能我们 ...

最新文章

  1. git fetch和git pull
  2. Win64 驱动内核编程-17. MINIFILTER(文件保护)
  3. C语言 显示数组元素的值和地址
  4. 两经纬度之间的距离计算
  5. 利用java反射调用类的的私有方法
  6. Windows - Windows下安装MSI程序遇到2503和2502错误
  7. Win32 程序运行原理
  8. VGGNet原理和实现
  9. ConstraintLayout约束控件详解
  10. MySQL数据库regdate_第十五章 MySQL 数据库
  11. 中国音频放大器市场现状研究分析与发展前景分析报告
  12. js 监听浏览器刷新操作
  13. 各大主流编程语言简介
  14. 小程序——scroll-view 页面不滚动与隐藏导航条
  15. Espresso之RecyclerView
  16. java 图片背景色_java处理图片背景颜色的方法
  17. Remove Double Negative(去除双重否定)
  18. 轻量级程序编辑器的选择:EmEditor、Editplus等---Web开发系列之工具篇(一)
  19. 输入手机号获取验证码的注册页面,说出测试过程
  20. RNA-seq 详细教程:搞定count归一化(5)

热门文章

  1. 计算机固态加机械硬盘,在台式机中添加固态/机械硬盘驱动器,让我与这篇文章一起教你...
  2. Gym 100015A
  3. 使用工具清理Windows的winsxs目录
  4. 帝国cms灵动标签调用标题图片没有图片时让其显示默认图片的方法
  5. php 判断非负整数,PHP-检测负数
  6. html选项卡出现乱码,html乱码
  7. palantir_Palantir开源的两个库– Cinch和Sysmon
  8. 数据结构与算法——深入理解红-黑树!
  9. CMD命令Program Files问题
  10. matlab有LLG方程的解么,matlab在常微分方程数值解中应用.docx