PluginFrameworkPOCStory

Functional specifications

Proof of concept. Decide where, which and how it should be possible to add plugins.
Also check out PluginFramework for more ideas.

Resources

Technical interpretation

There are four areas that need to be explored:
  1. The frontend plugins; we need a way to let other people extend our panels/components and add views.
    • Design a plugin component that adds/replaces a component and adds a tab to a tabbedpanel
    • Add a generic way to add components to specific extension points (forms for example) and include the model in the event.
  2. The Backend plugins; the backend plugins need a way to register new Dao's for the event/task storage. A first step is already taken with the DaoFactory.
    • Design a Factory that takes new types of calendars and a way to store the registrations.
    • Create a dummy dao to test this
  3. The locale packages. We need to check out how to register new packages and get them available. Also there must be decided whether to make it possible to upload packages with translated markup files and switch between them or if we can use propety-files for all locale specific matters.
    • Set up a page that switches between languages and date formats depending on a locale set by a form.
    • Create a setup where additional locale files can be added in a seperate directory
  4. We must provide a way to install new plugins in an intuitive way. The most ideal solution would be to have a directory on the server (configurable offcourse) were you can put the extension packages, these will be eveluated on startup.
    • A package manifest must be thougth off that can be used to validate the package contents (xsd and file checks)
    • A package layout must defined to allow for the different types off packages to have a logical layout.
    • An architecture must be designed that allows for the classes to be registered, loaded by the classloader and called on the rigth time.

Budget/Hours

task estimate todo spent developer
Frontend plugin system
Create an event system for the frontend plugins 8 0 9 Ivo
Generic extension point 4 0 4 Ivo
Backend plugin system
Extend the DaoFactory 2 0 1 Ivo
Dummy dao 3 0 2 Ivo
Internationalization
Decide on localization support ( only property files or html aswell) 3 0 3 Ivo
Set up a page that switches the locale 3 0 2 Ivo
Add external localization files and show them in the page 5 0 4 Ivo
Plugin architecture
Xsd for plugin manifest 4 0 4 Ivo
Directory layout 2 0 1 Ivo
Plugin validation (xsd/file presence) 8 3 3 Ivo
Classloading + plugin registration 12 4 12 Ivo
Example plugin 2 2 0 Ivo
Total 56 9 45

The last functionality is moved to PluginArchitectureStory

Notes

Frontend plugin system

The plugin system is made up by five parts
  • The ExtensionEvent send to the ExtensionListener by the ExtensionHandler. The ExtensionEvent consists of:
    • The source ExtensionHandler List additionalResources
    • A List of Ids for the replaceablecomponents the source offers.
    • A List of arbitrary resources; Listeners used in the Component for example.
    • A list of ExtensionPoints?
  • The ExtensionHandler implemented by baseclasses for the Components. In the Poc I've implemented it in the AbstractPanel subclassed by the Panels that offer plugability. The ExtensionHandler offers.
    • Methods to remove/register an ExtensionListener
    • A method to replace existing Components on the source.
    • A method to add new Components
    • A method that can be overidden by the AbstractPanel's subclass to offer the possibility to add a new Tab
    • A helper methods that offer a list of replaceable components to add to and such
  • The ExtensionListener This interface is implemented by plugin classes that want to add new functionality. The Listener has two method that recieves an ExtensionEvent. One before the target panel renders and one after.
  • The ExtensionPoint defines an extension point, its component and a possible model if it is inbedded in a Form for example.
  • The Extension is send to the ExtensionListener to add a new component. This class holds the new component ans a reference to the extensionpoint it belongs to.

In the poc I've tested each of the three plugin possibilities (Adding/replacing components and adding a tab) and one addition to a form. The extended Panels double as the plugins in this case seeing that there isn't a way to register plugins as of yet:


The cylce is as follows:
  • An ExtensionListener registers itself with the ExtensionHandler
  • The ExtensionHandler's sublass is created.
  • Before attaching the component, onAttach is called in the ExtensionHandler:
    • The events are fired and the ExtensionListeners get the chance to add functionality before the panel renders through the implemented addExtensionsBeforeComponentSetup() method
    • The subclass' own components are added
    • The events are fired again but now the addExtensionsAfterComponentSetup() is called
    • The Components added/replaced by the ExtensionListener are handled
  • The component renders

Backend plugin system

The backend plugins can be registered in the DaoFactory. At the moment only through the applicationContext.xml untill a plugin architecture is devised. The registration methods check for double registration keys/invalid registrations and throw exceptions when nessecary.

Localization support

The localization support can be added by using a property file to specify all the labels and such in. In addition to this its also possible to translate entire pages, wicket will look the rigth one up according to the selected locale automatically.
Additional translations can be added through plugin files. At the moment I configured a couple of directories (Hardcoded) in which resources like html and property files can be placed.
involved files:
  • WebIcalWebApplication Holds a list of additional resource lookup paths (relative from webroot or full paths). These can be be added through the applicationContext.xml or lateron through the plugin system.
  • BasePage switches between Locales.
  • CalendarAddEditPanel adds a Label with a StringResourceModel? witch looks up the value in the resource files.
  • A hardcoded plugin folder Holds a couple of property files and translations of entire pages/components. Note that they must include the full package structure.
  • applicationContext.xml configures a list of pluginfolders. Later on these should also be created by the plugin registration system.

Plugin registration system

The plugin registration must handle a couple of things.
  • Configuration of the plugin paths ( configured in the applicationContext.xml )
  • Unpacking the plugin packages
  • Checking the plugin manifest
  • Adding resource lookup paths
  • Registering new classes with the classloader
  • Registering the frontend plugins with the plugin handlers (AbstractBasePanel and AbstractBasePage subclasses)
  • Registering the backend plugins with the DaoFactory

The components:

  • PluginSystemInitializer - A class that handles all the unpacking and registering

Class Loading

To load in the classes from outside the classpath three things were needed:
  • A PluginClassResolver this class is registered with wicket as the default IClassResolver and gets called upon to locate classes. This ClassResolver first tries a DefaultClassResolver before using our own implementation. Classes are registered in a HashMap containing the className and full path (eg /some/dir/Class.class).
  • A PluginClassLoader which is called by the PluginClassResolver to read in the classfile and define a Class.
  • A PluginClassNotFoundRuntimeException which is thrown by the PluginClassResolver with a wrapped ClassNotFoundException containing the error.

Zipfile extraction

Plugin manifest

In order to let the plugins describe themselves a plguin manifest file is needed. We set up jaxb to support the manifest (an xml file) and validate using sax. The components used:
  • The xsd used to validate the manifest
  • The PluginManifestReader first parses and validates the manifest according to the xsd and then unmarshalls it using jaxb

There is a example plugin manifest included in svn

Directory structure

The standard plugin structure looks as follows:

Zipfile root:
  • META-INF
    • manifest.xml
  • resources
    • your
      • package
        • resource1.html
        • resource2.property
  • classes
    • your
      • package
        • YourExtension.class
        • AnotherExtension.class

Plugin initialisation/validation

During startup a bean is created by spring that initializes the plugin system. A couple of steps are taken:
  1. The manifest is validated to the schema
  2. The manifest is unmarshalled with jaxb
  3. The Package is validated
    1. file references are checked
    2. classes are checked
    3. Frontend/Backend plugins are checked
      1. Class files are checked for the right Interface implementations

The components:

Discussion

Frontend plugin system

  • Some plugins migth require some more from the source components like models and listeners. What makes a good way to expose these to the plugin. For now I've added a List in the ExtensionEvent where arbitrary objects can be placed, but this is probately not the cleanest solution. Models associated specificly with an added ExtensionPoint? are handled correctly now.

  • It is simple to add components in a single level this way. It is still to be tested if a component like a panel wich includes its own sub-components can be added correctly aswell.

-- IvoVanDongen - 22 Oct 2006
Topic revision: r17 - 15 Nov 2006 - 15:34:03 - IvoVanDongen
 
This site is powered by the TWiki collaboration platformCopyright © by the contributing authors. All material on this collaboration platform is the property of the contributing authors.
Ideas, requests, problems regarding TWiki? Send feedback