Provide system definitions with a custom plugin
This tutorial explains how to provide any kind of preconfigured UBIK® data (system definitions) using a custom plugin.
- Big Picture
- Create a new plugin
- Create a new SystemDefinitionProvider
- Create a new SystemDefinitions package
- Add a new basic MetaClass
- Add a new special MetaClass
- Add new arbitrary instances
- Provide a version upgrade
Big Picture
Create a new plugin
The plugin class is the central access point for your definitions. It must implement the IUbikModule interface for the system definitions to be applied.
{
[Export(typeof(UBIK.Injection.IUbikPlugin))]
[ExportMetadata("ID", "e9395ebd-4e41-40a3-9ac6-01bce6fb7e68")]
[ExportMetadata("Type", typeof(MyPlugin))]
[ExportMetadata("Name", "MyPlugin")]
[ExportMetadata("Description", "My custom plugin")]
[ExportMetadata("Version", 1)]
[ExportMetadata("Company", "Augmensys GmbH")]
[ExportMetadata("MinimumKernelVersion", "4.0.0.0")]
public class MyPlugin: IUbikModule
{
public static Guid ID
{
get
{
return Guid.Parse("e9395ebd-4e41-40a3-9ac6-01bce6fb7e68");
}
}
public UBIKEnvironment Environment { get; private set; }
public ISystemDefinitionProvider SystemDefinitionsProvider
{
get
{
return MySystemDefinitionProvider.Instance;
}
}
public virtual void Initialize(UBIKEnvironment environment)
{
this.Environment = environment;
}
public virtual void Terminate()
{
this.Environment = null;
}
public virtual bool Initialized()
{
return this.Environment != null;
}
public List<ModuleInfo> DependencyModules
{
get;
} = new List<ModuleInfo>();
}
}
Create a new SystemDefinitionProvider
The SystemDefinitionProvider has a list of all supported system definitions packages. The base implementation uses the version information from the packages to handle the upgrading.
{
public class MySystemDefinitionProvider : SystemDefinitionProviderBase
{
public override Guid ModuleID => MyPlugin.ID;
private static MySystemDefinitionProvider instance = null;
public static MySystemDefinitionProvider Instance
{
get
{
return instance ?? (instance = new MySystemDefinitionProvider());
}
}
private MySystemDefinitionProvider() :
base(
new MySystemDefinitions_V100(),
new MySystemDefinitions_V110())
{ }
}
}
Create a new SystemDefinitions package
The SystemDefinitions contain any data you may want to deliver with your plugin.
{
public class MySystemDefinitions_V100 : SystemDefinitionsBase
{
#region Constants
public static readonly Version VERSION = new Version(1, 0, 0, 0);
#endregion Constants
#region Version
public override Version Version
{
get
{
return VERSION;
}
}
#endregion Version
#region System Classifications
public override UBIKClassList<MetaClass> DefineSystemClassifications(UBIKEnvironment environment)
{
return new UBIKClassList<MetaClass>();
}
#endregion System Classifications
#region System Meta Classes
public override UBIKClassList<MetaClass> DefineSystemMetaClasses(UBIKEnvironment environment)
{
UBIKClassList<MetaClass> metaClasses = new UBIKClassList<MetaClass>();
return metaClasses;
}
#endregion System Meta Classes
#region System Meta Properties
public override UBIKClassList<MetaProperty> DefineSystemMetaProperties(UBIKEnvironment environment)
{
UBIKClassList<MetaProperty> result = new UBIKClassList<MetaProperty>();
return result;
}
#endregion System Meta Properties
#region System Selective Lists
public override UBIKClassList<SelectiveList> DefineSystemSelectiveLists(UBIKEnvironment environment)
{
UBIKClassList<SelectiveList> result = new UBIKClassList<SelectiveList>();
return result;
}
#endregion System Selective Lists
#region Module Definition
public override void UpdateSystemContent(UBIKEnvironment environment)
{
UpdateModuleDefinition(environment);
}
protected void UpdateModuleDefinition(UBIKEnvironment environment)
{
MetaClass moduleMc = environment.GetSystemMetaClass(SystemObjects.MODULE);
BaseClass module = moduleMc.GetOrCreateInstance(MyPlugin.ID);
module.Name = "MyPlugin";
module.Namespace = "MyPlugin";
if (environment.LanguageManager.TryGetLanguageIndex("de", out int idxDe))
{
module.SetInternationalDescription(idxDe, "UBIK Plugin Vorlage. (C) Augmensys GmbH");
}
if (environment.LanguageManager.TryGetLanguageIndex("en", out int idxEn))
{
module.SetInternationalDescription(idxEn, "UBIK template plugin. (C) Augmensys GmbH");
}
module.Save();
}
#endregion Module Definition
}
}
Add a new basic MetaClass
Here's how you can add a new MetaClass (and MetaProperty) to be shipped with your plugin.
{
public class MyBaseMetaClass : SystemDesignMetaClass
{
public static readonly Guid UID = Guid.Parse("30ed406b-a5f1-498b-ad34-2db1bd786b13");
private const string NAME = "MY_BASECLASS";
private const string NAMESPACE = "System.MyPlugin";
private const string DESCRIPTION = "My Baseclass";
public MyBaseMetaClass(UBIKEnvironment environment)
{
InitUidAndEnvironment(UID, environment);
InitStrings(NAME, NAMESPACE, DESCRIPTION);
SetModuleId(MyPlugin.ID);
DefineMetaProperties(new List<Guid>() {
MyMetaProperties.PROPERTY_UID_MYPROPERTY
});
}
public override MetaClass Inheritance
{
get
{
return this.Environment.GetSystemMetaClass(SystemObjects.NAMEDBASECLASS);
}
set
{
throw new NotImplementedException();
}
}
public override MetaClassTypes ClassType
{
get
{
return MetaClassTypes.Inherited;
}
set
{
// do nothing
}
}
}
}
{
public class MyMetaProperties
{
public const string NS_MY_PLUGIN = "System.MyPlugin;
public static Guid PROPERTY_UID_MYPROPERTY = Guid.Parse("d90b50e0-17d9-40ac-b89d-18f4a01cd5cb");
public const string PROPERTY_NAME_MYPROPERTY = "LK_LOCATION";
public static UBIKClassList<MetaProperty> DefineSystemMetaProperties(UBIKEnvironment environment)
{
MetaProperty myProperty = SystemDesignMetaProperty.CreateStringSystemDesignMetaProperty
(environment, PROPERTY_NAME_MYPROPERTY, NS_MY_PLUGIN, PROPERTY_UID_MYPROPERTY, multiLang: false, orderID: 0, stringLen: 0);
myProperty.Description = "MyProperty";
UBIKClassList<MetaProperty> metaProperties = new UBIKClassList<MetaProperty>() {
myProperty
};
return metaProperties;
}
}
}
{
public class MySystemDefinitions_V100 : SystemDefinitionsBase
{
// ...
#region System Meta Classes
public override UBIKClassList<MetaClass> DefineSystemMetaClasses(UBIKEnvironment environment)
{
UBIKClassList<MetaClass> metaClasses = new UBIKClassList<MetaClass>();
MyBaseMetaClass myBaseClass = new MyBaseMetaClass(environment);
metaClasses.Add(myBaseClass);
return metaClasses;
}
#endregion System Meta Classes
#region System Meta Properties
public override UBIKClassList<MetaProperty> DefineSystemMetaProperties(UBIKEnvironment environment)
{
UBIKClassList<MetaProperty> result = new UBIKClassList<MetaProperty>();
result.AddRangeUnique(MyMetaProperties.DefineSystemMetaProperties(environment));
return result;
}
#endregion System Meta Properties
// ...
}
}
Add a new special MetaClass
In some cases you need to defined something more elaborate, e.g., a MetaClass with custom code deriving from another MetaClass you defined.
{
public class MySpecialMetaClass : SystemDesignMetaClass
{
public static readonly Guid UID = Guid.Parse("0925ad66-7199-4e70-871c-cdd799f8d8e7");
private const string NAME = "MY_SEPCIALCLASS";
private const string NAMESPACE = "System.MyPlugin";
private const string DESCRIPTION = "My special class";
private MyBaseMetaClass parent = null;
public MySpecialMetaClass(UBIKEnvironment environment, MyBaseMetaClass parent)
{
InitUidAndEnvironment(UID, environment);
InitStrings(NAME, NAMESPACE, DESCRIPTION);
SetModuleId(MyPlugin.ID);
this.parent = parent;
DefineMetaProperties(new List<Guid>() {
// ...
});
}
public override MetaClass Inheritance
{
get
{
return this.parent;
}
set
{
throw new NotImplementedException();
}
}
public override MetaClassTypes ClassType
{
get
{
return MetaClassTypes.DEFINED_IN_PLUGIN;
}
set
{
// do nothing
}
}
public override Type GetRuntimeType()
{
return typeof(MySpecialType);
}
public override Type GetSystemRuntimeType()
{
return typeof(MySpecialType);
}
}
}
{
public class MySpecialType : ContentClass
{
// This implementation will be used to instantiate respective instances in UBIK during runtime.
// Here you can override anything that can be overridden in UBIK.Studio's code editor, and more.
// Additional code may be added, too.
}
}
{
public class MySystemDefinitions_V100 : SystemDefinitionsBase
{
// ...
#region System Meta Classes
protected MyBaseMetaClass MyBaseMetaClass { get; set; }
protected MySpecialMetaClass MySpecialMetaClass { get; set; }
public override UBIKClassList<MetaClass> DefineSystemMetaClasses(UBIKEnvironment environment)
{
UBIKClassList<MetaClass> metaClasses = new UBIKClassList<MetaClass>();
MyBaseMetaClass = new MyBaseMetaClass(environment);
metaClasses.Add(MyBaseMetaClass);
MySpecialMetaClass = new MySpecialMetaClass(environment, MyBaseMetaClass);
metaClasses.Add(MySpecialMetaClass);
return metaClasses;
}
#endregion System Meta Classes
// ...
}
}
Add new arbitrary instances
In some cases you may want to deliver instances of an arbitrary type the user can change to their liking.
{
public class MySystemDefinitions_V100 : SystemDefinitionsBase
{
public static readonly Guid DEFAULT_INSTANCE_UID = Guid.Parse("a71c2c7e-a7b7-4462-b1c8-61ea9cba0dcd");
// ...
#region System Content
public override void UpdateSystemContent(UBIKEnvironment environment)
{
MySpecialType defaultInstance = MySpecialMetaClass.GetOrCreateInstance(DEFAULT_INSTANCE_UID) as MySpecialType;
if (defaultInstance.IsNewInstance)
{
defaultInstance.Namespace = "MyPlugin.Default";
defaultInstance.Name = "MySpecialInstance";
defaultInstance.Description = "Default instance";
defaultInstance.Save();
}
}
#endregion System Content
// ...
}
}
Provide a version upgrade
If you released system definitions previously, which are already used productively, how do you deliver changes? The solution is to not change the older version, but create a newer version instead. We always want to stay downward compatible.
{
public class MySystemDefinitions_V110 : MySystemDefinitions_V100
{
// ...
#region System Meta Classes
// Refactor MySystemDefinitions_V100 so the "MyBaseMetaClass" is defined in a separate method, so we can override it!
public override MyBaseMetaClass DefineMyBaseMetaClass(UBIKEnvironment environment)
{
MyBaseMetaClass mc = new MyBaseMetaClass_V110(environment);
// MyBaseMetaClass_V110 should derive from the original MyBaseMetaClass, adapting it to the new version
return mc;
}
#endregion System Meta Classes
// ...
}
}