Navigation:  Application Architecture >

Plugin/Extension Architecture

Previous pageReturn to chapter overviewNext page

Extensibility is one of the primary goals of the ClearCanvas platform.  The purpose of the extension point framework is to provide a formal mechanism for allowing a ClearCanvas application to be extended indefinitely.

Functionality is added to a ClearCanvas application through plugins.  A plugin is simply a .NET assembly that is loaded dynamically by the framework at runtime.  However, in order for the code in a plugin to be useful, the framework must know what to do with the code once the assembly is loaded.  Extension points and extensions effectively provide knowledge of how the code contained in a plugin is to be used.

In general, a plugin is only useful if some existing plugin knows what to do with it.

 

 

Figure 1 shows three plugins A, B and C, and the arrows are meant to suggest that plugin A knows how to make use of plugin B, and plugin B knows how to make use of plugin C.  In this case, plugin B is said to extend plugin A, and C is said to extend B.  But in order for a plugin to be extended, it must have some mechanism for declaring how it is to be extended.  That is, it must declare one or more points of extensibility, known as extension points.

Figure 2 shows that plugin A actually declares two extensions points, w and x.  The arrows show that plugin B provides extensions to both w and x.  Plugin B also declares two new extension points, y and z.  The arrows show that plugin C provides an extension to y, and yet a fourth plugin, plugin D, provides extensions to both y and z.

Note that plugin B defines both extensions (to w and x) and extension points (y and z).  In general, a plugin may define any number of extensions and any number of extension points.  Although not shown in Figure 2, a plugin may even extend the same extension point multiple times.  For instance, plugin C might actually provide multiple extensions to point y.  It is up to the plugin that defines the extension point to determine whether it will make use of all available extensions or only some subset of the available extensions.

In terms of the actual code, the process of extension is accomplished through the mechanism of interface implementation.  That is, an extension point will always specify an interface that the extension must implement.  The extension itself is a class that implements the specified interface.

This is best understood by considering an example.  One of the most common ways to extend ClearCanvas is to provide a new tool.  There are several extension points that allow for the integration of new tools, and the choice of which point to extend depends upon the applicability of the tool.  The most widely applicable tools are those that apply to the workstation as a whole, such as the Help tool.  The plugin ClearCanvas.Desktop.dll defines the extension point DesktopToolExtensionPoint for this kind of tool.

DesktopToolExtensionPoint is a class whose definition is as follows:

 

[ExtensionPoint()]

public sealed class DesktopToolExtensionPoint : ExtensionPoint<ITool>

{

}

 

There are several important things to note:

1.The extension point is effectively defined by a class.  The fully-qualified name of the class, ClearCanvas.Desktop.DesktopToolExtensionPoint, acts as a unique identifier for the extension point.
2.The class is a subclass of ExtensionPoint<ITool>.  The template parameter, ITool, is an interface.  As will be shown shortly, an extension class must implement ITool.
3.The class is decorated with the [ExtensionPoint()] attribute.  The attribute tells the framework that this class defines an extension point, and optional parameters to the attribute may be used to provide additional metadata about the extension point, such as a friendly name and description.
4.The class is empty.  No additional implementation is necessary, as all of the required implementation is provided by the base class ExtensionPoint<ITool>.  The class exists for the dedicated purpose of uniquely defining the extension point, as discussed in 1.  For this reason, it is generally good practice to seal extension point classes.

Now consider the definition of the HelpTool class.  This class is found in the plugin ClearCanvas.Desktop.Help.dll:

 

[ExtensionOf(typeof(DesktopToolExtensionPoint))]

public class HelpTool : Tool<IDesktopToolContext>

{

   public HelpTool()

   {

   }

   // other methods

}

 

Again, there are several things to note:

1.The class is decorated with the [ExtensionOf(…)] attribute.  This attribute tells the framework that the class is an extension of the specified extension point.  Without this attribute, the framework has no way of knowing that HelpTool is an extension.  Optional parameters to the attribute may be used to provide additional metadata about the extension, such as a friendly name and description.
2.The class implements ITool (well ok, it does not directly implement ITool, but it does so indirectly through inheritance of the class Tool).  This is necessary, because DesktopToolExtensionPoint is defined on the interface ITool.  Without a common interface, the Desktop plugin would not be able to work with the HelpTool.
3.The class has a no-arguments constructor.  All extension classes must supply a no-arguments constructor, so that they may be instantiated by the framework.

At application startup, the framework loads the plugins and processes each plugin in turn to discover any extension points and extensions that it defines.

At some point during the application initialization, the ClearCanvas.Desktop.dll plugin will ask the framework for an instance of each available extension of DesktopToolExtensionPoint.  The framework will attempt to instantiate an instance of every extension of DesktopToolExtensionPoint that exists in the current set of plugins, and return the extension objects to the Model.  Because each extension class implements the ITool interface, the Model knows how to interact with the tool extensions and integrate them into the application.

The ClearCanvas.ImageViewer.dll plugin defines another extension point called ImageViewerToolExtensionPoint:

 

[ExtensionPoint()]

public sealed class ImageViewerToolExtensionPoint : ExtensionPoint<ITool>

{

}

 

ImageViewerToolExtensionPoint is similar to DesktopToolExtensionPoint – indeed, both are defined on the interface ITool.  However, ImageViewerToolExtensionPoint is defined for tools that are applicable for use in an image viewer component, such as StackTool.  The StackTool class, found in the plugin ClearCanvas.ImageViewer.Tools.Standard, is defined as follows:

 

[ExtensionOf(typeof(ImageViewerToolExtensionPoint))]

public class StackTool : MouseImageViewerTool

{

   // implementation code

}

 

Note that StackTool is marked as an extension of ImageViewerToolExtensionPoint, and that it implements the ITool interface (indirectly through the MouseImageViewerTool base class).

The key point here is that, although HelpTool and StackTool are both tools that implement the ITool interface, they extend different extension points.  An extension class must extend the correct extension point in order for the host plugin (the Model in this case) to know how to treat it.