MS RFC: Layer Plug-in Architecture

Paul Spencer pspencer at DMSOLUTIONS.CA
Tue Sep 6 17:15:49 EDT 2005


Jani,

what will happen to mapscript code that changes the layer type on the 
fly?  What about dynamically created layers?

Paul

Jani Averbach wrote:
> Hello,
> 
> Here is my updated proposal for the plug-in architecture.
> 
> One note: I kept the CloseConnection and CloseLayer because POSTGIS
> needs both of them and it is already using new mappool API. So, if it
> is possible to remove this extra logic, it would be nice if someone
> who knows POSTGIS could comment. Otherwise, I think we should
> implement both of CloseConnection and CloseLayer.
> 
> BR, Jani
> 
> 
> ==============================================
> MS RFC: Layer Plug-in Architecture
> ==============================================
> :Date:  2005/08/22
> :Author: Jani Averbach
> :Contact: javerbach at extendthereach.com
> :Last Edited: $Date: 2005-09-06 14:36:04 -0600 (Tue, 06 Sep 2005) $
> :Status: draft
> 
> 
> **Description:** Change current layer infrastructure from switch based
> static solution to the virtual table based dynamic solution.  The main
> objectives for this proposal are cleaning and simplifying code and
> provide a robust architecture to implement dynamic plug-in API for
> external layer providers.
> 
> 
> Abstract Solution
> -----------------
> 
> Implement a virtual table structure for ``layerObj``. This structure
> will contain function pointers for all layer specific operations.
> This structure will be populated when the layer is created or when it
> is opened. After that all back-end format specific layer operations
> will happen through this vtable which is cached in the ``layerObj``
> struct.
> 
> 
> Technical Solution
> ------------------
> 
> All file names and numbers are against released MapServer 4.6.0 source
> code.
> 
> 1. Add new field to the ``layerObj``. It will be pointer to the vtable,
>    which will contain function pointers for this layer.
> 
> 2. Add the virtual table architecture
> 
>    The vtable will be initialized when the layerObj is created and
>    parsed, this will happen in the function (mapfile.c):
>    ::
> 
>       int loadLayer(layerObj *layer, mapObj *map)
> 
>    The vtable will be populated with dummies when it is created and
>    these dummies will implement feasible default actions if there are
>    any (e.g. do nothing) or return error by default.
> 
> 
>    2.1. Standard functions which are found currently from ``maplayer.c``
> 
>         2.1.1. InitItemInfo
>                ::
> 
>                  int (*LayerInitItemInfo)(layerObj *layer);
>                              
> 
>         2.1.2. FreeItemInfo
>                ::
> 
>                   void (*LayerFreeItemInfo)(layerObj *layer);
> 
> 
>         2.1.3. Open
>                ::
> 
>                   int (*LayerOpen)(layerObj *layer);
> 
>                Currently there are two layers which accept more than
>                the generic layer arg for LayerOpen function:
>                :: 
> 
>                   int msOGRLayerOpen(layerObj *layer, 
>                                      const char *pszOverrideConnection);
>                   int msWFSLayerOpen(layerObj *lp, 
>                                      const char *pszGMLFilename, 
>                                      rectObj *defaultBBOX);
>                                      
>                However, these are called from ``msLayerOpen`` with
>                ``NULL`` args, so I think that proposed interface for
>                this virtual table function should be fine.
> 
> 
>         2.1.4. IsOpen
>                ::
> 
>                   int (*LayerIsOpen)(layerObj *layer);
> 
> 
>         2.1.5. WhichShapes
>                ::
> 
>                   int (*LayerWhichShapes)(layerObj *layer, 
>                                             rectObj rect);
> 
>         2.1.6. NextShape
>                ::
> 
>                   int (*LayerNextShape)(layerObj *layer, shapeObj *shape);
> 
> 
>         2.1.7. GetShape
>                ::
> 
>                   int (*LayerGetShape)(layerObj *layer, shapeObj *shape, 
>                                          int tile, long record);
> 
> 
>         2.1.8. LayerClose
>                ::
> 
>                   int (*LayerClose)(layerObj *layer);
> 
> 
>         2.1.9. LayerGetItems
>                ::
> 
>                   int (*LayerGetItems)(layerObj *layer);
> 
> 
>         2.1.10. GetExtent
>                 ::
> 
>                    int (*LayerGetExtent)(layerObj *layer, 
>                                            rectObj *extent);
> 
> 
>         2.1.11. GetAutoStyle
>                 ::
> 
>                    int (*LayerGetAutoStyle)(mapObj *map, layerObj *layer,
>                                               classObj *c, int tile, 
>                                               long record);
>                 
> 
> 
>    2.2.  New functions and/or fields for vtable
> 
>          2.2.1. CloseConnection
> 
>                 This function is used to actually close the
>                 connection, in case that layer implements some kind of
>                 connection pooling by its own.  If layer doesn't use
>                 any connection pooling, this function should be
>                 implemented as no-op. Caller should first call layer's
>                 "close" function, and finally at the very end
>                 ``CloseConnection``.
> 
>                 The signature of function is
>                 ::
> 
>                    int (*LayerCloseConnection)(layerObj *layer);
> 
> 
>                 And the main place where this function will be called,
>                 is ``mapfile.c: 4822``
>                 ::
>                    
>                    void msCloseConnections(mapObj *map)
> 
>                 This function is needed because e.g. ``POSTGIS`` is
>                 implementing this usage pattern at the moment
>                 ``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. SetTimeFilter
> 
>                 This function is used to create a time filter for
>                 layer. At the moment we have three special cases
>                 (``maplayer.c: 1635``):
> 
>                 1. ``POSTGIS`` with it's own function
>                 2. Layers with backticks delimited expressions
>                 3. Layers without backticks
> 
>                 The idea is provide a generic helper function,
>                 ::
> 
>                    int makeTimeFilter(layerObj *lp,
>                                       const char *timestring,
>                                       const char *timefield,
>                                       const bool bBackTicks)
> 
>                 And the actual layer's ``SetTimeFilter`` could use the
>                 above, or implement something totally different as
>                 ``POSTGIS`` is doing at the moment.
> 
>                 The signature for layer's vtable function is
>                 ::
> 
>                    int (*LayerSetTimeFilter)(layerObj *lp, 
>                                                const char *timestring, 
>                                                const char *timefield);
> 
> 
> 
>    2.3. Extra functions to add to the vtable
> 
>         2.3.1. FLTApplyFilterToLayer (``mapogcfilter.c: 1084``)
> 
>                This is the main filter interface for layers.  We will
>                provide two helper functions, one for "SQL" case and
>                the another for "non-SQL" case, and set all layers,
>                except ``POSTGIS``, ``ORACLESPATIAL`` and ``OGR`` to
>                call directly this "non-SQL" version of this helper
>                function (else-branch of if).
> 
>                ``ORACLESPATIAL``, ``POSTGIS`` and ``ORG`` could use
>                "SQL" version of the helper function (actual if-branch)
>                if the conditions for this are met, otherwise they will
>                use Non-SQL version of the function.
> 
> 
>         2.3.2. layerObj->items allocation
> 
>                There will be vtable function for allocation ``items`` and
>                initialization for ``numitems``. If layer has some
>                special needs for these objects it can override default
>                function.
> 
>                The signature for function will be:
>                ::
> 
>                   int (*CreateItems)(layerObj *) 
> 
>                which does the allocation and set numitems to correct
>                value.
> 
>         2.3.3. msCheckConnection (``mapfile.c: 4779``)
> 
>                This API is deprecated. It is called only from
>                ``msMYGISLayerOpen``.  We will not provide this
>                functionality through vtable.
> 
> 
>    2.4. Interface functions for internal layers
> 
>         We have to add at least some new interface functions for
>         internal layers, e.g. ``msXXXInitializeLayerVirtualTable``,
>         where ``XXX`` is the layer's name.
>         
> 
> 
> 3. Remove unwanted interfaces
>    
>    Frank Warmerdam proposed [FW1]_ that we remove all layer specific
>    interface functions from ``map.h``.
> 
>       I see each "built-in" module such as mapsde.c providing a
>       registration function such as "msSDEInitializeLayerVirtualTable"
>       so that none of the layer type specific definitions need to
>       appear in map.h any more.
> 
>    .. [FW1] 
>       | ``Frank Warmerdam on the mapserver-dev:``
>       | ``Message-Id: <smtpd.490f.4303f2ee.d8246.1 at mtaout-c.tc.umn.edu>``
>       | ``Date:       Wed, 17 Aug 2005 22:31:09 -0400``
>       | ``Subject:    Re: Mapserver Plug-in Infastructure: RFC and PATCH``
> 
> 
> 
> 
> Files and objects affected
> --------------------------
> 
> This proposal will affect at least following files and objects:
> 
> * ``map.h``
> 
>   * ``layerObj`` will contain new fields. There will be a new
>     object ``vtableObj`` in the ``map.h``.
> 
> 
> * ``maplayer.c`` 
> 
>   * Various changes, layer specific ``switch``-statements will go
>     away, vtable handling and layers vtable initialization will be
>     added.
> 
> 
> * ``mapfile.c``
> 
>   * mapfile writing will change slightly, no more ``if-else``
>     structure for connectiontype strings.
>   * Cleaning of  ``msCheckConnection``
>   * Vtable for ``msCloseConnection``
> 
> 
> * ``mapogcfilter.c``
> 
>   * Remove layer-logic from ``FLTApplyFilterToLayer``
> 
> 
> * ``mapXXX.c``, where ``XXX`` is the name of layer.
> 
>   * Add new initialization function
>   * Add all new interface functions
>   * Fix existing interface functions, if needed / add wrappers for
>     ``msOGRLayerOpen`` and ``msWFSLayerOpen``. 
> 
> 
> 
> Backwards compatibility issues
> ------------------------------
> 
> This is binary and source code level backward incompatible change. The
> proposal will remove some previously public functions, and add new
> field(s) to the ``layerObj`` struct.  The proposal is ``MAP``-file
> backward compatible.
> 
> 
> Implementation Issues
> ---------------------
> 
> * Biggest problem is probably that the author has ignored or missed
>   something by oversight which will show up during implementation.
>   However, there is a prototype implementation of external plug-in
>   architecture which works at the moment and is based on ideas
>   presented in this proposal.  So there is some real life experience
>   that this architecture change is feasible thing to do.
> 
> * I also like to note that this proposal won't remove all layer
>   specific code from MapServer e.g. ``WMF``, ``WMS`` and ``GRATICULE``
>   are used as special cases from place to place.
> 
> 
> 
> Bug ID
> ------
> 
> unassigned
> 
> 
> 
> Voting history
> --------------
> 
> None
> 
> 
> 
> Open questions
> --------------
> 
> * MapScript. What is the impact of this change to the MapServer's
>   MapScript Interface?
> 
> * How do we like to expose layer's virtual table to the layers. We
>   have at least two different routes to go:
> 
>   * expose it as a struct, layers will fill vtable pointers by
>     accessing directly struct's field.
> 
>   * expose it as a complete opaque type, vtable pointers will be set
>     by accessing functions ``setLayerOpenFP``, ``setLayerCloseFP`` and
>     so on.
> 
>   The advance of second option is that this way we could easily add
>   new functions to the struct if we refactor code more or found some
>   logic which is ignored by oversight in this proposal.
> 
> 
> * Are there any special issues with the raster query layer support
>   which is handled via the layer API?
> 
> 
> =============
> Working Notes
> =============
> 
> 
> 
> .. Local Variables: 
>    mode: text
>    End:
> 

-- 
+-----------------------------------------------------------------+
|Paul Spencer                           pspencer at dmsolutions.ca   |
+-----------------------------------------------------------------+
|Applications & Software Development                              |
|DM Solutions Group Inc                 http://www.dmsolutions.ca/|
+-----------------------------------------------------------------+



More information about the mapserver-dev mailing list