Extension points

VtrinLib driver

ABB Ability™ History's data abstraction layer VtrinLib provides object-based data access to any data source for which a driver is available. The list of currently available drivers can be found from the separate VtrinLib concept article.

Driver architecture

Implementing a driver

The pieces of code that Vtrin uses to connect to different databases are called drivers. When connecting to a new database for the first time, Vtrin searches the directory it has been installed in for potential drivers that could be used to connect, and tries all of them like keys to a lock, until a suitable one is found or all of them fail.

Much is defined in the code above the driver interface, but nothing is defined below it. You can make a driver just as you please, using any .NET-compatible language as long as the driver implements the required members of the cDriverSkeleton class. Before you start making a new driver, make sure you have all components required to connect to the database you want to make the driver for, and a working Vtrin installation that you know to work and have tested with another database. After this, you can start up your Visual Studio and create a new "Class Library" project with your favorite language, name it so that the name ends with the word 'Driver' (e.g. RTDBDriver, WisDriver, etc.), and make it reference VtrinLib.dll. As the next thing, you need to create one class that shall be the driver, and make it inherit from the ABB.Vtrin.Drivers.cDriverSkeleton. As a result, your code should look something like this:

namespace ABB.Data.RTDB
{
	public class cRTDB3_0Driver : ABB.Vtrin.Drivers.cDriverSkeleton
	{
		// Driver implementation here
	}
}

Now, try to compile the code you just made, and you will get a number of error messages complaining about abstract members not being implemented.

Time to consider a shortcut

The list of members to implement is quite long, but is not even close to the actual list, as some of the members you probably want to implement are optional and will not appear on the error list. Now, for SQL-based databases or databases that use a SQL database for supporting Vtrin's own needs, you might consider referencing SQLBasedDriverSkeletons.dll. This DLL provides you with the classes cSQLDriverSkeleton, cOracleDriverSkeleton, cOLEDBDriverSkeleton and cODBCDriverSkeleton - which provide you with the simple SQL-based implementations for accessing the databases that support it. You can enable using one of them by just inheriting from it instead of the cDriverSkeleton. If no part of your database supports SQL, or you want to do things by yourself, you may just continue by implementing all steps by yourself.

The hard work

Now what you got is a bunch of missing implementations, which you hopefully can code with the help of this documentation. Unfortunately, the author's time is up and cannot write any further at this time. Hopefully in the next SDK there will be more...

Plugin support

VtrinLib supports server-side plugins. The following functions can be overridden.

- mFetch<classname>s
- mCommit<classname>s
- mDelete<classname>s
- mExecuteClassBoundCommand
- mReadProperties
- mWriteProperties

Plugins are searched and loaded from the same folder where Vtrin-NetServer.exe resides. The allowed file extensions are .dll and .cs. Both, pre-compiled dlls, and plain C# source files are therefore supported. The name of the file must be in the format PluginName_DriverNamePlugin.extension. For example, MyTestPlugin_RTDBDriverPlugin.dll.

Plugins are searched in alphabetical order, so APlugin_RTDBDriverPlugin.dll will be loaded (and its functions executed) before BPlugin_RTDBDriverPlugin.dll.

Example - Adding a new class

The following example plugin provides a new class called "Pet", for which fetch returns the "Cat", "Dog", "Giraffe" and "Camel" instances.

namespace ABB.Vtrin.Drivers.ExamplePlugin_RTDBDriverPlugin
{
   public class cExamplePlugin_RTDBDriverPlugin
   {
      private ABB.Vtrin.Drivers.cDriverSkeleton.IDriverPluginHandle mHandle;
      public cExamplePlugin_RTDBDriverPlugin(ABB.Vtrin.Drivers.cDriverSkeleton.IDriverPluginHandle handle)
      {
         mHandle = handle;
      }
      protected ABB.Vtrin.cDbClass mFetchPetClassInfo()
      {
         System.Collections.Generic.List<cDbPropertyInfo> a = new System.Collections.Generic.List<cDbPropertyInfo>();
         a.Add(new cDbPropertyInfo(typeof(string), "Id", null, isreadonly: true, isunique: true, size: 32));
         cDbClass cls = mHandle.Driver.Classes.InitializeClassWithinDriverCode("Pet", a.ToArray());
         cls.CommitChanges();
         return cls;
      }
      protected cDbClassInstance[] mFetchPets(string[] instancenames, System.Array instanceids, cDbPropertyMask[] masking, ref int count, out System.Exception err)
      {
         var cls = mHandle.Driver.Classes["Pet"];
         System.Func<string, cDbClassInstance> a = (x) =>
         {
            var i = cls.CreateInstance();
            i.SetRawPropertyValue("Id", x);
            i.CommitChanges();
            return i;
         };
         err = new System.NotSupportedException(); //Signal to VtrinLib that we have not processed the masks in the 'masking' parameter
         return new cDbClassInstance[] { a("Cat"), a("Dog"), a("Giraffe"), a("Camel") };
      }
   }
}