Adding Relationships to Abstract Base Classes

So maybe you’ve had a idea of some data that makes sense for every everything ever. One of mine is a Maintainer relationship for every CI to go along with the owner relationship that comes out of the box. This would give us one person (or group) who could be assigned to any incident or service request that affected the CI in question, to go along with my Data Owner Must Approve for reviews.

Try to do this through the Authoring tool, and it won’t let you extend an abstract base class. Loverly error provided:

Abstract.Class

The Solution:

If you need a relationship only, and not a property, then you can modify the XML to make this work. Go into the authoring tool and open or create a concrete class, preferably one that inherits from the abstract class you mean to extend. Create a new relationship sourced from the concrete class, targeted at whatever concrete or abstract class you mean to target. In my example, I created a new relationship from Windows computer to System.User, and called it “Maintained By User”. Save your MP, and go get your favorite XML editor.

You’ll want to locate the <RelationshipType> entry for your new relationship. should look like this:

RelationshipType MP XML

take a look at the red highlighted section. that’s the Class Type of the Source Object. In your MP, it’s going to reference the sealed MP alias and the MP Object that you selected as your concrete class. you’ll want to change it to MP Alias and Internal Name the abstract class; in this example, it’s System!System.ConfigItem, which is the abstract base class Configuration Item.

Here is a Demo MP that contains a new custom CI class, the new CI relationship, a custom type projection that includes the new relationship:

<ManagementPack ContentReadable="true" SchemaVersion="2.0" OriginalSchemaVersion="1.1" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <Manifest>
    <Identity>
      <ID>ServiceManager.AbstractRelationships.DemoLibrary</ID>
      <Version>3.0.10.3</Version>
    </Identity>
    <Name>ServiceManager.AbstractRelationships.DemoLibrary</Name>
    <References>
      <Reference Alias="System">
        <ID>System.Library</ID>
        <Version>7.5.8501.0</Version>
        <PublicKeyToken>31bf3856ad364e35</PublicKeyToken>
      </Reference>
      <Reference Alias="Console">
        <ID>Microsoft.EnterpriseManagement.ServiceManager.UI.Console</ID>
        <Version>7.5.2905.0</Version>
        <PublicKeyToken>31bf3856ad364e35</PublicKeyToken>
      </Reference>
      <Reference Alias="WorkItem">
        <ID>System.WorkItem.Library</ID>
        <Version>7.5.2905.0</Version>
        <PublicKeyToken>31bf3856ad364e35</PublicKeyToken>
      </Reference>
      <Reference Alias="SupportingItem">
        <ID>System.SupportingItem.Library</ID>
        <Version>7.5.1561.0</Version>
        <PublicKeyToken>31bf3856ad364e35</PublicKeyToken>
      </Reference>
      <Reference Alias="CoreKnowledge">
        <ID>System.Knowledge.Library</ID>
        <Version>7.5.1561.0</Version>
        <PublicKeyToken>31bf3856ad364e35</PublicKeyToken>
      </Reference>
      <Reference Alias="ConfigurationManagement">
        <ID>ServiceManager.ConfigurationManagement.Library</ID>
        <Version>7.5.1561.0</Version>
        <PublicKeyToken>31bf3856ad364e35</PublicKeyToken>
      </Reference>
    </References>
  </Manifest>
  <TypeDefinitions>
    <EntityTypes>
      <ClassTypes>
        <ClassType ID="NewCustomCIClass" Accessibility="Public" Abstract="false" Base="System!System.ConfigItem" Hosted="false" Singleton="false" Extension="false">
          <Property ID="Title" Type="string" AutoIncrement="false" Key="true" CaseSensitive="false" MaxLength="256" MinLength="0" Required="false" Scale="0" />
        </ClassType>
      </ClassTypes>
      <RelationshipTypes>
        <RelationshipType ID="System.ConfigItemMaintainedByUser" Accessibility="Public" Abstract="false" Base="System!System.Reference">
          <Source ID="ConfigItem" MinCardinality="0" MaxCardinality="2147483647" Type="System!System.ConfigItem" />
          <Target ID="MaintainedByUser" MinCardinality="0" MaxCardinality="1" Type="System!System.User" />
        </RelationshipType>
      </RelationshipTypes>
      <TypeProjections>
        <TypeProjection ID="NewCustomCIClass.Form_TypeProjection" Accessibility="Public" Type="NewCustomCIClass">
          <Component Path="$Context/Path[Relationship='System!System.ConfigItemOwnedByUser']$" Alias="OwnedByUser" />
          <Component Path="$Context/Path[Relationship='WorkItem!System.WorkItemRelatesToConfigItem' SeedRole='Target']$" Alias="ImpactedWorkItem" />
          <Component Path="$Context/Path[Relationship='WorkItem!System.WorkItemAboutConfigItem' SeedRole='Target']$" Alias="RelatedWorkItem" />
          <Component Path="$Context/Path[Relationship='SupportingItem!System.ConfigItemHasFileAttachment']$" Alias="FileAttachment" />
          <Component Path="$Context/Path[Relationship='System!System.ConfigItemRelatesToConfigItem']$" Alias="RelatedConfigItem" />
          <Component Path="$Context/Path[Relationship='System!System.ConfigItemRelatesToConfigItem' SeedRole='Target']$" Alias="RelatedConfigItemSource" />
          <Component Path="$Context/Path[Relationship='CoreKnowledge!System.EntityLinksToKnowledgeDocument']$" Alias="RelatedKnowledgeArticles" />
          <Component Path="$Context/Path[Relationship='System.ConfigItemMaintainedByUser']$" Alias="MaintainedByUser" />
        </TypeProjection>
      </TypeProjections>
    </EntityTypes>
  </TypeDefinitions>
  <Categories>
    <Category ID="ServiceManager.AbstractRelationships.DemoLibrary.Category" Value="Console!Microsoft.EnterpriseManagement.ServiceManager.ManagementPack">
      <ManagementPackName>ServiceManager.AbstractRelationships.DemoLibrary</ManagementPackName>
      <ManagementPackVersion>1.0.0.0</ManagementPackVersion>
    </Category>
  </Categories>
  <LanguagePacks>
    <LanguagePack ID="ENU" IsDefault="true">
      <DisplayStrings>
        <DisplayString ElementID="ServiceManager.AbstractRelationships.DemoLibrary">
          <Name>ServiceManager.AbstractRelationships.DemoLibrary</Name>
        </DisplayString>
        <DisplayString ElementID="NewCustomCIClass">
          <Name>New Custom CI Class</Name>
          <Description>Demo Security Role</Description>
        </DisplayString>
        <DisplayString ElementID="NewCustomCIClass" SubElementID="Title">
          <Name>Title</Name>
        </DisplayString>
        <DisplayString ElementID="System.ConfigItemMaintainedByUser">
          <Name>Config Item Maintained By User</Name>
        </DisplayString>
        <DisplayString ElementID="System.ConfigItemMaintainedByUser" SubElementID="ConfigItem">
          <Name>ConfigItem</Name>
        </DisplayString>
        <DisplayString ElementID="System.ConfigItemMaintainedByUser" SubElementID="MaintainedByUser">
          <Name>Maintained By User</Name>
        </DisplayString>
      </DisplayStrings>
    </LanguagePack>
  </LanguagePacks>
</ManagementPack>

You’ll notice I’ve made a few other minor adjustments, specifically around the DisplayStrings and Internal Names of the Source & Target of the relationship. This just makes it easier to read if you’re looking at the relationship through the SDK or PowerShell.

In Other News:

Microsoft has strongly implied it’s unsupported to extend an abstract base class in Service Manager. I do not believe this method falls under that restriction, since:

  1. Adding a relationship doesn’t actually modify either the source or target classes, but instead adds a third relationship class that links the source & target classes together.
  2. They don’t prevent us adding a relationship that targets an abstract class.

Notwithstanding, I have no insight into MS Support Rules, and MS has never made it clear if this is an architecture, design, practical or implementation limitation, so Caveat Diem or some such.

Advertisements