=====================================================
MS RFC 8: Pluggable External Feature Layer Providers
=====================================================

:Date:  2005/10/26
:Author: Jani Averbach
:Contact: javerbach@extendthereach.com
:Last Edited: $Date: 2007-09-05 13:56:10 -0700 (Wed, 05 Sep 2007) $
: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, funtion 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_

.. _1477: http://mapserver.gis.umn.edu/bugs/show_bug.cgi?id=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.

.. 
   Local Variables: 
   mode: rst
   coding: iso-latin-1-unix
   End:

