Skip to end of metadata
Go to start of metadata

Choosing an approach

I'm hoping for an abstract solution such that I can define this in a single place and use it for all types. I see two likely paths forward, one putting the methods into KrmsTypeRepositoryService and the other putting them in the type services themselves. pros/cons of each:

Put all the type-type relation functionality into the KrmsTypeRepositoryService

(plus) KrmsTypeRepositoryService is already in the business of dealing with KrmsTypeDefinition, additional methods will feel at home here
(plus) The specification and implementation is more consolidated and doesn't impact type service interfaces
(plus) Type-type relations will all be configured the same way (no overriding in specific type services)

Put the type-type relation functionality into the type services themselves

(plus) There would be flexibility to customize how type-type relations are derived for specific type services. Use cases?
(plus) Method signatures would be simpler since the type itself wouldn't be a parameter
(plus) May cut down on some direct dependencies to the KrmsTypeRepositoryService

The advantages seem more significant for putting it in KrmsTypeRepositoryService, so I'll start there and see how that goes.

Schema additions / changes

To store type-type relations we'll need to modify the krms repository schema. First, a new table to hold the relation entries:

Also, we'll nee to be able to distinguish service types in the repository. Otherwise, there is no way to know the difference between nonsense associations that don't respect the natural hierarchy of governing entities, and meaningful ones. To help illustrate the difference between a meaningful association and a meaningless one, consider the following: (Note that in this table, each row represents a relation)


From type

To type







The first row doesn't make sense because a Context is a container that holds underneath it (several layers beneath) Propositions, and thus while perhaps a Context could relate to a Proposition in this way, a Proposition doesn't have occasion to make use of a Context. The second row does make sense since a Rule is a container holding a tree of Propositions.

Without some tag to tell what type of service the type is for, one would have to get hold of the service instances themselves and reflect on them to determine what type of services are being related. That is messy and doesn't make much sense if we want to be able to configure these relations within an administrative page.

To be able to discern these differences easily, a new column is needed in krms_typ_t. This column would hold some key for the service interface (the fully qualified interface name would work):

Of course, we also need to add a serviceType getter to the KrmsTypeDefinitionContract, and member fields to all i8ts implementors – and don't forget to update the ORM configuration too. With that in place, we can easily determine the types of services that a relation is spanning. With some extension, we could also use that information to limit the relations allowed between certain types of services, or prohibit certain types of relations altogether (this would be easiest to achieve through validation code). To facilitate this, the following configuration parameter could be added as well:

Here are the KRMS type tables including these additions:


TODO: update diagram to take out krms_typ_reln_vld_t

Interface additions

First, we'll need a class to hold our relation:

Next, we add any needed methods to the KrmsTypeRepositoryService for maintaining and accessing relations

Other details

One nuance of our implementation is that for repository entites with krms type IDs, setting a null type ID results in using a default type service. For example, if you create an agenda and don't specify a type, the type ID will be set to null, and when that agenda is translated to executable form, the default AgendaTypeService will be used.

When we move to using types to constrain the types available on child entities, there will be a greater use of types in the system as a means to hold this configuration data, and so the defaulting of null type IDs will not be as helpful as there will be fewer cases where null type IDs will be an option. In order to keep the configuration as simple as we can, I suggest that we modify our type translation (see RepositoryToEngineTranslator) in such a way that a KRMS type with a null service name will result in the default type service being used.

Usage examples?

Here's a method from a (hypothetical) ValuesFinder used for populating a select list of available proposition types in some KRMS UI:

validate that the proposition type is valid given the rule type

get all related types

add a type relation

delete a TypeRelation object

Backward compatibility

In order to make the proposed changes without breaking applications such as KC and OLE who have implemented with the above method of valid types being specified, we will need to respect both the legacy configuration mechanism for restricting available types as well as the new one.  Please note that the intent is to deprecate the old approach of restricting types in favor of using type relations. 

Legacy mapping of valid types

The legacy system for limiting available types in KRMS works by mapping from a context instance to the valid types. To state this more concretely, a context (call it 'CONTEXT1') has associations to some specific agenda types ('AwesomeAgendaTypeService', 'OkayAgendaTypeService', ...) specifying that they can be used within it. There are a few specific KRMS types that can be associated in this way, and there is a table-per-type to support these associations. The tables are:




specifies the valid action types that can be used within the context


specifies the valid agenda types that can be used within the context


specifies the valid rule types that can be used within the context

These tables all have structures similar to the following:

You can also see the pertinent part of the schema on the upper left hand side of this diagram: krms.png

Example backwards compatible implementation

Achieving this should not be particularly difficult, it merely requires querying for the valid types using both methods, and taking the union of the two result sets. So for example, the following method could be used to return the available rule types using the context ID and the agenda type ID:

Default Proposition Types:

Another backward compatibility note: if there are no type relations specifying the allowed proposition types, then the built in simple and compound proposition types will be allowed by default. This will support legacy data as previously there were no constraints on allowed proposition types, but the UI only supported compound and simple propositions.

  • No labels

1 Comment

  1. Having gone the route of generating new classes that puts use going down the 2nd implementation option, giving TypeTypeRelationship its own Service