Changes

HowTo:Provide system definitions with a custom plugin

17,201 bytes added, 02:24, 25 November 2024
Created page with "This tutorial explains how to provide any kind of preconfigured {{UBIK}} data (system definitions) using a custom plugin. <!-- DO NOT REMOVE THIS -->{{Template:HowTo/Begin}}..."
This tutorial explains how to provide any kind of preconfigured {{UBIK}} data (system definitions) using a custom plugin.


<!-- DO NOT REMOVE THIS -->{{Template:HowTo/Begin}}<!-- DO NOT REMOVE THIS -->

= Big Picture =

The Plugin hosts a SystemDefinitionProvider, which in turn gives access to a set of versioned SystemDefinitions. The latter can contain any kind of {{UBIK}} data like MetaClasses, MetaProperties, instance of any type and scripts to execute when the package is installed or initialized.

[[File:Systemdefinitions.drawio.png]]

= 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.

<div class="toccolours mw-collapsible mw-collapsed" style="width:100%; overflow:auto;">
<div style="font-weight:bold;line-height:1.6;">Plugin template code</div>
<div class="mw-collapsible-content">
<syntaxhighlight lang="csharp">
namespace UBIK.MyPlugin
{
[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>();
}
}

</syntaxhighlight>
</div></div>

= 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.

<div class="toccolours mw-collapsible mw-collapsed" style="width:100%; overflow:auto;">
<div style="font-weight:bold;line-height:1.6;">SystemDefinitionsProvider template code</div>
<div class="mw-collapsible-content">
<syntaxhighlight lang="csharp">

namespace UBIK.MyPlugin
{
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())
{ }
}
}

</syntaxhighlight>
</div></div>

= Create a new SystemDefinitions package =

The SystemDefinitions contain any data you may want to deliver with your plugin.

<div class="toccolours mw-collapsible mw-collapsed" style="width:100%; overflow:auto;">
<div style="font-weight:bold;line-height:1.6;">SystemDefinitions package template code</div>
<div class="mw-collapsible-content">
<syntaxhighlight lang="csharp">

namespace UBIK.MyPlugin
{
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
}
}

</syntaxhighlight>
</div></div>

= Add a new basic MetaClass =

Here's how you can add a new MetaClass (and MetaProperty) to be shipped with your plugin.

<div class="toccolours mw-collapsible mw-collapsed" style="width:100%; overflow:auto;">
<div style="font-weight:bold;line-height:1.6;">SystemDesignMetaClass template code</div>
<div class="mw-collapsible-content">
<syntaxhighlight lang="csharp">

namespace UBIK.MyPlugin
{
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
}
}
}
}

</syntaxhighlight>
</div></div>

<div class="toccolours mw-collapsible mw-collapsed" style="width:100%; overflow:auto;">
<div style="font-weight:bold;line-height:1.6;">SystemDesignMetaProperty template code</div>
<div class="mw-collapsible-content">
<syntaxhighlight lang="csharp">
namespace UBIK.MyPlugin
{
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;
}
}
}
</syntaxhighlight>
</div></div>

<div class="toccolours mw-collapsible mw-collapsed" style="width:100%; overflow:auto;">
<div style="font-weight:bold;line-height:1.6;">SystemDefinitions adaptations</div>
<div class="mw-collapsible-content">
<syntaxhighlight lang="csharp">
namespace UBIK.MyPlugin
{
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

// ...
}
}
</syntaxhighlight>
</div></div>

= 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.

<div class="toccolours mw-collapsible mw-collapsed" style="width:100%; overflow:auto;">
<div style="font-weight:bold;line-height:1.6;">SystemDesignMetaClass template code</div>
<div class="mw-collapsible-content">
<syntaxhighlight lang="csharp">

namespace UBIK.MyPlugin
{
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);
}
}
}

</syntaxhighlight>
</div></div>

<div class="toccolours mw-collapsible mw-collapsed" style="width:100%; overflow:auto;">
<div style="font-weight:bold;line-height:1.6;">Special runtime type template code</div>
<div class="mw-collapsible-content">
<syntaxhighlight lang="csharp">
namespace UBIK.MyPlugin
{
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.
}
}
</syntaxhighlight>
</div></div>

<div class="toccolours mw-collapsible mw-collapsed" style="width:100%; overflow:auto;">
<div style="font-weight:bold;line-height:1.6;">SystemDefinitions adaptations</div>
<div class="mw-collapsible-content">
<syntaxhighlight lang="csharp">
namespace UBIK.MyPlugin
{
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

// ...
}
}
</syntaxhighlight>
</div></div>

= Add new arbitrary instances =

In some cases you may want to deliver instances of an arbitrary type the user can change to their liking.

<div class="toccolours mw-collapsible mw-collapsed" style="width:100%; overflow:auto;">
<div style="font-weight:bold;line-height:1.6;">SystemDefinitions adaptations</div>
<div class="mw-collapsible-content">
<syntaxhighlight lang="csharp">
namespace UBIK.MyPlugin
{
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

// ...
}
}
</syntaxhighlight>
</div></div>

= 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.

<div class="toccolours mw-collapsible mw-collapsed" style="width:100%; overflow:auto;">
<div style="font-weight:bold;line-height:1.6;">SystemDefinitions adaptations</div>
<div class="mw-collapsible-content">
<syntaxhighlight lang="csharp">
namespace UBIK.MyPlugin
{
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

// ...
}
}
</syntaxhighlight>
</div></div>

<!-- DO NOT REMOVE THIS -->{{Template:HowTo/End}}<!-- DO NOT REMOVE THIS -->

==See also==

* [[HowTo:Create_UBIK_Module|Create your own module]]

[[Category:How-To]]
[[Category:Module]]
1,765
edits