BMM Persistence Model and Syntax
Issuer: openEHR Specification Program | |
---|---|
Release: LANG latest |
Status: STABLE |
Revision: [latest_issue] |
Date: [latest_issue_date] |
Keywords: reflection, meta-model, UML |
© 2016 - 2022 The openEHR Foundation | |
---|---|
The openEHR Foundation is an independent, non-profit foundation, facilitating the sharing of health records by consumers and clinicians via open specifications, clinical models and open platform implementations. |
|
Licence |
Creative Commons Attribution-NoDerivs 3.0 Unported. https://creativecommons.org/licenses/by-nd/3.0/ |
Support |
Issues: Problem Reports |
Amendment Record
Issue | Details | Raiser | Completed |
---|---|---|---|
LANG Release 1.0.0 |
|||
SPECLANG-2. Add Basic Meta-Model (BMM) spec to BASE component. |
openEHR SEC |
||
Add |
T Beale |
04 Sep 2019 |
|
Add value-set constraint. |
T Beale |
26 Mar 2019 |
|
Separate from main BMM specification; |
T Beale |
27 Apr 2018 |
|
2.2.2 |
Improve and update introductory text in the Overview section. |
E Sundvall, |
03 Nov 2017 |
2.2.1 |
Rename |
C Nanjo, |
02 Mar 2017 |
2.2.0 |
Remove class |
T Beale |
20 Jun 2016 |
Add missing inheritance from |
T Beale |
18 Apr 2016 |
|
2.1.0 |
Initial writing based on ADL Workbench implementation. |
T Beale |
08 Feb 2016 |
Acknowledgements
Contributors
This specification has benefited from formal and informal input from the openEHR and wider health informatics community. The openEHR Foundation would like to recognise the following people for their contributions.
-
Patrick Langford, NeuronSong LLC, Utah, USA
-
Claude Nanjo MA African Studies., M Public Health, Cognitive Medical Systems Inc., California, USA
-
Erik Sundvall PhD, Linkoping University, Sweden
1. Preface
1.1. Purpose
This document describes a persistence model for the Basic Meta-Model (BMM) known as P_BMM
, that may be used as a basis for serialisation of BMM models. It may be considered as an approximate replacement for the UML XMI for data-only models. It is human-readable and writable, and supports generic types (open and closed), container types, and multiple inheritance.
1.2. Status
This specification is in the STABLE state. The development version of this document can be found at https://specifications.openehr.org/releases/LANG/latest/bmm_persistence.html.
Known omissions or questions are indicated in the text with a 'to be determined' paragraph, as follows:
TBD: (example To Be Determined paragraph)
1.3. Feedback
Feedback may be provided on the openEHR languages specifications forum.
Issues may be raised on the specifications Problem Report tracker.
To see changes made due to previously reported issues, see the LANG component Change Request tracker.
1.4. Conformance
Conformance of a data or software artifact to an openEHR specification is determined by a formal test of that artifact against the relevant openEHR Implementation Technology Specification(s) (ITSs), such as an IDL interface or an XML-schema. Since ITSs are formal derivations from underlying models, ITS conformance indicates model conformance.
1.5. Tooling
The openEHR ADL Workbench (AWB) fully implements this specification, and provide a convenient way of illustrating BMM semantics. The screenshots used in this specification are all from the ADL Workbench. The tool is written in the Eiffel language, and is available as open source on Github. The BMM libraries can be found in the EOMF Github repository.
A modelling tool known as Archie implements BMM in Java, and can be found in the openEHR Github area.
2. Overview
2.1. Conceptual Approach
This specification defines a model that may be used as the basis for a serial format for the Basic Meta-Model (BMM). The formalism described here is an adaptation of pure object serialisation approaches used in mainstream programming languages. Instead of directly materialising a BMM instance graph from serial form, the initial materialised form is a graph of P_BMM_XXX
classes, with a subsequent in-memory model-to-model transform step required to produce a materialised BMM model.
The P_BMM_*
classes perform two functions. Firstly, they are a modified and simplified version of the BMM_*
classes that enable for example symbolic referencing via class names, syntactical type names to be used etc, rather than the full explosion of fine-grained objects that would result from a direct serialisation of BMM_*
classes. This enables an object model represented internally (to a tool, say) in BMM
form, converted to P_BMM
form, and then serialised to a .bmm
file, to be easily readable and editable by human users.
The second is that .bmm
files function as schemas that support schema inclusion and therefore re-use, in a similar manner to the XML schema languages. Thus, a single logical BMM model can be expressed as a number of .bmm
schema files which are actually P_BMM_*
object serialisations of parts of the BMM model. A schema reading component has to resolve the schema inclusions and ultimately BMM_*
object instantiations to obtain the in-memory form of the model.
We thus talk of the P_BMM_*
classes as a 'model of a BMM schema' and the BMM_*
classes as a 'model of a BMM model', where the latter is understood as the fully computable in-memory object structure with all name references resolved to object references.
The P_BMM
format is not the only serial format possible for BMM, and alternatives, e.g. a more syntactic style reminiscent of OMG IDL, are possible.
The normal use of P_BMM schemas is as follows:
-
create one or more
.bmm
schema files, using theP_BMM_
form of the model. This is easy to understand by using the example schema and/or copying other examples; -
locate these files in a suitable place for use with a tool such as the openEHR ADL Workbench and LinkEHR.
2.2. Concrete Format
BMM models are normally expressed as schema text files that support inclusion and re-use. The default file format has historically been openEHR ODIN syntax, and BMM tools to date support this format. However any common format that can express typed object models may be used, including JSON (with type markers), YAML, and XML. The examples shown in this specification are primarily in ODIN, but a tool implementing BMM may choose to serialise in and out of another preferred format.
3. Persistence Package
3.1. Overview
The org.openehr.lang.bmm_persistence
package, shown below, defines a simplified form of the main BMM model suitable for persisting and human authoring. The openEHR BMM schemas are authored in the P_BMM
form of the BMM, using the openEHR ODIN syntax.
lang.bmm_persistence
PackageThe general approach taken in this model is that attributes named bmm_xxx
and of type BMM_XXX
are derived from the persisted attributes of the P_BMM_XXX
classes of this model. In other words, they are in-memory only references to reconstructed instances of BMM_XXX
types.
3.2. Class Definitions
3.2.1. P_BMM_MODEL_ELEMENT Class
Class |
P_BMM_MODEL_ELEMENT (abstract) |
|
---|---|---|
Description |
Persistent form of |
|
Attributes |
Signature |
Meaning |
0..1 |
documentation: |
Optional documentation of this element. |
3.2.2. P_BMM_PACKAGE_CONTAINER Class
Class |
P_BMM_PACKAGE_CONTAINER |
|
---|---|---|
Description |
Persisted form of a model component that contains packages. |
|
Attributes |
Signature |
Meaning |
1..1 |
packages: |
Package structure as a hierarchy of packages each potentially containing names of classes in that package in the original model. |
3.2.3. P_BMM_SCHEMA Class
Class |
P_BMM_SCHEMA |
|
---|---|---|
Description |
Persisted form of |
|
Inherit |
||
Attributes |
Signature |
Meaning |
0..1 |
primitive_types: |
Primitive type definitions. Persisted attribute. |
0..1 |
class_definitions: |
Class definitions. Persisted attribute. |
Functions |
Signature |
Meaning |
0..1 |
validate_created |
Implementation of |
0..1 |
load_finalise |
Implementation of |
0..1 |
merge ( |
Implementation of |
0..1 |
validate |
Implementation of |
0..1 |
create_bmm_model |
Implementation of |
1..1 |
canonical_packages (): |
Package structure in which all top-level qualified package names like |
3.2.4. P_BMM_PACKAGE Class
Class |
P_BMM_PACKAGE |
|
---|---|---|
Description |
Persisted form of a package as a tree structure whose nodes can contain more packages and/or classes. |
|
Inherit |
||
Attributes |
Signature |
Meaning |
1..1 |
name: |
Name of the package from schema; this name may be qualified if it is a top-level package within the schema, or unqualified. Persistent attribute. |
0..1 |
classes: |
List of classes in this package. Persistent attribute. |
0..1 |
bmm_package_definition: |
|
Functions |
Signature |
Meaning |
0..1 |
merge ( |
Merge packages and classes from other (from an included |
0..1 |
create_bmm_package_definition |
Generate a |
3.2.5. P_BMM_TYPE Class
Class |
P_BMM_TYPE (abstract) |
|
---|---|---|
Description |
Persistent form of |
|
Attributes |
Signature |
Meaning |
0..1 |
bmm_type: |
Result of |
Functions |
Signature |
Meaning |
0..1 |
create_bmm_type ( |
Create appropriate |
1..1 |
as_type_string (): |
Formal name of the type for display. |
3.2.6. P_BMM_CLASS Class
Class |
P_BMM_CLASS |
|
---|---|---|
Description |
Definition of persistent form of |
|
Inherit |
||
Attributes |
Signature |
Meaning |
1..1 |
name: |
Name of the class. Persisted attribute. |
0..1 |
ancestors: |
List of immediate inheritance parents. If there are generic ancestors, use |
0..1 |
properties: |
List of attributes defined in this class. Persistent attribute. |
0..1 |
is_abstract: |
True if this is an abstract type. Persisted attribute. |
0..1 |
is_override: |
True if this class definition overrides one found in an included schema. |
0..1 |
generic_parameter_defs: |
List of generic parameter definitions. Persisted attribute. |
1..1 |
source_schema_id: |
Reference to original source schema defining this class. Set during |
0..1 |
bmm_class: |
|
1..1 |
uid: |
Unique id generated for later comparison during merging, in order to detect if two classes are the same. Assigned in post-load processing. |
0..1 |
ancestor_defs: |
List of structured inheritance ancestors, used only in the case of generic inheritance. Persisted attribute. |
Functions |
Signature |
Meaning |
1..1 |
is_generic (): |
True if this class is a generic class. |
0..1 |
create_bmm_class |
Create |
0..1 |
populate_bmm_class ( |
Add remaining model elements from Current to |
3.2.7. P_BMM_GENERIC_PARAMETER Class
Class |
P_BMM_GENERIC_PARAMETER |
|
---|---|---|
Description |
Persistent form of |
|
Inherit |
||
Attributes |
Signature |
Meaning |
1..1 |
name: |
Name of the parameter, e.g. 'T' etc. Persisted attribute. Name is limited to 1 character, upper case. |
0..1 |
conforms_to_type: |
Optional conformance constraint - the name of a type to which a concrete substitution of this generic parameter must conform. Persisted attribute. |
0..1 |
bmm_generic_parameter: |
|
Functions |
Signature |
Meaning |
0..1 |
create_bmm_generic_parameter ( |
Create |
Invariants |
Inv_generic_name: |
3.2.8. P_BMM_PROPERTY Class
Class |
P_BMM_PROPERTY (abstract) |
|
---|---|---|
Description |
Persistent form of |
|
Inherit |
||
Attributes |
Signature |
Meaning |
1..1 |
name: |
Name of this property within its class. Persisted attribute. |
0..1 |
is_mandatory: |
True if this property is mandatory in its class. Persisted attribute. |
0..1 |
is_computed: |
True if this property is computed rather than stored in objects of this class. Persisted Attribute. |
0..1 |
is_im_infrastructure: |
True if this property is info model 'infrastructure' rather than 'data'. Persisted attribute. |
0..1 |
is_im_runtime: |
True if this property is info model 'runtime' settable property. Persisted attribute. |
0..1 |
type_def: |
Type definition of this property, if not a simple String type reference. Persisted attribute. |
0..1 |
bmm_property: |
BMM_PROPERTY created by create_bmm_property_definition. |
Functions |
Signature |
Meaning |
0..1 |
create_bmm_property ( |
Create |
3.2.9. P_BMM_BASE_TYPE Class
Class |
P_BMM_BASE_TYPE (abstract) |
|
---|---|---|
Description |
Persistent form of |
|
Inherit |
||
Attributes |
Signature |
Meaning |
0..1 |
value_constraint: |
3.2.10. P_BMM_SIMPLE_TYPE Class
Class |
P_BMM_SIMPLE_TYPE |
|
---|---|---|
Description |
Persistent form of |
|
Inherit |
||
Attributes |
Signature |
Meaning |
1..1 |
type: |
Name of type - must be a simple class name. |
0..1 |
bmm_type: |
Result of |
3.2.11. P_BMM_OPEN_TYPE Class
Class |
P_BMM_OPEN_TYPE |
|
---|---|---|
Description |
Persistent form of |
|
Inherit |
||
Attributes |
Signature |
Meaning |
1..1 |
type: |
Simple type parameter as a single letter like 'T', 'G' etc. |
0..1 |
bmm_type: |
Result of |
3.2.12. P_BMM_GENERIC_TYPE Class
Class |
P_BMM_GENERIC_TYPE |
|
---|---|---|
Description |
Persistent form of |
|
Inherit |
||
Attributes |
Signature |
Meaning |
1..1 |
root_type: |
Root type of this generic type, e.g. |
1..1 |
generic_parameter_defs: |
Generic parameters of the root_type in this type specifier if non-simple types. The order must match the order of the owning class’s formal generic parameter declarations. Persistent attribute. |
0..1 |
generic_parameters: |
Generic parameters of the |
0..1 |
bmm_type: |
Result of |
Functions |
Signature |
Meaning |
0..1 |
generic_parameter_refs (): |
Generic parameters of the root_type in this type specifier. The order must match the order of the owning class’s formal generic parameter declarations |
3.2.13. P_BMM_CONTAINER_TYPE Class
Class |
P_BMM_CONTAINER_TYPE |
|
---|---|---|
Description |
Persistent form of |
|
Inherit |
||
Attributes |
Signature |
Meaning |
1..1 |
container_type: |
The type of the container. This converts to the |
0..1 |
type_def: |
Type definition of |
0..1 |
type: |
The target type; this converts to the first parameter in |
0..1 |
bmm_type: |
Result of |
Functions |
Signature |
Meaning |
1..1 |
type_ref (): |
The target type; this converts to the first parameter in |
3.2.14. P_BMM_INDEXED_CONTAINER_TYPE Class
Class |
P_BMM_INDEXED_CONTAINER_TYPE |
|
---|---|---|
Description |
||
Inherit |
||
Attributes |
Signature |
Meaning |
1..1 |
index_type: |
|
0..1 |
bmm_type: |
Result of |
3.2.15. P_BMM_SINGLE_PROPERTY Class
Class |
P_BMM_SINGLE_PROPERTY |
|
---|---|---|
Description |
Persistent form of |
|
Inherit |
||
Attributes |
Signature |
Meaning |
0..1 |
type: |
If the type is a simple type, then this attribute will hold the type name. If the type is a container or generic, then type_ref will hold the type definition. The resulting type is generated in type_def. |
0..1 |
type_ref: |
Type definition of this property computed from |
0..1 |
bmm_property: |
|
Functions |
Signature |
Meaning |
1..1 |
type_def (): |
Generate |
3.2.16. P_BMM_SINGLE_PROPERTY_OPEN Class
Class |
P_BMM_SINGLE_PROPERTY_OPEN |
|
---|---|---|
Description |
Persistent form of a |
|
Inherit |
||
Attributes |
Signature |
Meaning |
0..1 |
type_ref: |
Type definition of this property computed from |
0..1 |
type: |
Type definition of this property, if a simple String type reference. Really we should use |
0..1 |
bmm_property: |
|
Functions |
Signature |
Meaning |
1..1 |
type_def (): |
Generate |
3.2.17. P_BMM_GENERIC_PROPERTY Class
Class |
P_BMM_GENERIC_PROPERTY |
|
---|---|---|
Description |
Persistent form of |
|
Inherit |
||
Attributes |
Signature |
Meaning |
0..1 |
type_def: |
Type definition of this property, if not a simple String type reference. Persistent attribute. |
0..1 |
bmm_property: |
|
3.2.18. P_BMM_CONTAINER_PROPERTY Class
Class |
P_BMM_CONTAINER_PROPERTY |
|
---|---|---|
Description |
Persistent form of |
|
Inherit |
||
Attributes |
Signature |
Meaning |
0..1 |
Cardinality of this property in its class. Persistent attribute. |
|
0..1 |
type_def: |
Type definition of this property, if not a simple String type reference. Persistent attribute. |
0..1 |
bmm_property: |
|
Functions |
Signature |
Meaning |
0..1 |
create_bmm_property ( |
Create |
3.2.19. P_BMM_INDEXED_CONTAINER_PROPERTY Class
Class |
P_BMM_INDEXED_CONTAINER_PROPERTY |
|
---|---|---|
Description |
||
Inherit |
||
Attributes |
Signature |
Meaning |
0..1 |
type_def: |
Type definition of this property, if not a simple String type reference. Persistent attribute. |
0..1 |
bmm_property: |
|
3.2.20. P_BMM_ENUMERATION Class
Class |
P_BMM_ENUMERATION |
|
---|---|---|
Description |
Persistent form of |
|
Inherit |
||
Attributes |
Signature |
Meaning |
0..1 |
item_names: |
|
0..1 |
||
0..1 |
bmm_class: |
|
3.2.21. P_BMM_ENUMERATION_STRING Class
Class |
P_BMM_ENUMERATION_STRING |
|
---|---|---|
Description |
Persistent form of |
|
Inherit |
||
Attributes |
Signature |
Meaning |
0..1 |
bmm_class: |
|
3.2.22. P_BMM_ENUMERATION_INTEGER Class
Class |
P_BMM_ENUMERATION_INTEGER |
|
---|---|---|
Description |
Persistent form of an instance of |
|
Inherit |
||
Attributes |
Signature |
Meaning |
0..1 |
bmm_class: |
|
4. BMM Persistence Syntax
4.1. Overview
A BMM schema is normally written in the ODIN syntax, although any other serialisation supporting typed object models may be used, including JSON (with type markers), YAML, XML etc. The ODIN form is described here. The structures are direct ODIN serialisations of the P_BMM_XXX
classes in the persistence
package.
4.2. Header Items
The following shows the header items of a BMM schema, which correspond to the 'persistent' attributes of the class P_BMM_SCHEMA
.
------------------------------------------------------
-- P_BMM version on which these schemas are based.
------------------------------------------------------
bmm_version = <"2.3">
------------------------------------------------------
-- schema identification
-- (schema_id computed as <rm_publisher>_<schema_name>_<rm_release>)
------------------------------------------------------
rm_publisher = <"openehr">
schema_name = <"adltest">
rm_release = <"1.0.2">
model_name = <"TEST_PKG">
------------------------------------------------------
-- schema documentation
------------------------------------------------------
schema_revision = <"1.0.36">
schema_lifecycle_state = <"stable">
schema_description = <"openEHR schema to support test archetypes">
4.4. Package Definition
The packages definition should be self-explanatory: just name the classes and packages in a recursive fashion.
Note
|
only top-level package ids can be paths (i.e. contain the '.' character) |
Note
|
only classes defined in the same schema can be referenced in the package section in that schema. |
Note
|
make sure that the ODIN 'keys' are the same as the 'name' attributes in each block. |
packages = <
["org.openehr.test_pkg"] = <
name = <"org.openehr.test_pkg">
classes = <"WHOLE", "SOME_TYPE", "BOOK", "CHAPTER", "ENTRY", "CAR", "CAR_BODY">
>
>
4.5. Class Definitions
4.5.1. Classes for Primitive Types
Definitions for primitive types in a BMM schema are just normal class definitions within a primitive_types
block. Types that are included here are usually types corresonding to primitives in target programming languages, XML schema or other downstream technologies. These types can be be detected as primitive types by tools, but otherwise are processed in the same way as types defined in the main class_definitions
group.
Note
|
unlike UML, all container types such as List<T> , Hash<V,K> etc are exlicit in a BMM schema, and consequently, such types are normally defined (including with generic parameters) in a BMM schema.
|
primitive_types = <
["Any"] = <
name = <"Any">
is_abstract = <True>
>
["Ordered"] = <
name = <"Ordered">
is_abstract = <True>
ancestors = <"Any">
>
>
4.5.2. Non-primitive Classes
The main group of class definitions in a schema occurs within the class_definitions
block. Each definition is a keyed ODIN object block correspnding to a serialised P_BMM_CLASS
object, where the key is the class name. Since name
is a BMM meta-model attribute, the class definition always contains its ODIN key.
The possible class-level meta-properties:
-
name
- class name - any capitalisation can be used, usually one of CamelCase or so-called UPPER_SNAKE_CASE; -
ancestors
- states classes from which this class inherits, as an ODIN String list; -
is_abstract
- indicates that the class cannot be instantiated directly; -
properties
- ODIN block containing definitions consisting ofP_BMM_PROPERTY
descendants, keyed by property name.
4.5.3. Simple Classes
Simple classes are those whose type is the same as the class, as opposed to generic classes and enumerated types (see below).
class_definitions = <
["ITEM"] = <
name = <"ITEM">
ancestors = <"Any">
is_abstract = <True>
properties = <
-- properties here
>
>
-- more classes here
>
4.5.3.1. Class properties
Class properties from the original model are expressed using ODIN object blocks keyed by property name. Since there are multiple possible descendants of P_BMM_PROPERTY
, ODIN type markers must be used to indicate which subtypes is used in each case.
The possible BMM meta-properties of all property types are as follows:
-
name
-String
name of the property in its owning class in the model - use camelCase or snake_case as appropriate; -
is_mandatory
-Boolean
flag indicating whether the property is mandatory within its class.
The following shows the class ELEMENT
with two properties null_flavour
and value
of BMM meta-type P_BMM_SINGLE_PROPERTY
, i.e. corresponding to a single-valued attribute from the original model.
["ELEMENT"] = <
name = <"ELEMENT">
ancestors = <"ITEM">
properties = <
["null_flavour"] = (P_BMM_SINGLE_PROPERTY) <
name = <"null_flavour">
type = <"DV_CODED_TEXT">
is_mandatory = <True>
>
["value"] = (P_BMM_SINGLE_PROPERTY) <
name = <"value">
type = <"DATA_VALUE">
>
>
>
4.5.3.2. Container Properties
The following is a P_BMM_CONTAINER_PROPERTY
definition for the model property items: List<ITEM>
in the ELEMENT
class. The type is expressed in the type_def
part which indicates the type of the container, which must be defined elsewhere in the schema, typically in the primitive types. The optional cardinality
meta-property indicates cardinality of the container, and is expressed as a ODIN range. The default is |0..*|
.
["ELEMENT"] = <
name = <"ELEMENT">
ancestors = <"ITEM">
properties = <
["items"] = (P_BMM_CONTAINER_PROPERTY) <
name = <"items">
type_def = <
container_type = <"List">
type = <"ITEM">
>
cardinality = <|>=1|>
is_mandatory = <True>
>
>
>
Indexed containers such as Hash<K,V>
, Dictionary<K,V>
etc are also suuported via the P_BMM_INDEXED_CONTAINER_PROPERTY
, the use of which is shown here:
["CALLBACK_WAIT"] = <
name = <"CALLBACK_WAIT">
ancestors = <"...">
properties = <
["custom_actions"] = (P_BMM_INDEXED_CONTAINER_PROPERTY) <
name = <"custom_actions">
type_def = <
container_type = <"Hash">
index_type = <"String">
type = <"EVENT_ACTION">
>
cardinality = <|>=0|>
>
>
>
The above represents a property custom_actions: Hash <String, EVENT_ACTION>
in the class CALLBACK_WAIT
. The meta-element index_type
is used to state the key type.
4.5.4. Generic Classes
Generic classes are those that have one or more substitutable generic type parameters. Such classes are therefore type generators, since actual types are formed by substitution of concrete types (typically simple classes) for the formal type parameters. The following example shows a generic class Interval
with generic_parameter_defs
of T
which is constrained to conform to the type Ordered
. This structure defineds the type Interval<T→Ordered>
, with the same meaning as UML and programming languages supporting generic (templated) types.
Generic classes will normally contain one or more properties whose formal type is the generic type parameter, i.e. the T
in this example, as is the case below where the model properties lower
and upper
are both declared to be of type T
. This declaration necessitates the use of the BMM meta-type P_BMM_SINGLE_PROPERTY_OPEN
.
["Interval"] = <
name = <"Interval">
ancestors = <"Any">
generic_parameter_defs = <
["T"] = <
name = <"T">
conforms_to_type = <"Ordered">
>
>
properties = <
["lower"] = (P_BMM_SINGLE_PROPERTY_OPEN) <
name = <"lower">
type = <"T">
>
["upper"] = (P_BMM_SINGLE_PROPERTY_OPEN) <
name = <"upper">
type = <"T">
>
>
>
Given the presence of generic classes in a BMM schema, derived generic types can be used as the type of properties in other classes, for which the BMM meta-type P_BMM_GENERIC_PROPERTY
is used. The folowing example shows first a generic class DV_INTERVAL
defined in a similar way to Interval
above, and then a class SOME_TYPE
containing the property qty_interval_attr
whose model type is DV_INTERVAL<DV_QUANTITY>
. In the latter type declaration, the DV_INTERVAL
is the root_type
and DV_INTERVAL
the generic_parameter
.
["DV_INTERVAL"] = <
name = <"DV_INTERVAL">
ancestors = <"Interval", "DATA_VALUE">
generic_parameter_defs = <
["T"] = <
name = <"T">
conforms_to_type = <"DV_ORDERED">
>
>
>
["SOME_TYPE"] = <
name = <"SOME_TYPE">
ancestors = <"Any", ...>
properties = <
["qty_interval_attr"] = (P_BMM_GENERIC_PROPERTY) <
name = <"qty_interval_attr">
type_def = <
root_type = <"DV_INTERVAL">
generic_parameters = <"DV_QUANTITY">
>
>
>
>
Type declarations can also be nested types, for example and container followed by a generic type. In the following the careProvider
attribute is declared to be of model type List<Reference<Party>>
. Any level of type nesting is allowed.
["Patient"] = <
name = <"Patient">
ancestors = <"Any">
properties = <
["careProvider"] = (P_BMM_CONTAINER_PROPERTY) <
name = <"careProvider">
type_def = <
container_type = <"List">
type_def = (P_BMM_GENERIC_TYPE) <
root_type = <"Reference">
generic_parameters = <"Party">
>
>
cardinality = <|>=0|>
>
>
>
The following property definition is based on the class REFERENCE_RANGE
, and in this case, has a generic parameter type that is another generic type: DV_INTERVAL<DV_QUANTITY>
. To express this, we use generic_parameter_defs
instead of just generic_parameters
to specify a type structure, rather than just a string type name. Note that generic_parameter_defs
is a logical list in general, since there can always be more than one generic parameter, i.e. 'T', 'U' etc, even though it is most commonly just one. Accordingly, the usual ODIN keyed hash structure is used with each member being keyed by a generic parameter name, below ["T"]
.
["REFERENCE_RANGE"] = <
name = <"REFERENCE_RANGE">
ancestors = <"Any">
generic_parameter_defs = <
["T"] = <
name = <"T">
conforms_to_type = <"DV_ORDERED">
>
>
properties = <
["range"] = (P_BMM_SINGLE_PROPERTY) <
name = <"range">
type = <"DV_INTERVAL">
is_mandatory = <True>
>
>
>
["RANGE_OF_INTERVAL_OF_QUANTITY"] = <
name = <"RANGE_OF_INTERVAL_OF_QUANTITY">
ancestors = <"Any", ...>
properties = <
["range"] = (P_BMM_GENERIC_PROPERTY) <
name = <"range">
type_def = <
root_type = <"REFERENCE_RANGE">
generic_parameter_defs = <
["T"] = (P_BMM_GENERIC_TYPE) <
root_type = <"DV_INTERVAL">
generic_parameters = <"DV_QUANTITY">
>
>
>
>
>
The following example just does the same as the one above, but shows an (unrealistic) but legal case of multiple, mixed, nested generic parameters corresponding to the model property definition range: REFERENCE_RANGE<DV_INTERVAL<DV_QUANTITY>, Integer, List<DV_QUANTITY>, List<DV_INTERVAL<DV_QUANTITY>>>
. The rules for expressing types is clearly illustrated:
-
use 'type' for simple string type refs; use
type_def
for structure types; -
within
P_BMM_GENERIC_TYPE
, usegeneric_parameters
for a list of string types; -
use
generic_parameter_defs
for a list of complex type references.
["CRAZY_TYPE"] = <
name = <"CRAZY_TYPE">
ancestors = <"Any">
properties = <
["range"] = (P_BMM_GENERIC_PROPERTY) <
name = <"range">
type_def = <
root_type = <"REFERENCE_RANGE">
generic_parameter_defs = <
["T"] = (P_BMM_GENERIC_TYPE) <
root_type = <"DV_INTERVAL">
generic_parameters = <"DV_QUANTITY">
>
["U"] = (P_BMM_SIMPLE_TYPE) <
type = <"Integer">
>
["V"] = (P_BMM_CONTAINER_TYPE) <
type = <"DV_QUANTITY">
container_type = <"List">
>
["W"] = (P_BMM_CONTAINER_TYPE) <
type_def = (P_BMM_GENERIC_TYPE) <
root_type = <"DV_INTERVAL">
generic_parameters = <"DV_QUANTITY">
>
container_type = <"List">
>
>
>
>
>
>
4.5.5. Enumerated Types
In a BMM schema, enumerated types are treated as constrained forms of standard types with open ranges, currently only Integer
and String
. They are accordingly represented using class definitions of the meta-types P_BMM_ENUMERATION_INTEGER
and P_BMM_ENUMERATION_STRING
respectively. In either case, just names (items_names
meta-property) or both names and values (item_values
meta-property) can be specified.
The following example shows two variants of am enumerated type based on the Integer
primitive type.
["PROPORTION_KIND"] = (P_BMM_ENUMERATION_INTEGER) <
name = <"PROPORTION_KIND">
ancestors = <"Integer">
item_names = <"pk_ratio", "pk_unitary", "pk_percent", "pk_fraction", "pk_integer_fraction">
>
["PROPORTION_KIND_2"] = (P_BMM_ENUMERATION_INTEGER) <
name = <"PROPORTION_KIND_2">
ancestors = <"Integer">
item_names = <"pk_ratio", "pk_unitary", "pk_percent", "pk_fraction", "pk_integer_fraction">
item_values = <0, 1001, 1002, 1003>
>
The following example shows two similar examples based on String
.
["MAGNITUDE_STATUS"] = (P_BMM_ENUMERATION_STRING) <
name = <"MAGNITUDE_STATUS">
ancestors = <"String", ...>
item_names = <"le", "ge", "eq", "approx_eq">
item_values = <"<=", ">=", "=", "~">
>
["NAME_PART"] = (P_BMM_ENUMERATION_STRING) <
name = <"NAME_PART">
ancestors = <"String", ...>
item_names = <"FIRST", "MIDDLE", "LAST">
>
4.5.6. Value-set Constraints
Value-sets are related to enumerated types, but rather than specifying the possible instance values for a type in an explicit enumeration type, a standard type can be marked as having values that conform to an external value set, such as a terminology. The following shows an attribute declared to be of a simple type CODE_PHRASE
in the normal way.
["encoding"] = (P_BMM_SINGLE_PROPERTY) <
name = <"encoding">
type = <"CODE_PHRASE">
>
With a value-set constraint added, it now looks as follows:
["encoding"] = (P_BMM_SINGLE_PROPERTY) <
name = <"encoding">
type_ref = <
type = <"CODE_PHRASE">
value_constraint = <"openEHR::languages">
>
>
The use of the value_constraint
attribute forces the use of the type_ref
structural form of the type definition within a P_BMM_SINGLE_PROPERTY
instance, rather than the simple String
form above.
Within a container type, the structure is slightly different, owing to another level of instance nesting. The following exmaple shows a container class declaration in original form and then with a value constraint.
-- original form
["language"] = (P_BMM_CONTAINER_PROPERTY) <
name = <"language">
type_def = <
container_type = <"List">
type = <"Coding">
>
>
-- with value constraint
["language"] = (P_BMM_CONTAINER_PROPERTY) <
name = <"language">
type_def = <
container_type = <"List">
type_def = (P_BMM_SIMPLE_TYPE) <
type = <"Coding">
value_constraint = <"hl7::Languages">
>
>
>
4.6. Inheritance
In the case of inheritance from simple classes, the ancestors
list of Strings may be used to simply name the types (which are the same as class names), as seen in the above examples. In the case of generic inheritance, the ancestors are generic types, which may be open, partially closed or fully closed. The following example shows a class model containing generic inheritance in UML (using the closest approximation available in UML), followed by the equivalent P_BMM schema. In the latter, a structured ancestor_defs
section is used instead of the ancestors
String list, in the same way as for the P_BMM_GENERIC_PROPERTY
examples above.
["GENERIC_PARENT"] = <
name = <"GENERIC_PARENT">
generic_parameter_defs = <
["T"] = <
name = <"T">
conforms_to_type = <"SUPPLIER">
>
["U"] = <
name = <"U">
conforms_to_type = <"SUPPLIER">
>
>
properties = <
["property_a"] = (P_BMM_SINGLE_PROPERTY_OPEN) <
name = <"property_a">
type = <"T">
>
["property_b"] = (P_BMM_SINGLE_PROPERTY_OPEN) <
name = <"property_b">
type = <"U">
>
>
>
["SUPPLIER"] = <
name = <"SUPPLIER">
is_abstract = <True>
properties = <
["abstract_prop"] = (P_BMM_SINGLE_PROPERTY) <
name = <"abstract_prop">
type = <"String">
>
>
>
["SUPPLIER_A"] = <
name = <"SUPPLIER_A">
ancestors = <"SUPPLIER">
properties = <
["magnitude"] = (P_BMM_SINGLE_PROPERTY) <
name = <"magnitude">
type = <"Double">
is_mandatory = <True>
>
["units"] = (P_BMM_SINGLE_PROPERTY) <
name = <"units">
type = <"String">
is_mandatory = <True>
>
>
>
["SUPPLIER_B"] = <
name = <"SUPPLIER_B">
ancestors = <"SUPPLIER">
properties = <
["property"] = (P_BMM_SINGLE_PROPERTY) <
name = <"property">
type = <"CODE_PHRASE">
is_mandatory = <True>
>
["precision"] = (P_BMM_SINGLE_PROPERTY) <
name = <"precision">
type = <"Integer">
>
>
>
["GENERIC_CHILD_OPEN_T"] = <
name = <"GENERIC_CHILD_OPEN_T">
ancestor_defs = <
["GENERIC_PARENT<T,SUPPLIER_B>"] = (P_BMM_GENERIC_TYPE) <
root_type = <"GENERIC_PARENT">
generic_parameters = <"T", "SUPPLIER_B">
>
>
generic_parameter_defs = <
["T"] = <
name = <"T">
conforms_to_type = <"SUPPLIER">
>
>
properties = <
["gen_child_open_t_prop"] = (P_BMM_SINGLE_PROPERTY) <
name = <"gen_child_open_t_prop">
type = <"String">
>
>
>
["GENERIC_CHILD_OPEN_U"] = <
name = <"GENERIC_CHILD_OPEN_U">
ancestor_defs = <
["GENERIC_PARENT<SUPPLIER_A,U>"] = (P_BMM_GENERIC_TYPE) <
root_type = <"GENERIC_PARENT">
generic_parameters = <"SUPPLIER_A", "U">
>
>
generic_parameter_defs = <
["U"] = <
name = <"U">
conforms_to_type = <"SUPPLIER">
>
>
properties = <
["gen_child_open_u_prop"] = (P_BMM_SINGLE_PROPERTY) <
name = <"gen_child_open_u_prop">
type = <"String">
>
>
>
["GENERIC_CHILD_CLOSED"] = <
name = <"GENERIC_CHILD_CLOSED">
ancestor_defs = <
["GENERIC_PARENT<SUPPLIER_A,SUPPLIER_B>"] = (P_BMM_GENERIC_TYPE) <
root_type = <"GENERIC_PARENT">
generic_parameters = <"SUPPLIER_A", "SUPPLIER_B">
>
>
properties = <
["gen_child_closed_prop"] = (P_BMM_SINGLE_PROPERTY) <
name = <"gen_child_closed_prop">
type = <"String">
>
>
>
>