用于将设备集成到中间件框架中的代码生成的制作方法

文档序号:7719009阅读:215来源:国知局
专利名称:用于将设备集成到中间件框架中的代码生成的制作方法
背景技术
1.发明领域本发明涉及电子网络和消费电子产品领域,特别是涉及生成用于将设备集成到一个中间件框架中的程序代码,例如一个用于家庭自动化网络的中间件框架。
2.相关技术的描述随着数字电子设备,例如DTV、D-VHS、电话、音频播放机、静止和视频摄像机等等,变得越来越普遍,已经组成了一些联盟来定义中间件,以使这些设备易于控制和管理,这一般地是通过一个联网的环境来进行。HAVi、Jini和UPnP就是这种努力的几个例子。通常所知的“中间件”是一软件层,位于网络和应用之间,提供与网络上的设备相关的识别、鉴权、安全和控制等服务。
编写软件将一个设备集成到一个中间件框架中并不是一项简单的任务。除了实现主要功能的软件,数字设备还必须包括执行中间件所要求的功能和使得该设备功能可以被其他设备和/或软件通过网络接入访问和控制的软件。
多个中间件的存在使这个问题更加激化。如果设备生产商希望提供一个模板将设备集成到这样一个中间件中,生产商就需要提供多个模板,以及用来保证使用适当模板的相应方案。同样的情形,如果用户环境包括多个网络,每个网络有不同的中间件,那么用户就必须学习这些网络中每一个所要求的编程语言和中间件。
发明概要本发明的目的是提供一个方法和系统,方便产生将一个设备接口到网络所要求的程序代码。本发明的另一个目的是提供方便对网络上的设备控制所要求的代码。
这些目的和其他目的是通过提供一个中间件代码生成系统实现的,该系统生成用于将设备集成到网络中的程序代码。提供了多种工具和一个用户界面,使得用户可以创建包含生成中间件集成代码所必须信息的数据库。在一个优选实施方案中,代码生成系统被配置为方便用户修改生成的代码,特别是修改用于错误处理的代码。在优选实施方案中,代码生成系统还生成了一个示例测试应用程序,用于演示在一个应用中如何使用生成的集成代码。此外,在优选实施方案中,代码生成系统生成编译工具,例如Makefiles。
附图简述参考附图,更详细地和通过例子来解释本发明,其中

图1给出了根据本发明的中间件代码生成系统的实例框图。
图2给出了根据本发明的代码生成引擎的实例框图。
图3给出了根据本发明,保存在HAVi规范数据库功能控制模块(FCM)部件中的信息的实例框图,由代码生成系统用来生成FCM代码以方便将设备集成到HAVi中间件中。
图4给出了根据本发明,由代码生成系统使用的、保存在FCM部件的数据结构部件中的信息的实例框图。
图5给出了根据本发明,由中间件代码生成系统使用的、保存在FCM部件的服务应用编程接口(API)部件中的信息的实例框图。
图6给出了根据本发明,由中间件代码生成系统使用的、保存在FCM部件的事件部件中的信息的实例框图。
图7给出了根据本发明,由中间件代码生成系统使用的、保存在FCM部件的通知特性部件中的信息的实例框图。
图8给出了根据本发明,由中间件代码生成系统使用的、保存在专用链路数据库的专用链路部件中的信息的实例框图。
图9给出了根据本发明,由中间件代码生成系统使用的、保存在一个特定链路类型的链路状态响应部件中的信息的实例框图。
图10给出了根据本发明,在中间件代码生成系统中生成的代码的安装实例框图。
在所有附图中,相同的参考编号表示相似或对应的特征或功能。
发明详述图1给出了根据本发明的中间件代码生成系统100的实例框图。该代码生成系统100包含软件工具110、数据库120、125、130、135和包括设备中间件和集成代码的代码生成引擎150。它被配置为使得能够自动生成将一个电子设备集成到一个中间件框架例如HAVi网络中的软件。软件工具110提供一个用户界面,用于提供代码生成引擎150生成集成代码180模块所要求的信息120-135。接口设备110也用于控制代码生成过程,修改或升级该生成的代码。信息120-135已被说明为被组织成数据库的组合,其中术语数据库用来表示逻辑数据存储,其包含为了代码生成的目的已结构化的信息。该信息120-135包括一个规范数据库120、一个堆栈信息数据库125、一个模板数据库130和一个专用链路数据库135。虽然可以用一个真正的数据库,也可以使用内存(in-core)数据结构和文件。
在操作中,系统100的用户了解代码180为其生成的设备的特点和功能。在一个典型的代码生成过程中,用户用软件工具110指示代码180为其生成的设备的类型,以及用于与该设备通信的专用链路的类型。例如,用户可能指出该设备是一个VCR,它包括一个调谐器、一个磁带录像机和一个磁带播放机作为子单元。软件工具110也可以让用户指定中间件规范尚未覆盖的设备特征。在优选实施方案中,代码生成系统150生成用于该设备的集成代码模块180和一个示例测试应用程序185。集成代码180用来将一个设备集成到中间件环境,测试应用程序185用来演示如何在一个应用中使用集成代码180。代码生成引擎150也生成一个指针的列表,例如线路编号和文件名,它们提供了对生成代码180中推荐用户修改部分的索引。修改信息优选地通过用户修改指南145的形式提供,并且这些修改优选地定义为使得用户不需要知道中间件的知识。一般情况下,推荐的修改145包括错误处理代码。在代码180的适当位置有注释,向用户说明为什么和怎样修改代码180。在优选实施方案中,软件工具110也提供了一个界面为用户一个一个地展示代码180中的代码段,并在整个修改过程中指导用户。在优选实施方案中,代码生成系统100还配置为生成用于所生成代码的编译实用程序,例如Makefiles。
代码生成过程主要由中间件规范驱动。例如,用于HAVi录像机(VCR)功能控制模块(FCM)的代码生成由HAVi VCRFCM规范驱动。为了实现这一点,中间件规范中的相关信息被转换为代码生成容易使用的一个形式(120)。软件工具110也辅助从规范到规范数据库的转换。利用这些工具110,转换通过两个步骤进行。
步骤1用户引导的自动转换。软件工具110包括剖析器和格式化器,自动将规范中的信息转换到一个基于规范文本语法的规范数据库120。这个步骤生成大部分的所需信息。这些工具允许用户只选择规范中与他们的事务有关的部分。例如,如果公司只生产录像机和摄像机,就只要使用规范中与录像机和摄像机相关的部分。
步骤2用户扩充和规范。如果在规范中正式定义了语义信息,例如在UPnP的情况下,则信息被提取出来,并保存在规范数据库120中。但是,如果在规范中语义信息并没有正式表示,就像在HAVi的情况下,那么软件工具110允许用户根据规范定义的语义来扩充该规范数据库120。语义信息一般来自对设备的了解和对设备规范的理解。例如,播放命令将录像机从传送模式改变到值‘播放’,这个变化就触发了一个事件。用户可以使用工具来指定中间件规范没有包含的特征和专用链路信息。例如,如果摄像机有全球定位(GPS)能力,那么这个能力需要增加到规范数据库中,以生成合适的代码将这个能力输出到该中间件。在HAVi的情况下,这个能力可以建模为摄像机设备的一个FCM。用户也可以用工具修改模板130以影响将来的代码构造。
在下面的描述中,术语模块和方法(函数)遵照编程语言中定义的标准定义。在本领域中众所周知,不同的编程语言对操作组使用不同的术语面向对象语言,例如Java用“method”;过程语言,例如C、Pascal和Fortran用“procedure”、“subroutine”和“function”;如此等等。为了方便,术语“方法(函数)”在下文中用来区别“method”这个编程解释。术语代码段在本申请中代表一个或多个连续程序语句的序列。
目标代码180(要生成的代码)的结构和编码风格被设计为简化编码生成算法。目标代码模块180被设计为使得模块可以归类成较少的组,一个组中的模块结构遵循相似的模式。诸如生产商名称、设备类别和型号此类的参数可用于将所希望的代码模块与不相关的模块区分开来。例如,用户可以使用“飞利浦制造的录像机型号xyz”来指定要产生的代码模块。诸如代码类型(例如FCM或DCM)和使用的协议类型可用于进一步选择所希望的模块。例如,用户可能为一个使用1394上的AV/C协议作为其专用链路的VCR选择FCM生成器。类似的,模块中的方法(函数)和代码段也可以划分成多个组,一个组中的方法(函数)和代码段分别遵循相似的模式。如下面进一步讨论的,上面对目标代码180的设计使得利用代码生成引擎150中的代码生成器(图2中的252、254和256)和模板130就可以编码该目标代码180的结构。优选地,一组类似代码模块的骨架被封装在模块生成器254中。一个模块生成器254生成代码模块284。Client_Module_Generator(客户端模块生成器)和Sever_Module_Generator(服务器模块生成器)是模块生成器的例子,而Java类模块是代码模块的例子。一组类似方法(函数)的骨架被封装在方法生成器252中。方法生成器252生成方法282。Client_Asycronous_Method_Generator(客户端异步方法生成器)和Server_Operation_Method_Generator(服务器操作方法生成器)是方法生成器的例子。一组类似代码段的骨架被封装在代码段生成器256中。代码段的例子有告警代码段,包含代码段和错误处理代码段等等。图2中每个模板210、220,即方法模板210和代码段模板220标记不同的地方。代码段生成器256解析不同之处,以及生成连续语句序列286。Argument_List_Generator(自变量列表生成器)和Include_Block_Generator(包含块生成器)是代码生成器的例子。
一组语句的模式和一组简单方法(函数)的模式被封装在模板130中。模板130包含代码段的固定部分和根据所选的编程语言比如C语言的可变部分。模板的可变部分在代码生成的时候解析,以使该模板130变成代码180的有效代码段。一个代码段生成器一般包含一个或多个模板。模板可用来表示简单方法(函数),假设方法(函数)的代码可通过解析模板变量生成。
在下面的描述中,术语树、子树、节点、叶、父和子遵循在计算机科学中使用的标准定义。优选地,代码生成引擎150配置为通过穿越一个代码生成节点树来生成代码。一般情况下,树的根部指示要为一个单独的程序生成的所有模块,这样的程序比如是FCM服务器程序或FCM客户端程序。该根的孩子是用于该程序所要求的代码模块的模块生成器。一个模块生成器节点是一个子树的根,该子树生成该模块的部件;该子树中的节点就是方法生成器和代码段生成器。类似的,代表方法生成器的节点就是获取方法结构的子树的根;子树中的节点就是其他方法生成器和代码段生成器。程序树的一个叶子包含一个代码段生成器。为保证代码生成过程的终止,子树的根不能作为同一子树的任意节点出现。例如,模块生成器不能作为它本身子树的非根节点出现,而方法生成器不能作为它本身子树的内部节点出现。
如上面所指出的,目标代码180由代码生成器252、254和256生成。每个代码生成器知道怎样生成目标代码180的一个特定部分,例如一个模块、一个函数或一个代码段。在代码生成过程中,生成器252、254或256利用用户输入,比如设备的类别、型号和生产商,从数据库120、125和135找到信息,并用这些信息生成它所负责的代码部分。当生成器遇到一个模板130,它就用来自数据库120、125和135的知识解析该模板130中的可变部分,以及将模板130变成所希望的代码。当一个父代码生成器在穿越树的时候遇到一个子代码生成器时,父代码生成器在继续它自己的代码生成之前,调用子代码生成器来生成代码中相应的部分。例如,当一个模块生成器遇到一个方法生成器时,模块生成器就调用方法生成器来生成所希望的方法。在该方法生成之后,父模块生成器再继续它的工作。类似的,当一个方法生成器遇到一个子方法生成器或一个子代码段生成器,它就调用该子代码生成器,并且只有在该子生成器完成后它才再继续自己的工作。
在本发明的优选实施方案中,如图1所示,提供了代码高速缓存器155允许用户保存生成的模块和方法(函数)用于将来的代码生成。高速缓存器155包含指向代码的指针(比如文件名)和代码生成的条件。这些条件包括所有数据库的版本信息和通过用户界面输入的用户说明。使用代码高速缓存器155的典型场合是当用户修改部分设备规范120,例如,增加一个新的特征,并希望重新生成代码时。本发明优选实施方案中的代码生成引擎150配置为只对受影响部分重新生成新的代码180,并且对不受影响的部分使用高速缓存器155的代码。
图1中堆栈信息数据库125包含代码生成所需的中间件堆栈实现信息。数据库125也明了堆栈实现的版本。数据库125信息中的一个主要部分是在堆栈中声明的用户定义类型和包含在声明中的文件名。这个信息用来生成包含文件。
图1中模板数据库130包含代码生成引擎150所使用的所有模板。数据库130的一个优选实施方案将每个模板保存为一个文件,放在一个定义好的目录下。模板的名称明显地指出了在代码生成中该模板可以使用的位置。数据库130也明了模板的版本。
图1中新代码信息数据库140包含关于已经被代码生成系统生成的代码的信息。例如,它包含在已生成代码中声明的用户定义类型和包含在声明中的文件名。这个信息用来生成包含文件。
图1中的规范数据库120将中间件规范中的语法和语义信息编码成代码生成引擎150可以有效使用以生成该设备-中间件集成代码180的形式。规范数据库120也保留版本信息。数据库120的版本一般和对应的中间件规范的版本相匹配。但是,如果用户为了支持新的特征而修改数据库120,那么该数据库120就提供对它原始的版本编号的扩展。该版本信息用来从代码高速缓存器155中选取合适的代码。
数据库120提供了产生集成代码180中专门用于特定类型设备的部分所要求的信息。例如,在HAVi实施方案中,数据库120包括产生用于设备控制模块(DCM)和功能控制模块(FCM)的集成代码所要求的信息。
图3到7给出了为每个FCM类型保存的信息的例子。在这些例子中,该信息被组织为树。
图3给出了供根据本发明的中间件代码生成引擎150使用的一个功能控制模块(FCM)数据库310的上面三级的实例框图。第二级包括一个总FCM规范节点322和由FCM类型索引的规范信息节点,FCM类型比如像录像机324、调谐器326等等。总FCM规范322包括可用于所有FCM的信息和其他只应用于特定类型设备的规范。第三级给出由第二级中父节点保存的信息类型。例如,如图3所示,对于录像机节点324,第三级包括数据结构331、应用程序接口(API)332、事件333和通知特性334节点。第三级也包括交互节点335,其记录与这个FCM类型324交互的HAVi管理器(例如资源管理器、流管理器等)。模块高速缓存器节点336明了已由用户保存的模块代码284的版本,也记录产生代码模块的条件,因此可以获得匹配所要求的创建条件的代码。这些条件包括用户修改的最近时间和产生代码中使用的所有数据库和模板的版本。
在HAVi情况下,一个DCM包含一个或多个FCM。根据本发明,在一个根节点DCM(没有给出)下的结构与图3中FCM310下的结构相似,只是通知特性节点334由一个FCM节点(没有给出)所代替。FCM部分明了包含在设备控制模块(对应包含特定功能的设备)中的功能控制模块(例如录音机、播放机、调谐器)。
图4给出了图3的数据结构数据库331中数据结构条目331’的实例框图,它由根据本发明的、图1的中间件代码生成引擎150使用。为了表示的方便,符号(’)用在一个参考编号后表示具有相同参考编号数据项的例子。数据结构331’记录为一个特定FCM类型,例如录像机类型,而定义的数据结构。图4给出了每个数据结构的信息411-424,用于产生对于FCM类型特定的包含文件和声明语句,和产生检查数据有效性的代码185。每个数据结构331’有一个关联的数据类型411和识别名412。在优选实施方案中,数据结构331’还以具有特定性质418和可选的,一个预定义的法定值集合416为特征。每个数据结构331’包含一个或多个成员414,每个成员有一个给定的类型422和识别名424。
为了使中间件能够控制一个FCM,FCM代码将服务输出给中间件。例如,一个VCR FCM向中间件输出播放、记录、倒带等服务。为了输出每个服务,由中间件规范定义了一个API,以及为了代码产生的目的,规范数据库120记录下这个API。图5给出了根据本发明,与图3中API块332相对应的一个服务API条目332’的实例框图,它由图1中的中间件代码生成引擎150来使用。图5给出了为每个服务API332’保存的信息511-524实例。此信息用来生成与不同模块中的服务相关的方法(函数)。例如,一个VCR FCM模块包含方法(函数)“播放”、“记录”、“倒带”、“前进”等。
提供者条目511指示这个服务是否应由服务器或客户端提供。
返回类型条目512给出由服务(即输出服务的方法)332’返回的项目的数据类型。
名称务目513记录服务332’,如播放、记录或快进等的名称。
自变量条目514记录应该传递给服务332’或从它返回的参数。输入/输出条目522指示参数是否是只读(输入)、只写(输出)或可读可写(既输入也输出),而数据结构条目524指示每个自变量的结构。
性质条目515记录与服务有关的信息,例如,服务是否需要通过专用链路与物理设备通信,并且该条目被用于生成对专用链路的接口代码180(图1中)。
副作用条目516指示其值被API332’的激活(如果有的话)所改变的数据结构326。副作用条目516也记录改变后每个数据结构新的值。一般情况下,这些数据结构是前面提到的图3中FCM310的数据结构条目331’的子集。副作用516信息用来生成所生成代码180中的通知代码。
异常条目517指示与该服务相关的异常和错误条件。虽然可以生成缺省代码来处理异常和错误,但本发明优选实施方案中的代码生成系统100推荐用户修改这些代码部分,正如上面所讨论的。
有效调用者条目518指示可以调用此API332’的有效软件元素类型,并用来生成要求检查调用者身份的代码180。
方法高速缓存条目519跟踪用户为服务332’所保存的方法(函数)。除了修改时间和版本信息外,方法高速缓存条目519还记录方法(函数)所属的模块类型。
图6给出了图3的事件条目333中一个事件333’的实例框图,它由根据本发明的、图1的中间件代码生成引擎150使用。事件条目333’记录图3的FCM类型310应被调用的事件。图6给出了为每个事件333’保存的信息。此信息用于生成与事件相关的方法(函数)和代码段。图6中各个节点612、613、614、619、622、624的含义与图5中各个节点512、513、514、519、522和524的含义相同,即是返回类型、名称、变量、输入/输出、数据结构和方法高速缓存器、图7给出了图3的通知特性条目334中通知特性334’的实例框图,它由根据本发明的、图1的中间件代码生成引擎150使用。通知特性334’记录触发一个FCM以当该特征改变值时发送通知的特性。数据结构724和输入/输出722条目定义该特性,如上面关于条目524和522所讨论的。通知特性信息334用来生成图2中与通知相关的方法(函数)282和代码段284。
图8给出了图1的专用链路条目135中专用链路135’的实例框图,它由根据本发明的中间件代码生成引擎150使用。专用链路条目135记录与代码生成有关的生产商特定的信息,特别是关于每个专用链路的信息。图8给出了为一个链路维持的信息实例。操作映射821给出了专用链路定义的操作和中间件规范定义的名称间的对应性,用于生成将来自中间件的命令翻译为物理设备相应操作的代码180。链路状态响应823记录来自该链路的响应的名称,且被用来生成处理该响应的代码180。
图9给出了由根据本发明的图1的中间件代码生成引擎150使用的、链路状态响应条目823的链路状态响应823’的实例框图,还给出了为每个链路状态响应保存的信息。名称条目922是响应的名称,例如SUCCESS(成功)或NOT_IMPLEMENTED(未完成)。事件触发器条目924指示应该是响应处理一部分的事件。为每个事件924保存的信息包括事件名称931、触发操作932、状态数据应从其读取的服务器933,即目标服务器、应采取的动作(读或寄送)934和如果事件要被寄送则为参数值935。方法高速缓存条目926跟踪用户保存的用于每个链路状态响应832’的方法(函数)。
图10给出了在根据本发明的中间件代码生成系统100中生成的代码180、185安装的实例框图,用一个简化的HAVi视图作为例子。一个设备1050被说明为被配置为允许通过与两个HAVi节点1010、1020的1394堆栈1040的IEEE-1394接口来控制其设备的主要功能1052。HAVi节点1010、1020是包含HAVi软件元素1012、HAVi消息传递系统1030和1394堆栈1040的软件容器。在这个例子中,假设测试应用程序185在节点1010上提供,设备FCM在节点1020上提供。本例中节点1010上的应用程序185通过节点1010上的FCM客户端代码180a与节点1010上的FCM服务器代码180b交互。FCM客户端代码代表应用程序185动作,它通过HAVi消息传递系统和1394堆栈与1020上的FCM服务器代码通信。FCM服务器1020然后在应用程序185的控制下与设备1050交互。
上面只是给出了本发明的主要原理。因此可以理解,本领域的技术人员可以设计不同的装置,虽然在这里没有明确地描述或展示,但是体现了本发明的主要原理,因此也在下面的权利要求的精神和范围之内。
权利要求
1.一种程序生成系统,包含一个配置为基于中间件规范包含中间件信息的规范数据库,一个中间件代码生成引擎,它操作地与该规范数据库相耦合,被配置为基于该中间件信息来产生中间件集成代码。
2.如权利要求1的程序生成系统,进一步包括一个模板数据库,它被配置为包含一个或多个模板,并且其中该中间件代码生成引擎进一步配置为使用来自该中间件信息的数据、通过该一个或多个模板的例示而产生该中间件集成代码。
3.如权利要求1的程序生成系统,进一步包括一个配置为包含专用于一个特定链路类型的链路信息的专用链路数据库,该链路信息包含在用于该特定链路类型的链路操作名称与包含在中间件信息中的中间件操作名称之间的映射,并且其中上述中间件代码生成引擎进一步配置为基于该链路信息而产生该中间件集成代码。
4.如权利要求1的程序生成系统,其中该中间件代码生成引擎也配置为基于该中间件信息而产生示例测试应用程序代码。
5.如权利要求1的程序生成系统,进一步包括代码高速缓存器,它操作地与该中间件代码生成引擎耦合,被配置为存储至少一部分中间件集成代码以便随后重用。
6.如权利要求1的程序生成系统,其中中间件代码生成引擎也配置为生成指导信息,方便用户修改至少一部分中间件集成代码。
7.如权利要求1的程序生成系统,其中中间件代码生成引擎包括至少以下之一一个配置为生成代码模块的模块生成器,一个配置为生成方法代码的方法生成器,和一个配置为生成代码语句的代码段生成器。
8.如权利要求7的程序生成系统,其中该方法生成器和代码段生成器中的至少一个被配置为分别根据一方法模板和代码段模板来生成方法代码和代码语句。
9.如权利要求1的程序生成系统,其中上述中间件信息包含接口信息,用于将一个应用接口到对应该中间件信息的、通过一个网络接受控制的设备的一个或多个功能。
10.如权利要求1的程序生成系统,进一步包括一个包括方便创建规范数据库的工具的用户界面系统。
11.一种程序生成的方法,包括访问一个配置为基于中间件规范包含中间件信息的规范数据库,基于该中间件信息,生成中间件集成代码。
12.如权利要求11的方法,进一步包括访问一个配置为包含一个或多个模板的模板数据库,并且其中生成该中间件集成代码进一步包括利用来自该中间件信息的数据,例示该一个或多个模板。
13.如权利要求11的方法,进一步包括访问一个配置为包含专用于一个特定链路类型的链路信息的专用链路数据库,该链路信息包含在用于该特定链路类型的链路操作名称与包含在该中间件信息中的中间件操作名称之间的映射,并且其中生成上述中间件代码进一步包含基于该链路信息而生成该中间件集成代码。
14.如权利要求11的方法,进一步包括根据该中间件信息,生成示例测试应用程序代码。
15.如权利要求11的方法,进一步包括存储至少一部分中间件集成代码以便随后重用。
16.如权利要求11的方法,进一步包括提供方便用户修改至少一部分中间件集成代码的指导信息。
17.如权利要求11的方法,其中生成该中间件集成代码包括生成代码模块,生成方法代码,和生成代码语句。
18.如权利要求17的方法,其中生成方法代码和代码语句中的至少一个包括分别访问一个对应的方法模板和代码段模板。
19.如权利要求11的方法,进一步包括提供接口信息,用于将一个应用接口到对应该中间件信息的、通过一个网络接受控制的设备的一个或多个功能。
20.如权利要求11的方法,进一步包括提供方便创建该规范数据库的工具。
全文摘要
中间件代码生成系统生成用于将一个设备集成到一个网络中的程序代码。给出了多种工具和一个用户界面来创建包含生成中间件集成代码所必需的信息的数据库。代码生成系统被配置为便于用户修改已生成的代码,以及特别是修改用于错误处理的代码。在一个优选实施方案中,该代码生成系统也生成了一个示例测试应用程序,用于演示在一个应用中如何使用生成的集成代码。
文档编号H04L12/28GK1620646SQ02801734
公开日2005年5月25日 申请日期2002年5月17日 优先权日2001年5月18日
发明者D·Y·程 申请人:皇家菲利浦电子有限公司
网友询问留言 已有0条留言
  • 还没有人留言评论。精彩留言会获得点赞!
1