How to create a dynamic plugin

From OpenSimulator

(Difference between revisions)
Jump to: navigation, search
(Current state of Plugin loading)
(Current state of Plugin loading)
Line 5: Line 5:
 
This has unfortunately lead to a situation in OpenSim where historically module loading was hard-coded and done by hand, using copy-and-paste code. Clearly this is a suboptimal situation.
 
This has unfortunately lead to a situation in OpenSim where historically module loading was hard-coded and done by hand, using copy-and-paste code. Clearly this is a suboptimal situation.
  
Effort was made to find a reusable, cross-platform dynamic assembly loader that could be used as-is, instead of reinventing our own. The only current candidate is Mono.Addins. MS's .NET runtime has its own Addin class, however it is not yet implemented in Mono.
+
Effort was made to find a reusable, cross-platform dynamic assembly loader that could be used as-is, instead of reinventing our own. The only current candidate is Mono.Addins. MS's .NET runtime has its own Addin class, however as of this writing it is not yet implemented in Mono.
  
 
A class called PluginLoader has been created to thinly wrap Mono.Addins, and the assemblies loaded by this class have been standardized on the IPlugin interface hierarchy. With the exception of RegionModules, all dynamically loaded assemblies should be called Plugins, and inherit from this base class.
 
A class called PluginLoader has been created to thinly wrap Mono.Addins, and the assemblies loaded by this class have been standardized on the IPlugin interface hierarchy. With the exception of RegionModules, all dynamically loaded assemblies should be called Plugins, and inherit from this base class.
  
 
Currently the following interfaces have been converted to IPlugin:
 
Currently the following interfaces have been converted to IPlugin:
# OpenSim.Region.Application.IApplicationPlugin
+
# OpenSim.IApplicationPlugin
 
# OpenSim.Grid.GridServer.IGridPlugin
 
# OpenSim.Grid.GridServer.IGridPlugin
 
# OpenSim.Data.IGridDataPlugin
 
# OpenSim.Data.IGridDataPlugin
Line 24: Line 24:
  
  
 +
== Why Mono.Addins ==
  
 
Mono.Addins offers features outside of being upstream maintained by the Mono project:
 
Mono.Addins offers features outside of being upstream maintained by the Mono project:
 
* logically splits up module interfaces from implementations in a cross platform way through the use of text-based "extension points" and "addin manifests"
 
* logically splits up module interfaces from implementations in a cross platform way through the use of text-based "extension points" and "addin manifests"
 +
* lazily loads assemblies only when finally necessary
 +
* tracks module dependencies
 +
* allows customize the addin manifest XML
 
* automatically handles module sharing across application domains
 
* automatically handles module sharing across application domains
 
* provides support for downloading assemblies from remote repositories
 
* provides support for downloading assemblies from remote repositories
 +
 +
== Mono.Addin concepts ==
 +
 +
Although effort has been made to make PluginLoader independent of the module loading mechanism, there are some concepts that should be understood when learning how to learn the system:
 +
 +
=== Separating Male and Female ===
 +
 +
A good system provides a means of loosely coupling two connected parts with a common interface so that one can be changed easily without affecting the other.
 +
 +
The assembly that consumes a service is called a ''host'', and the provider of a service is called an ''addin''.
 +
 +
The common reference point that addins and hosts use to identify each other is called an ''extension point'', which is essentially a hierarchical text "path". If a host asks for the addin(s) corresponding to extension point "/Foo", and an addin claims to implement "/Foo", then the two can be joined to make a functioning whole.
 +
 +
All OpenSim extension points start at the root "/OpenSim". If you wished to create a new service "Foo", you might choose to name it "/OpenSim/Foo".
 +
 +
In operation the consumer of a service, the host, requests that the system load all addins that claim to extend an extension point, and a list is returned to the consumer, who can choose to load any subset of those providers, the addins, into memory.
 +
 +
=== Describing an Addin ===
 +
 +
Clearly metadata must be associated with both host and addin, in our case this is an XML file that has the extension *.addin.xml, called a ''manifest''.
 +
 +
In practice, the host manifest and addin manifest are so similar as to be almost exactly the same. The principle difference is that host manifests tell Mono.Addins where to find abstract interfaces, and addin manifests tell Mono.Addins where to find concrete implementations of those interfaces.
 +
 +
The manifest has 3 critical parts
 +
# Name and Version information <br> this is used to check inter-addin dependencies
 +
# Filename of assemblies where the consumer interfaces or provider implementations can be found <br> this is needed to know which assemblies must be searched
 +
# Extension Point path and Fully Qualified .NET Class Name of the consumer interface or provider implementation <br> this is needed to load the actual classes into memory

Revision as of 01:23, 29 July 2008

Contents

Current state of Plugin loading

The .NET runtime system has always made reflecting and introspecting of assemblies at runtime very easy to do, making dynamic loading of modules possible with very little effort.

This has unfortunately lead to a situation in OpenSim where historically module loading was hard-coded and done by hand, using copy-and-paste code. Clearly this is a suboptimal situation.

Effort was made to find a reusable, cross-platform dynamic assembly loader that could be used as-is, instead of reinventing our own. The only current candidate is Mono.Addins. MS's .NET runtime has its own Addin class, however as of this writing it is not yet implemented in Mono.

A class called PluginLoader has been created to thinly wrap Mono.Addins, and the assemblies loaded by this class have been standardized on the IPlugin interface hierarchy. With the exception of RegionModules, all dynamically loaded assemblies should be called Plugins, and inherit from this base class.

Currently the following interfaces have been converted to IPlugin:

  1. OpenSim.IApplicationPlugin
  2. OpenSim.Grid.GridServer.IGridPlugin
  3. OpenSim.Data.IGridDataPlugin
  4. OpenSim.Data.ILogDataPlugin

And the following Assemblies are being loaded by PluginLoader:

  1. OpenSim.ApplicationPlugins.LoadRegions.LoadRegionsPlugin
  2. OpenSim.ApplicationPlugins.Rest.Regions.RestRegionPlugin
  3. OpenSim.ApplicationPlugins.Rest.Inventory.RestHandler
  4. OpenSim.ApplicationPlugins.RemoteController.RemoteAdminPlugin
  5. OpenSim.Data.MySQL.MySQLGridData
  6. OpenSim.Data.MySQL.MySQLLogData


Why Mono.Addins

Mono.Addins offers features outside of being upstream maintained by the Mono project:

  • logically splits up module interfaces from implementations in a cross platform way through the use of text-based "extension points" and "addin manifests"
  • lazily loads assemblies only when finally necessary
  • tracks module dependencies
  • allows customize the addin manifest XML
  • automatically handles module sharing across application domains
  • provides support for downloading assemblies from remote repositories

Mono.Addin concepts

Although effort has been made to make PluginLoader independent of the module loading mechanism, there are some concepts that should be understood when learning how to learn the system:

Separating Male and Female

A good system provides a means of loosely coupling two connected parts with a common interface so that one can be changed easily without affecting the other.

The assembly that consumes a service is called a host, and the provider of a service is called an addin.

The common reference point that addins and hosts use to identify each other is called an extension point, which is essentially a hierarchical text "path". If a host asks for the addin(s) corresponding to extension point "/Foo", and an addin claims to implement "/Foo", then the two can be joined to make a functioning whole.

All OpenSim extension points start at the root "/OpenSim". If you wished to create a new service "Foo", you might choose to name it "/OpenSim/Foo".

In operation the consumer of a service, the host, requests that the system load all addins that claim to extend an extension point, and a list is returned to the consumer, who can choose to load any subset of those providers, the addins, into memory.

Describing an Addin

Clearly metadata must be associated with both host and addin, in our case this is an XML file that has the extension *.addin.xml, called a manifest.

In practice, the host manifest and addin manifest are so similar as to be almost exactly the same. The principle difference is that host manifests tell Mono.Addins where to find abstract interfaces, and addin manifests tell Mono.Addins where to find concrete implementations of those interfaces.

The manifest has 3 critical parts

  1. Name and Version information
    this is used to check inter-addin dependencies
  2. Filename of assemblies where the consumer interfaces or provider implementations can be found
    this is needed to know which assemblies must be searched
  3. Extension Point path and Fully Qualified .NET Class Name of the consumer interface or provider implementation
    this is needed to load the actual classes into memory
Personal tools
General
About This Wiki