Conflicting specifications in Archie's BuiltinReferenceModels class

In Archie there is a list of specifications in class BuiltinReferenceModels from which the repository is built.

I used this list to build a repository in my implementation (which is using Dart language).

I get errors due to the conflicting definition of the EVENT type. It is defined as a SimpleType in

bmm/openEHR/components/RM/Release-1.0.3/openehr_structures_103.bmm

but as a GenericType in

bmm/openEHR/components/RM/Release-1.1.0/openehr_rm_structures_110.bmm

Archie doesn’t treat these errors as exceptions during the validation but it keeps them in the validation results.
(these conflicts occur in class PBmmContainerType.createBmmType())
Edit: Archie catches the duplicates with DUPLICATE_CLASS_IN_PACKAGES.

Should I just remove the conflicting specifications (I guess most of RM/Release-1.1.0)?

Or should I start with a top specification and let it include the specifications it requires?
(e.g. specifications-ITS-BMM/components/RM/Release-1.0.3/openehr_ehr_103.bmm)

Or is something else that I’m doing wrong :man_shrugging:


Passed and failed validations in my implementation (scrollable):

Validation result of openehr_lang_1.0.0: Passed
Validation result of openehr_ehr_1.0.3: Failed
Validation result of openehr_rm_1.0.3: Failed
Validation result of openehr_rm_ehr_1.1.0: Passed
Validation result of openehr_primitive_types_1.0.3: Passed
Validation result of openehr_structures_1.0.2: Passed
Validation result of openehr_rm_structures_1.0.4: Passed
Validation result of openehr_rm_demographic_1.0.4: Passed
Validation result of openehr_rm_demographic_1.1.0: Passed
Validation result of openehr_ehr_extract_1.0.3: Failed
Validation result of openehr_basic_types_1.0.2: Passed
Validation result of openehr_rm_ehr_1.0.4: Passed
Validation result of openehr_basic_types_1.0.3: Passed
Validation result of openehr_proc_task_planning_2.0.0: Failed
Validation result of openehr_base_1.1.0: Passed
Validation result of openehr_ehr_extract_9.9.9: Failed
Validation result of openehr_rm_ehr_extract_1.0.4: Passed
Validation result of openehr_rm_data_types_1.0.4: Passed
Validation result of openehr_demographic_1.0.2: Passed
Validation result of openehr_rm_1.0.2: Passed
Validation result of openehr_rm_1.1.0: Passed
Validation result of openehr_rm_1.0.4: Passed
Validation result of openehr_demographic_1.0.3: Failed
Validation result of openehr_proc_task_planning_1.0.0: Failed
Validation result of openehr_base_1.0.0: Passed
Validation result of openehr_rm_ehr_extract_1.1.0: Passed
Validation result of openehr_ehr_1.0.2: Passed
Validation result of openehr_rm_data_types_1.1.0: Passed
Validation result of openehr_structures_1.0.3: Failed
Validation result of openehr_primitive_types_1.0.2: Passed
Validation result of openehr_rm_structures_1.1.0: Passed

I am the main maintainer of the BMM files; I’m surprised to see a static list of paths in that Java class. I would suggest it should at least be replaced with a routine to find all paths with ‘openehr’ in the filename. Then, there needs to be logic that selects the most recent version of any BMM, at least for most purposes, i.e. RM/Release-1.1.0 is a replacement for RM/Release-1.0.4 and all previous versions - we fix errors in these schemas as time goes on. This means performing a version id comparison, i.e. determining that ‘1.1.0’ is more recent than ‘1.0.4’ etc.

1 Like

I believe I figured it out.

RM releases 1.0.3, 1.0.4 and 1.1.0 work well together. They only clash with the original RM release 1.0.2.

I’ve implemented automated loading of the included schemas and can now use much simpler list of included specifications:

  static const _specifications = [
    // 'original/Release-1.0.2/openehr_ehr_102.bmm',
    //'RM/Release-1.0.3/openehr_rm_103.bmm',
    //'RM/Release-1.0.4/openehr_rm_104.bmm',
    'RM/Release-1.1.0/openehr_rm_110.bmm',
    'PROC/Release-1.5.0/openehr_proc_task_planning_150.bmm',  // Works with RM >=1.0.4
  ];

Results (scrollable):

Parsing: RM/Release-1.1.0/openehr_rm_110.bmm
  Includes:
    Parsing: RM/latest/openehr_rm_ehr_extract.bmm
      Includes:
        Parsing: RM/latest/openehr_rm_ehr.bmm
          Includes:
            Parsing: RM/latest/openehr_rm_structures.bmm
              Includes:
                Parsing: RM/latest/openehr_rm_data_types.bmm
                  Includes:
                    Parsing: BASE/Release-1.1.0/openehr_base_110.bmm
        Parsing: RM/latest/openehr_rm_demographic.bmm
          Includes:
            Already in repository: RM/latest/openehr_rm_structures.bmm
Parsing: PROC/Release-1.5.0/openehr_proc_task_planning_150.bmm
  Includes:
    Already in repository: RM/latest/openehr_rm_ehr.bmm
    Already in repository: RM/latest/openehr_rm_demographic.bmm
    Parsing: LANG/Release-1.0.0/openehr_lang_100.bmm
      Includes:
        Already in repository: BASE/Release-1.1.0/openehr_base_110.bmm
Loading: openehr_rm_demographic_1.1.0
Loading: openehr_rm_structures_1.1.0
Loading: openehr_rm_data_types_1.1.0
Loading: openehr_base_1.1.0
Loading: openehr_lang_1.0.0
Loading: openehr_rm_ehr_extract_1.1.0
Loading: openehr_rm_ehr_1.1.0
Loading: openehr_proc_task_planning_1.5.0
Loading: openehr_rm_1.1.0
Valid models:
  Validation result of openehr_rm_demographic_1.1.0: Passed
  Validation result of openehr_lang_1.0.0: Passed
  Validation result of openehr_rm_ehr_extract_1.1.0: Passed
  Validation result of openehr_base_1.1.0: Passed
  Validation result of openehr_rm_data_types_1.1.0: Passed
  Validation result of openehr_rm_ehr_1.1.0: Passed
  Validation result of openehr_proc_task_planning_1.5.0: Passed
  Validation result of openehr_rm_structures_1.1.0: Passed
  Validation result of openehr_rm_1.1.0: Passed
1 Like

Thank you for the explanation. And thank you for the BMM files. They let me skip XML, JSON files when building the refence model. They are also good for learning specifications in a concise way.

I’ve looked into where Archie uses that list. It is only used for testing.

I should never have used Archie’s list without checking how it is used. I’ve spent a day debugging my code due to that. But it was a good day - I learned a lot about the schemas.

1 Like

I am not sure what problem you are reporting. Archie loads different versions of the BMM files, and you will have to select the correct one for your use case. Because those are different releases of the RM there will indeed be changes between the different releases. That should not cause validation errors. You list some validation errors in the task planning BMMs. I think those may need updating to a more recent version. That should not affect the more often used parts of the RM.

The built in reference models are not just included for testing. They are also there to make Archie just work, without any more setup. They are a separate module, so you can choose to not depend on them and use Archie with your own BMM files, if you choose.

Archie has as a selectModel(Archetype) method on the MetaModels class to select the correct RM metadata based on the archetype. That can help.

The list of included files in the BuiltinReferenceModels is static for a reason: it’s included on the classpath in a jar, as a resource. That is different from files on a file system. We have not found a way to scan these that works on both android and other JVMs. So, we made a couple of things static references to make most of Archie work on android, including this set of files in the built in reference models convenience class.

Of course if you load your own BMM files, you can use any method of loading the BMM files, including scanning part of a file system. Just provide them as Input streams to the BMM repository. The Archie readme contains an example on how to parse and validate BMM files.

Ah wait, are you saying the task planning model validates correctly if only rm 1.1.0 is loaded, but not if also rm 1.0.2 is present? If so, that sounds like a bug, either in Archie or in the task planning BMM files.

I apologize for implying there is a problem with Archie. The fact is that I used that list incorrectly in my implementation.

I studied Archie before starting my implementation. I’m thankful that I could look at Archie. It saved a lot of time by confirming that my approach is similar to a proven implementation.


My notes which RM and Task Planning releases work together:

  • ‘RM/Release-1.1.0/openehr_rm_110.bmm’
  • ‘PROC/Release-1.5.0/openehr_proc_task_planning_150.bmm’, // Works with RM >=1.0.4

Task Planning releases from 1.6.0 have the mentioned change in the EVENT type and will require a newer release of the RM:

  • ‘PROC/Release-1.0.0/openehr_proc_task_planning_100.bmm’, // Doesn’t work with >=1.0.3 <=1.1.0
  • ‘PROC/Release-1.6.0/openehr_proc_task_planning_latest.bmm’, // Doesn’t work with >=1.0.3 <=1.1.0: it has a duplicate class for EVENT.
  • ‘PROC/latest/openehr_proc_task_planning_latest.bmm’, // Doesn’t work with >=1.0.3 <=1.1.0: it has a duplicate class for EVENT.

Archie correctly reports the missmatches in the BmmValidationResult but it ignores them.

Ah, the problem is that archie uses an older task planning BMM, which refers to the rm version 1.0.4 inside of the BMM. Archie correctly parses and links it to the correct RM version, and then reports an error because that file really is broken. There is no live version updating, it just uses the exact same version specified in the BMM files.

I will create a pull request later to add the more recent BMMs to Archie and will check if they do validate.

Are you creating your own BMM implementation?

Yes. I have created one in Dart language (the one Flutter is using).

I’m currently writing support for generating Dart classes out of the RM which is built in-memory from BMM.

Next is reading ADL and hopefuly generate forms in Flutter :crossed_fingers:

4 Likes

Progress report: I finished generating Dart classes for the RMs. There are 269 classes generated for RM 1.1.0 + Task Planning 1.5.0.

Dart doesn’t support multiple inheritance like it is used in the specifications (and in Java). I used mixins and implements to solve it.

Dart also doesn’t allow overriding property types in descendants. Example:

  • DvQuantified is an abstract class with property Object? accuracy.
  • DvAmount extends DvQuantified and overrides the property with a more specific type as Real? accuracy.

This is not allowed in Dart. It was a bit tricky to solve this as specifications don’t have a flag that properties are overrides. It takes some walking up all the ascendants and back down all their descendants to figure out where a property was overridden the last time.


I forgot to take a look at how Archie solves this :blush:

It uses generics:

public abstract class DvAmount<DataValueType extends DvAmount<DataValueType, MagnitudeType>, MagnitudeType extends Comparable<MagnitudeType>> extends DvQuantified<DataValueType, Double, MagnitudeType> {

This was also how I expected this to be specified in the specifications. But it isn’t (I remember reading that generics weren’t “working” in Java when the specs were first created).

I could generate Dart classes using generics similar to Archie. Should I?

If these classes turn out to be used as simple data objects, then it doesn’t matter. From a developers perspective using generics is a “proper” but long winded way which turns out to be unreadable.

I’ll see if the initial approach of “simple” works. If it doesn’t I’ll use the “proper” way.

@pieterbos Is the above Archie code generated or written by hand?

They didn’t work properly in any language. We took care to absolutely minimise multiple inheritance to the kind found in languages like Java. The ability to override covariantly was also not supported in many languages early on; support is still patchy, even though it was worked out in about 1986 and implemented in some languages back then.

Anyway you should be able to interrogate the BMM model using Archie’s implementation - that’s what it’s for - asking questions like which class is property X first defined in and so on.

1 Like

Thank you for the explanation. Totally understandable that some things could be different if they were started today.

My implementation is not in Java so I cannot use Archie to interrogate the BMM model. I had to implement this part in Dart.


@thomas.beale May I use this topic to ask where to find the AOM BMM file?

I cannot find them in GitHub - openEHR/specifications-ITS-BMM: BMM schemas for use with openEHR systems and tools but I found them in a test folder in Archie: archie/openEHR_aom_206.bmm at master · openEHR/archie · GitHub

Yes, the entire RM and AOM implementation in Archie is hand-coded.

As far as I know, that does not exist. This branch in Archie has a file that converts the internal meta model of the archie implementation to a P_BMM model, which can be written to a BMM file. This is how the BMM file you point is generated, as you can see in the metadata at the top of the BMM file:

So the ModelInfoLookupToPBmmConverter is the class you need for that. It’s not perfect, but might be good enough for your needs, perhaps with some improvements.

That branch this link points to also has an openAPI file generator. It can generate openAPI files both the RM and AOM, and that can be used to generate RM and AOM implementations with widely available code generators.

Another question, what are you planning to do with your code? Will this be an open source library?

1 Like

I needed to remove 4 classes from your openEHR_aom_206.bmm:

  • AUTHORED_RESOURCE

  • RESOURCE_DESCRIPTION

  • RESOURCE_DESCRIPTION_ITEM

  • TRANSLATION_DETAILS

They are already defined in the openehr_base_110.bmm.

After running the generator, 61 new classes were generated for AOM.

I would like to use BMM files as a single source of openEHR specifications. I believe they were meant to be used for generating as much of the code as possible for openEHR applications.

There are 330 classes generated for 3 RMs I’m using. They have everything from the BMM transferred to them. If BMMs are changed or documentation added, the generator will update the source code files. Developers might benefit from reading the documentation provided by the BMM author(s).

Even better when new releases are published. Again all the classes are generated/updated automatically.

There are 347 lines of code to generate Dart classes from the RMs. To generate Kotlin/TypeScript/C#/Go source code, only about 150 lines need to be changed.


By coincidence, I learnt about openEHR only 27 days ago. After reading about it for 11 days I was excited to know it better.

I decided to learn by writing a generator of RM classes from BMM specifications.

This code is only 15 days old. It is too young to decide what to do with it.

I do have some plans about writing more code:

  • read OPT and create an in-memory model using the generated RM classes

  • generate base Flutter widgets for 330 RM classes and use them to generate a form for the OPT

  • add support for designing generated Flutter forms

  • add support for running designed form in a Flutter runtime or generate a complete Flutter app for the form(s)

One day at a time. Let’s see how far I can get.

My addvantage is being unaware of all the complications people with years of experience in openEHR know about.

1 Like

In case somebody stumbles on this same problem…

I’m thankful to @pieterbos for providing AOM BMM in the Archie!
(I cannot find this file in the BMM specifications)

The AOM BMM was generated by Archie with upper-case type names when other BMM files use PascalCase.

Since my code treats everything found in BMMs as case-sensitive, I renamed e.g. type = <"STRING"> to type = <"String">.

p.s.

It took some time for my eyes to see the difference between STRING and String :flushed:

1 Like

Ah yes, the normal classes are all UPPER_CASE. Except for some base types such as string. The bmm converter does not handle that difference properly currently, and for the Json schema/openapi use case it did not matter.

Better would be to have a proper aom bmm file. This one does work, but possibly contains a couple of fields too many, and possibly contains a couple of things that could be done better if done manually instead of being autogenerated from the java implementation.

1 Like

I may build one :wink:

1 Like