MS RFC 8: Pluggable External Feature Layer Providers

Date:

2005/10/26

Author:

Jani Averbach

Contact:

javerbach at extendthereach.com

Status:

adopted

Version:

MapServer 4.8

Purpose

The purpose of this proposal is provide a way to user actually plug-in external third party feature layer providers to the MapServer at run time.

Abstract Solution

Provide a way to user to tell via map-file which library to load for layer, then load this library on demand and cache it for later use and bind it to the running MapServer by layer’s virtual table.

Technical Solution

  • New CONFIG option MS_PLUGIN_DIR which, if set, tells the base path for plugins

  • New MAP-file keyword PLUGIN with string argument. This keywords tells which library dynamically to load for this layer.

    The plugins are loaded based on the following algorithm:

    • If plugin string is missing .so or .dll extension, append it to the plugin string

    • If MS_PLUGIN_DIR is set and plugin string is not an absolute path, prefix plugin string with MS_PLUGIN_DIR

    • otherwise use plugin string directly

    In general, the dynamic library loader will use system paths to seek appropriate plugin to load, if the path is not absolute.

  • New connection type PLUGIN

  • New field char* plugin_library in layerObj structure, this is the name of library to load for this layer.

  • Function to get virtual table for requested layer. If the library isn’t already loaded, it will be loaded on demand.

    static const layerVTableObj *
    getCustomLayerVirtualTable(layerObj *layer)
    

    where layerVTableObj is the virtual table and layer is a custom layer. In case of error, function will return NULL.

  • Function to get a function pointer from dynamic loaded library. This function will also load the library.

    msGetDynamicLibrarySymbol(const char *Library,
                              const char *SymbolName)
    

    This is implemented by GDAL project, and I have planned to use their implementation of this (CPLGetSymbol).

  • Cache structure for already loaded libraries. This cache structure will consist of a full name/path of the library (provided by user via mapfile), and a function pointer to the virtual table initialization function. The size of cache will be fixed and will be same as the maximum amount of layers (200 at the moment). This is the maximum number of different custom layers for MapServer which could be loaded at the same time. This cache implementation is internal, so if it has to be make dynamically allocated, it is possible to do later without breaking interface.

  • New lock item (TLOCK_LAYER_VTABLE) to protect library cache structure.

Files and objects affected

This proposal will affect at least following files and objects:

  • map.h

    • layerObj will contain a new field, char *plugin_library.

  • New lock token TLOCK_LAYER_VTABLE

  • New files and objects for custom layer handling.

Backwards compatibility issues

This change is binary incompatible, but mapfile backward compatible. It will add a new keyword which is unknown for old MapServers.

Implementation Issues

None

Bug ID

Bug 1477

Voting history

Vote proposed by Jani Averbach on 10/26/2005, the initial result was +3 and after amending RFC, got +4 (3 non-voting members).

Voting +1: Frank Warmerdam, Steve Lime, Yewondwossen Assefa, Daniel Morissette

Proposal passed and will move forward.

Open questions

None

Working Notes

Plugin library has to implement function PluginInitializeVirtualTable

int (*pfnPluginInitVTable)(layerVTableObj *,
                           layerObj *);

which is called during library loading. This function is responsible to populate layerVTableObj * virtual table. If this function leaves some function pointers to NULL in this virtual table, then default actions are used for these missing functions. The defaults are visible in function maplayer.c: populateVirtualTable(…). The function must not populate directly layerObj->vtable, it have to use layerVTableObj * argument for this. The MapServer is holding TLOCK_LAYER_VTABLE lock during this function call.