MS RFC 3:功能层插件架构

日期

2005/08/22

作者

贾尼阿维巴赫

联系

javerbach在extendtherach.com上

状态

采用

版本

MAPServer 4.8

抽象解

为以下对象实现虚拟表结构 layerObj 。该结构将包含所有层特定操作的函数指针。打开或首次访问该层时,将填充此结构。之后,所有后端格式特定的层操作都将通过此vtable进行,该vtable缓存在 layerObj 结构。

技术解决方案

所有文件名和编号都与发布的MapServer 4.6.0源代码相对应。

  1. 将新字段添加到 layerObj 。它将是指向vtable的指针,该vtable将包含该层的函数指针。

  2. 添加虚拟表体系结构

    当第一次访问层时,vtable将被初始化。vtable在创建时将被填充为假人,如果存在任何(例如不做任何事情)或默认返回错误,这些假人将执行可行的默认操作。

    2.1.标准函数,这些函数当前位于 maplayer.c

    2.1.1初始化信息

    int (*LayerInitItemInfo)(layerObj *layer);
    

    2.1.2.自由项信息

    void (*LayerFreeItemInfo)(layerObj *layer);
    

    2.1.3.正常开放

    int (*LayerOpen)(layerObj *layer);
    

    目前,有两个层接受的layeropen函数多于通用层arg:

    int msOGRLayerOpen(layerObj *layer,
                       const char *pszOverrideConnection);
    int msWFSLayerOpen(layerObj *lp,
                       const char *pszGMLFilename,
                       rectObj *defaultBBOX);
    

    但是,这些参数是从 msLayerOpen 使用 NULL Args,所以我认为为这个虚表函数建议的接口应该很好。

    2.1.4.ISOPEN

    int (*LayerIsOpen)(layerObj *layer);
    

    2.1.5。哪些形状

    int (*LayerWhichShapes)(layerObj *layer,
                            rectObj rect);
    

    2.1.6下一个形状

    int (*LayerNextShape)(layerObj *layer, shapeObj *shape);
    

    2.1.7.获得形状

    int (*LayerGetShape)(layerObj *layer, shapeObj *shape,
                         int tile, long record);
    

    2.1.8。层关闭

    int (*LayerClose)(layerObj *layer);
    

    2.1.9.层积物

    int (*LayerGetItems)(layerObj *layer);
    

    2.1.10。获得范围

    int (*LayerGetExtent)(layerObj *layer,
                          rectObj *extent);
    

    2.1.11.获取自动样式

    int (*LayerGetAutoStyle)(mapObj *map, layerObj *layer,
                             classObj *c, int tile,
                             long record);
    

    2.2.vtable的新功能和/或字段

    2.2.1闭连通

    此函数用于实际关闭连接,以防该层自己实现某种类型的连接池。如果Layer不使用任何连接池,则该函数应作为no-op实现。调用者应该首先调用Layer的“Close”函数,最后在最后调用 CloseConnection

    函数的签名是

    int (*LayerCloseConnection)(layerObj *layer);
    

    将调用此函数的主要位置是 mapfile.c: 4822

    void msCloseConnections(mapObj *map)
    

    此函数是必需的,因为例如 POSTGIS 目前正在实施这种使用模式 maplayer.c:599

     void msLayerClose(layerObj *layer)
     ...
    /*
     * Due to connection sharing, we need to close the results
     * and free the cursor, but not close the connection.
     */
     msPOSTGISLayerResultClose(layer);
    

    2.2.2.设置时间过滤器

    此函数用于为Layer创建时间过滤器。目前我们有三个特例 (maplayer.c: 1635 ):

    1. POSTGIS 有它自己的功能

    2. 带有反勾号分隔表达式的层

    3. 没有背景的图层

    其思想是提供一个通用的助手函数,

    int makeTimeFilter(layerObj *lp,
                       const char *timestring,
                       const char *timefield,
                       const bool bBackTicks)
    

    和实际层的 SetTimeFilter 可以使用上面的内容,或者实现一些完全不同的东西,如 POSTGIS 目前正在做的事情。

    层vtable函数的签名是

    int (*LayerSetTimeFilter)(layerObj *lp,
                              const char *timestring,
                              const char *timefield);
    

    2.3。要添加到vtable的额外功能

    2.3.1。FLTApplyFilterToLayer (mapogcfilter.c: 1084 )

    这是层的主过滤器界面。我们将提供两个helper函数,一个用于“SQL”情况,一个用于“非SQL”情况,并设置除 POSTGISORACLESPATIALOGR 直接调用此帮助函数的“非SQL”版本(if的Else-BRANCH)。

    ORACLESPATIALPOSTGISOGR 如果满足条件,可以使用“SQL”版本的帮助器函数(实际的IF-BRANCH),否则他们将使用非SQL版本的函数。

    2.3.2.layerobj->items allocation

    将有vtable函数可供分配 items 和初始化 numitems 。如果Layer对这些对象有一些特殊需求,它可以覆盖默认功能。

    函数的签名为:

    int (*CreateItems)(layerObj *)
    

    它进行分配并将numitems设置为正确的值。

    2.3.3。消息检查连接 (mapfile.c: 4779 )

    此接口已弃用。它仅从 msMYGISLayerOpen 。我们不会通过vtable提供此功能。

    2.4。内部层的接口功能

    我们必须添加一些新的接口函数来访问层。

    2.4.1内部层类型初始化功能接口

    我们需要一个每层类型的函数,当必须初始化层的vtable时将调用该函数。这些功能将

    int msXXXInitializeLayerVirtualTable(layerObj *)
    

    其中,xxx将是层的名称。当vtable未初始化并且第一次访问层时,随时调用此函数。

    2.4.2更改层连接类型的功能接口

    要更改层的连接类型,必须通过函数接口来完成。直接访问 connectiontype 不再支持字段。

    要更改连接类型并连接到新层,将有以下接口函数

    int msConnectLayer(int connectiontype,
                       const char *library_str)
    

    哪里 connectiontype 是新层的类型,并且 library_str 是将为该新层提供功能的库的名称。对于内部层类型,第二个参数被忽略。

  3. 删除不需要的接口

    弗兰克·沃默丹提议 [FW1] 中删除所有特定于层的接口函数 map.h

    我看到每个“内置”模块(如mapsde.c)都提供了注册功能(如“mssdeinitializelayervirtualtable”),这样就不需要在map.h中再出现任何特定于层类型的定义。

    FW1
    Frank Warmerdam on the mapserver-dev:
    Message-Id: <smtpd.490f.4303f2ee.d8246.1@mtaout-c.tc.umn.edu>
    Date: Wed, 17 Aug 2005 22:31:09 -0400
    Subject: Re: MapServer Plug-in Infastructure: RFC and PATCH

受影响的文件和对象

此建议将至少影响以下文件和对象:

  • map.h

    • layerObj 将包含新的字段。将会有一个新对象 vtableObjmap.h

  • maplayer.c

    • 各种更改,特定于层 switch -语句将消失,将添加vtable处理和层vtable初始化。

  • mapfile.c

    • 清洁 msCheckConnection

    • Vtable for msCloseConnection

  • mapogcfilter.c

    • 从删除层逻辑 FLTApplyFilterToLayer

  • mapXXX.c ,在哪里 XXX 是层的名称。

    • 添加新的初始化函数

    • 添加所有新接口函数

    • 修复现有接口函数(如果需要)/添加包装器 msOGRLayerOpenmsWFSLayerOpen

向后兼容性问题

这是二进制和源代码级别向后不兼容的更改。该提案将删除一些以前公开的功能,并在 layerObj 结构。

此建议不能向后兼容MapScript,它将中断直接更改的脚本 connectiontype 字段输入 layerObj

建议是向后兼容的映射文件。

实施问题

  • 最大的问题可能是作者忽略或错过了一些将在实施过程中出现的疏忽。但是,目前有一个外部插件架构的原型实现,它是基于本提案中提出的思想而工作的。因此,有一些实际的经验表明,这种架构更改是可行的。

  • 我还想指出的是,这个建议不会从MapServer中删除所有特定于层的代码,例如 WMFWMSGRATICULE 在不同的地方被用作特例。

臭虫识别码

臭虫1477

投票历史

Jani Averbach于2005年9月19日提出投票,结果为+4(3名无投票权成员)。

投票+1:Howard Butler、Frank Warmerdam、Yewondwossen Assefa、Daniel Morissette

提案通过并将继续推进。

开放性问题

  • 我们希望如何向层公开层的虚拟表。我们至少要走两条不同的路线:

    • 将其作为结构公开,层将直接访问结构的字段来填充vtable指针。

    • 将其公开为完全不透明的类型,将通过访问函数来设置vtable指针 setLayerOpenFPsetLayerCloseFP 诸若此类。

    第二个选项的先进之处在于,这样,如果我们重构更多的代码或者找到一些逻辑,我们可以很容易地向结构添加新的函数,而这些逻辑在这个建议中被忽略了。

  • 通过层API处理的栅格查询层支持有什么特殊问题吗?