Extending Omea with New Resource Types
Creating and Registering a Plugin
This article will discuss the main structure and responsibilities of a plugin which registers a new resource type. The example plugin discussed in the article is "Librarian" - a plugin which allows you to manage your book collection. It demonstrates a wide array of Omea interfaces that you will need to deal with when developing plugins, and at the same time does not involve any extra complexity related to integrating with external applications, protocols or data formats. The example implements only the bare minimum functionality, but you will be easily able to extend it if desired.
To create a new plugin in Visual Studio .NET, simply create a new project of type "Class Library" and add a reference to the OpenAPI.dll assembly from the Omea distribution. That assembly contains a set of classes and interfaces in the JetBrains.Omea.OpenAPI namespace which constitute the API available to the plugin developers. The documentation for the Open API is not included in the base Omea distribution and can be downloaded separately from our Web site.
In order for Omea to be able to load the plugin, it should implement the IPlugin
interface. The interface consists of three methods - Register(), Startup()
and Shutdown(). The plugin startup sequence is fully described in
the OpenAPI documentation; here we will simply note that Register()
is the first method called after a plugin has been loaded, and we will perform
all the initialization in that method.
All services provided by the Omea core can be accessed through the static
properties of the JetBrains.Omea.OpenAPI.Core class, which are
available all the time a plugin is running. For example, to create a new
resource, the method Core.ResourceStore.NewResource is used.
Complete documentation of interfaces available through the Core
class can be found in the Open API documentation.
After you have compiled the plugin for the first time, you'll need to add it
to the system registry, so that Omea will know that it should be loaded. On your
test machine you can use the "Add..." button in the Omea Plugins options page to
add a plugin, but it is better to create an installer for the plugin that will
add it to the registry automatically. The list of Omea plugins is stored in the
registry under Software\JetBrains\Omea\Plugins for Omea Pro and
under Software\JetBrains\Omea Reader\Plugins for Omea Reader. The
contents of these keys is scanned both for HKEY_LOCAL_MACHINE and HKEY_CURRENT_USER;
plugins from either key are loaded.
Defining Resource and Property Types
In order to understand which resource and property types will be needed by the plugin, we need to decide on our requirements first. To keep the example simple, we will store only the minimum required information about each book.
Our plugin will allow the user to create, edit and view books. For every book, the user will be able to enter its name, authors, the year it was published and, optionally, its ISBN (which will serve as the unique identifier for the book). Every book can have several authors, and every person can be the author of several books.
To make the most use of the core features of Omea, it is recommended to reuse
the resource and property types defined by the core and the standard plugins
whenever it makes sense. In our example, we will need to create a new resource
type to represent books (because that's the whole point of our plugin, after
all). On the other hand, we do not need to create a separate resource type to
represent book authors - we can reuse the standard Contact
resource type to represent them. The openness of the Omea data model allows us
to add any extra properties and links to Contact resources if we
need to.
To represent the name of the book, we can also reuse an existing property
type - Name, which is a string property type with no special
features, and suits us just fine. We could represent the publication date of the
book with the standard date property type Date, but it does not
fit us quite well. It is usually not important to know the exact publication
date of the book, and asking the user to enter that information will be an extra
burden. Thus, we will create a new integer property type to represent the
publication year. The ISBN will also be represented by a new string property
type.
We will also define a new link type to represent the connection between a book and its authors. There is no inherent order for that connection, so we will not use a directed link type - the link will be completely symmetric.
To make sure the resource and property types defined by a third-party plugin
do not conflict with the types defined by the Omea core or other third-party
plugins, it is strongly recommended to use a prefix consisting of your company
name and plugin name for every defined type. For example, our book resource type
is called JetBrains.Librarian.Book, and the ISBN property type is JetBrains.Librarian.ISBN.
The resource and property types defined by the Omea core do not have any dotted
prefix. Display names are registered for the resource and property types, so
that the user will see friendly-looking names, without any dotted prefixes.
The registration code for the resource and property types, along with the
accessors for the registered property type IDs, is found in the classes
PropTypes and
ResourceTypes. Because the display name templates of some resource
types may reference property types defined in the plugin, we register all
property types before registering all resource types.
Note that the registration of resource and property types is completely
separate - we do not need to tell Omea which properties we are going to use for
the Book resource type. Any property can be applied to any
resource type. However, to ensure data consistency, we register a link
restriction specifying that the BookAuthor link of a book must
point to a resource of type Contact. We could also specify
restrictions on the link count (for example, specify that a book must have at
least one author), but we want to allow the users to create books with unknown
authors, so we don't restrict the link count.
The unique restriction on the ISBN property guarantees
that the values of ISBN will be unique among all books. There can
be any number of books for which the ISBN property is not defined,
but if it is defined, there may exist no other Book resource with
the same value of ISBN.