From 94d9fb0ea54b602c48363fae98f9e717022947bd Mon Sep 17 00:00:00 2001 From: Jelte Zeilstra Date: Thu, 12 Jun 2025 11:30:27 +0200 Subject: [PATCH 01/25] Replace MetaModels class with MetaModelProviders (#690) * Refactor MetaModels * Replace or deprecate usages of MetaModels * Deprecate MetaModelInterface * Add SimpleMetaModelProviderTest --- README.md | 14 +- .../ADL14DefaultMultiplicitiesSetter.java | 24 +- .../archie/adl14/ADL14NodeIDConverter.java | 22 +- .../com/nedap/archie/adl14/ADL14Parser.java | 26 +- .../com/nedap/archie/adlparser/ADLParser.java | 35 ++- .../ReflectionConstraintImposer.java | 8 + .../adlparser/treewalkers/ADLListener.java | 24 +- .../treewalkers/CComplexObjectParser.java | 23 ++ .../com/nedap/archie/aom/utils/AOMUtils.java | 26 ++ .../com/nedap/archie/rminfo/MetaModel.java | 4 + .../archie/rminfo/MetaModelInterface.java | 4 + .../archie/rminfo/MetaModelProvider.java | 75 +++++ .../com/nedap/archie/rminfo/MetaModels.java | 123 ++++---- .../rminfo/NoModelSelectedException.java | 4 + .../rminfo/OverridingMetaModelProvider.java | 84 ++++++ .../rminfo/SimpleMetaModelProvider.java | 98 +++++++ referencemodels/build.gradle | 1 + .../BuiltinReferenceModels.java | 20 +- .../OverridingMetaModelProviderTest.java | 47 +++ .../rminfo/SimpleMetaModelProviderTest.java | 267 ++++++++++++++++++ .../BuiltInReferenceModelsTest.java | 1 + .../nedap/archie/adl14/ADL14Converter.java | 23 +- .../adl14/DefaultRmStructureRemover.java | 40 ++- .../ArchetypeValidation.java | 12 +- .../ArchetypeValidationBase.java | 10 +- .../ArchetypeValidator.java | 48 ++-- .../validations/AnnotationsValidation.java | 2 +- .../validations/AttributeTupleValidation.java | 2 +- .../BasicTerminologyValidation.java | 2 +- .../validations/CodeValidation.java | 2 +- .../DefinitionStructureValidation.java | 2 +- .../validations/FlatFormValidation.java | 4 +- .../validations/RmOverlayValidation.java | 2 +- .../SpecializedDefinitionValidation.java | 12 +- .../SpecializedOccurrencesValidation.java | 10 +- .../ValidateAgainstReferenceModel.java | 12 +- .../VariousStructureValidation.java | 6 +- .../ExampleJsonInstanceGenerator.java | 23 +- .../com/nedap/archie/diff/Differentiator.java | 25 +- .../nedap/archie/diff/LCSOrderingDiff.java | 12 +- .../archie/flattener/CAttributeFlattener.java | 8 +- .../com/nedap/archie/flattener/Flattener.java | 54 ++-- .../flattener/FullArchetypeRepository.java | 28 +- .../flattener/IAttributeFlattenerSupport.java | 8 + .../flattener/OperationalTemplateCreator.java | 2 +- .../FlatJsonExampleInstanceGenerator.java | 34 ++- ...ADL14DefaultOccurrencesConversionTest.java | 4 +- ...DL14ExternalTerminologyConversionTest.java | 8 +- .../adl14/ADL14InternalTerminologyTest.java | 4 +- .../adl14/ADL14TerminologyConversionTest.java | 4 +- .../adl14/ArchetypeSlotConversionTest.java | 4 +- .../adl14/AssumedValueConversionTest.java | 6 +- .../adl14/ConversionConfigurationTest.java | 6 +- .../archie/adl14/DvScaleConversionTest.java | 4 +- .../archie/adl14/LargeSetOfADL14sTest.java | 12 +- .../adl14/PreviousLogConversionTest.java | 32 +-- .../adlparser/AomUtilsPathFindingTest.java | 13 +- .../archie/adlparser/RMPathQueryTest.java | 6 +- .../archie/aom/ArchetypeTerminologyTest.java | 4 +- .../aom/TerminologyCodeConstraintsTest.java | 2 +- .../ArchetypeValidatorTest.java | 10 +- .../ArchetypeValidatorVersionsTest.java | 4 +- .../BigArchetypeValidatorTest.java | 11 +- .../CKMArchetypeValidatorTest.java | 7 +- .../TermCodeSpecializationTest.java | 14 +- .../ExampleJsonInstanceGeneratorTest.java | 8 +- .../com/nedap/archie/diff/DiffTestUtil.java | 15 +- .../OperationalTemplateCreatorTest.java | 18 +- .../flattener/RMOverlayFlattenerTest.java | 6 +- .../flattener/SiblingOrderFlattenerTest.java | 4 +- .../FlattenerExamplesFromSpecBMMTest.java | 4 +- .../FlattenerExamplesFromSpecTest.java | 35 +-- .../com/nedap/archie/json/AOMJacksonTest.java | 10 +- .../json/flat/FlatJsonGeneratorTest.java | 37 +-- .../RmObjectValidatorTest.java | 2 +- .../TerminologyCodeConstraintsTest.java | 2 +- .../ValidateArchetypedTest.java | 2 +- .../ArchetypeSlotValidationTest.java | 4 +- .../FixableAssertionsCheckerTest.java | 2 +- .../evaluation/ParsedRulesEvaluationTest.java | 6 +- ...rchetypeSerializerParserRoundtripTest.java | 8 +- .../adl/ADLArchetypeSerializerTest.java | 2 +- .../adl/DefaultValueSerializerTest.java | 12 +- .../nedap/archie/xml/JAXBRMRoundTripTest.java | 2 +- 84 files changed, 1237 insertions(+), 410 deletions(-) create mode 100644 aom/src/main/java/com/nedap/archie/rminfo/MetaModelProvider.java create mode 100644 aom/src/main/java/com/nedap/archie/rminfo/OverridingMetaModelProvider.java create mode 100644 aom/src/main/java/com/nedap/archie/rminfo/SimpleMetaModelProvider.java create mode 100644 referencemodels/src/test/java/com/nedap/archie/rminfo/OverridingMetaModelProviderTest.java create mode 100644 referencemodels/src/test/java/com/nedap/archie/rminfo/SimpleMetaModelProviderTest.java diff --git a/README.md b/README.md index 62224fe00..4ef89bb0f 100644 --- a/README.md +++ b/README.md @@ -137,7 +137,7 @@ InMemoryFullArchetypeRepository repository = new InMemoryFullArchetypeRepository for(Archetype archetype:allArchetypes) { repository.addArchetype(archetype); } -repository.compile(BuiltinReferenceModels.getMetaModels()); +repository.compile(BuiltinReferenceModels.getMetaModelProvider()); for(ValidationResult result:repository.getAllValidationResults()) { ... your code here @@ -149,7 +149,7 @@ The validation result contains the validation result, listing any errors in the ### Reference model metadata -You may have noticed a call to ```BuiltinReferenceModels.getMetaModels()```. This retrieves the metadata for the reference models, which are needed to validate and flatten archetypes. Archie contains two types of metamodels: BMM, and reflection based metadata. +You may have noticed a call to ```BuiltinReferenceModels.getMetaModelProvider()```. This retrieves the metadata for the reference models, which are needed to validate and flatten archetypes. Archie contains two types of metamodels: BMM, and reflection based metadata. The BMM models are a file containing metadata in a form defined by the openEHR specifications. The reflection based metadata contains ModelInfoLookup classes. They are derived from an implementation of a reference model. Note that the ModelInfoLookup classes are only added if you depended on them. If you depended on archie-all, you're all set. @@ -162,7 +162,7 @@ Note that ADL 2 operational templates is fundamentally different from the ADL 1. To create an Operational Template: ```java -Flattener flattener = new Flattener(repository, BuiltinReferenceModels.getMetaModels()).createOperationalTemplate(true); +Flattener flattener = new Flattener(repository, BuiltinReferenceModels.getMetaModelProvider()).createOperationalTemplate(true); OperationalTemplate template = (OperationalTemplate) flattener.flatten(sourceArchetype); ``` @@ -221,7 +221,7 @@ The inverse operation of flattening archetypes is diffing. This is useful if you ```java Archetype flatChild, flatParent; //for how to parse and flatten, see elsewhere in the readme -Differentiator differentiator = new Differentiator(BuiltinReferenceModels.getMetaModels()); +Differentiator differentiator = new Differentiator(BuiltinReferenceModels.getMetaModelProvider()); Archetype diffed = differentiator.differentiate(flatChild, flatParent); ``` @@ -391,7 +391,7 @@ If you want to do this yourself, The RMObjectCreator creates empty reference mod Setting primitive object values works in a similar way, with ```creator.set(...)```, or by setting them explicitly on the reference model object directly. -Notice the call to ```ArchieRMInfoLookup.getInstance()```, which obtains the metadata about the reference model implementation. It can also be obtained from the result of ```BuiltinReferenceModels.getMetaModels()```, or you can define your own to make Archie work with your own reference model implementation. +Notice the call to ```ArchieRMInfoLookup.getInstance()```, which obtains the metadata about the reference model implementation. It can also be obtained from the result of ```BuiltinReferenceModels.getMetaModelProvider()```, or you can define your own to make Archie work with your own reference model implementation. ### Parsing JSON @@ -456,10 +456,10 @@ Starting from version 0.7, Archie can import ADL 1.4 files, and convert them to ```java ADL14ConversionConfiguration conversionConfiguration = new ADL14ConversionConfiguration(); -ADL14Converter converter = new ADL14Converter(BuiltinReferenceModels.getMetaModels(), conversionConfiguration); +ADL14Converter converter = new ADL14Converter(BuiltinReferenceModels.getMetaModelProvider(), conversionConfiguration); List archetypes = new ArrayList<>(); -ADL14Parser parser = new ADL14Parser(BuiltinReferenceModels.getMetaModels()); +ADL14Parser parser = new ADL14Parser(BuiltinReferenceModels.getMetaModelProvider()); for(String file:fileNames) { try(InputStream stream = new FileInputStream(file)) { diff --git a/aom/src/main/java/com/nedap/archie/adl14/ADL14DefaultMultiplicitiesSetter.java b/aom/src/main/java/com/nedap/archie/adl14/ADL14DefaultMultiplicitiesSetter.java index 80b86d0e6..095958cf7 100644 --- a/aom/src/main/java/com/nedap/archie/adl14/ADL14DefaultMultiplicitiesSetter.java +++ b/aom/src/main/java/com/nedap/archie/adl14/ADL14DefaultMultiplicitiesSetter.java @@ -4,6 +4,8 @@ import com.nedap.archie.aom.CAttribute; import com.nedap.archie.aom.CObject; import com.nedap.archie.base.MultiplicityInterval; +import com.nedap.archie.rminfo.MetaModel; +import com.nedap.archie.rminfo.MetaModelProvider; import com.nedap.archie.rminfo.MetaModels; /** @@ -17,24 +19,32 @@ */ public class ADL14DefaultMultiplicitiesSetter { - private final MetaModels metaModels; + private final MetaModelProvider metaModelProvider; + /** + * @deprecated Use {@link #ADL14DefaultMultiplicitiesSetter(MetaModelProvider)} instead. + */ + @Deprecated public ADL14DefaultMultiplicitiesSetter(MetaModels metaModels) { - this.metaModels = metaModels; + this((MetaModelProvider) metaModels); + } + + public ADL14DefaultMultiplicitiesSetter(MetaModelProvider metaModelProvider) { + this.metaModelProvider = metaModelProvider; } public void setDefaults(Archetype archetype) { - metaModels.selectModel(archetype); - correctItemsMultiplicities(archetype.getDefinition()); + MetaModel metaModel = metaModelProvider.selectAndGetMetaModel(archetype); + correctItemsMultiplicities(metaModel, archetype.getDefinition()); } - private void correctItemsMultiplicities(CObject cObject) { + private void correctItemsMultiplicities(MetaModel metaModel, CObject cObject) { for (CAttribute attribute : cObject.getAttributes()) { for (CObject child : attribute.getChildren()) { - if (child.getOccurrences() == null && metaModels.isMultiple(cObject.getRmTypeName(), attribute.getRmAttributeName())) { + if (child.getOccurrences() == null && metaModel.isMultiple(cObject.getRmTypeName(), attribute.getRmAttributeName())) { child.setOccurrences(new MultiplicityInterval(1, 1)); } - correctItemsMultiplicities(child); + correctItemsMultiplicities(metaModel, child); } } diff --git a/aom/src/main/java/com/nedap/archie/adl14/ADL14NodeIDConverter.java b/aom/src/main/java/com/nedap/archie/adl14/ADL14NodeIDConverter.java index 48ad8663d..aa06afe1a 100644 --- a/aom/src/main/java/com/nedap/archie/adl14/ADL14NodeIDConverter.java +++ b/aom/src/main/java/com/nedap/archie/adl14/ADL14NodeIDConverter.java @@ -13,6 +13,8 @@ import com.nedap.archie.base.Cardinality; import com.nedap.archie.paths.PathSegment; import com.nedap.archie.query.APathQuery; +import com.nedap.archie.rminfo.MetaModel; +import com.nedap.archie.rminfo.MetaModelProvider; import com.nedap.archie.rminfo.MetaModels; import com.nedap.archie.rules.*; @@ -33,7 +35,8 @@ public class ADL14NodeIDConverter { private final ADL14TermConstraintConverter termConstraintConverter; private final PreviousConversionApplier previousConversionApplier; private final ADL2ConversionResult conversionResult; - private final MetaModels metaModels; + private final MetaModelProvider metaModelProvider; + private final MetaModel metaModel; private IdCodeGenerator idCodeGenerator; @@ -45,8 +48,17 @@ public class ADL14NodeIDConverter { private final Map createdValueSets = new LinkedHashMap<>(); private final Map newCodeToOldCodeMap = new LinkedHashMap<>(); + /** + * @deprecated Use {@link #ADL14NodeIDConverter(MetaModelProvider, Archetype, Archetype, ADL14ConversionConfiguration, ADL2ConversionLog, ADL2ConversionResult)} instead. + */ + @Deprecated public ADL14NodeIDConverter(MetaModels metaModels, Archetype archetype, Archetype flatParentArchetype, ADL14ConversionConfiguration configuration, ADL2ConversionLog oldLog, ADL2ConversionResult conversionResult) { - this.metaModels = metaModels; + this((MetaModelProvider) metaModels, archetype, flatParentArchetype, configuration, oldLog, conversionResult); + } + + public ADL14NodeIDConverter(MetaModelProvider metaModelProvider, Archetype archetype, Archetype flatParentArchetype, ADL14ConversionConfiguration configuration, ADL2ConversionLog oldLog, ADL2ConversionResult conversionResult) { + this.metaModelProvider = metaModelProvider; + this.metaModel = metaModelProvider.getMetaModel(archetype); this.conversionConfiguration = configuration; this.archetype = archetype; this.flatParentArchetype = flatParentArchetype; @@ -61,7 +73,7 @@ public ADL14ConversionConfiguration getConversionConfiguration() { } public ADL2ConversionLog convert() { - metaModels.selectModel(archetype); + metaModelProvider.selectAndGetMetaModel(archetype); // For backwards compatibility correctItemsCardinality(archetype.getDefinition()); List unnecessaryCodes = findUnnecessaryCodes(archetype.getDefinition(), @@ -123,7 +135,7 @@ private List findUnnecessaryCodes(CObject cObject, Map seenMetaDataIdentifiers = new HashSet<>(); private Archetype archetype; - private CComplexObjectParser cComplexObjectParser; private TerminologyParser terminologyParser; - private MetaModels metaModels; + private final MetaModelProvider metaModelProvider; + /** + * @deprecated Use {@link #ADLListener(ANTLRParserErrors, MetaModelProvider)} instead. + */ + @Deprecated public ADLListener(ANTLRParserErrors errors, MetaModels metaModels) { + this(errors, (MetaModelProvider) metaModels); + } + + public ADLListener(ANTLRParserErrors errors, MetaModelProvider metaModelProvider) { this.errors = errors; - cComplexObjectParser = new CComplexObjectParser(errors, metaModels); terminologyParser = new TerminologyParser(errors); - this.metaModels = metaModels; + this.metaModelProvider = metaModelProvider; } /** top-level constructs */ @@ -110,8 +118,8 @@ private void parseArchetypeHRID(TerminalNode hrId) { if(hrId != null) { ArchetypeHRID archetypeID = new ArchetypeHRID(hrId.getText()); archetype.setArchetypeId(archetypeID); - if(metaModels != null) { - metaModels.selectModel(archetype); + if(metaModelProvider != null) { + metaModelProvider.selectAndGetMetaModel(archetype); // For backwards compatibility } } } @@ -195,6 +203,8 @@ public void enterMetaDataItem(AdlParser.MetaDataItemContext ctx) { */ @Override public void enterDefinitionSection(DefinitionSectionContext ctx) { + MetaModel metaModel = metaModelProvider == null ? null : metaModelProvider.getMetaModel(archetype); + CComplexObjectParser cComplexObjectParser = new CComplexObjectParser(errors, metaModel); CComplexObject definition = cComplexObjectParser.parseComplexObject(ctx.c_complex_object()); archetype.setDefinition(definition); } @@ -223,6 +233,8 @@ public void enterSpecializationSection(SpecializationSectionContext ctx) { @Override public void enterRulesSection(RulesSectionContext ctx) { + MetaModel metaModel = metaModelProvider == null ? null : metaModelProvider.getMetaModel(archetype); + CComplexObjectParser cComplexObjectParser = new CComplexObjectParser(errors, metaModel); archetype.setRules(cComplexObjectParser.parseRules(ctx)); } diff --git a/aom/src/main/java/com/nedap/archie/adlparser/treewalkers/CComplexObjectParser.java b/aom/src/main/java/com/nedap/archie/adlparser/treewalkers/CComplexObjectParser.java index 43bf2fbf3..1ac3c17b6 100644 --- a/aom/src/main/java/com/nedap/archie/adlparser/treewalkers/CComplexObjectParser.java +++ b/aom/src/main/java/com/nedap/archie/adlparser/treewalkers/CComplexObjectParser.java @@ -7,6 +7,7 @@ import com.nedap.archie.base.Cardinality; import com.nedap.archie.base.MultiplicityInterval; import com.nedap.archie.base.OpenEHRBase; +import com.nedap.archie.rminfo.MetaModel; import com.nedap.archie.rminfo.MetaModels; import com.nedap.archie.rules.Assertion; import com.nedap.archie.serializer.odin.AdlOdinToJsonConverter; @@ -24,12 +25,26 @@ public class CComplexObjectParser extends BaseTreeWalker { private final PrimitivesConstraintParser primitivesConstraintParser; + @Deprecated private final MetaModels metaModels; + private final MetaModel metaModel; + /** + * @deprecated Use {@link #CComplexObjectParser(ANTLRParserErrors, MetaModel)} instead. + */ + @Deprecated public CComplexObjectParser(ANTLRParserErrors errors, MetaModels metaModels) { super(errors); primitivesConstraintParser = new PrimitivesConstraintParser(errors); this.metaModels = metaModels; + this.metaModel = null; + } + + public CComplexObjectParser(ANTLRParserErrors errors, MetaModel metaModel) { + super(errors); + primitivesConstraintParser = new PrimitivesConstraintParser(errors); + this.metaModels = null; + this.metaModel = metaModel; } public RulesSection parseRules(RulesSectionContext context) { @@ -158,6 +173,10 @@ private void parseOdinDefaultValue(CComplexObject parent, Default_valueContext d } private ObjectMapper getDefaultValueJsonObjectMapper() { + if(metaModel != null) { + return metaModel.getJsonObjectMapper(); + } + // For backwards compatiblity if(metaModels == null) { return null; } @@ -168,6 +187,10 @@ private ObjectMapper getDefaultValueJsonObjectMapper() { } private ObjectMapper getDefaultValueOdinObjectMapper() { + if(metaModel != null) { + return metaModel.getOdinInputObjectMapper(); + } + // For backwards compatiblity if(metaModels == null) { return null; } diff --git a/aom/src/main/java/com/nedap/archie/aom/utils/AOMUtils.java b/aom/src/main/java/com/nedap/archie/aom/utils/AOMUtils.java index d328799dc..a1efef59e 100644 --- a/aom/src/main/java/com/nedap/archie/aom/utils/AOMUtils.java +++ b/aom/src/main/java/com/nedap/archie/aom/utils/AOMUtils.java @@ -445,7 +445,9 @@ public static boolean valueSetContainsCodeOrParent(Collection valueSetMe * Check if the parent attribute of the given CObject is a container attribute. * * @see MetaModelInterface#isMultiple(String, String) + * @deprecated Use {@link #parentIsMultiple(CObject, Archetype, MetaModel)} instead. */ + @Deprecated public static boolean parentIsMultiple(CObject cObject, Archetype flatParentArchetype, MetaModels metaModels) { if(cObject.getParent() != null) { @@ -464,4 +466,28 @@ public static boolean parentIsMultiple(CObject cObject, Archetype flatParentArch } return false; } + + /** + * Check if the parent attribute of the given CObject is a container attribute. + * + * @see MetaModel#isMultiple(String, String) + */ + public static boolean parentIsMultiple(CObject cObject, Archetype flatParentArchetype, MetaModel metaModel) { + if(cObject.getParent() != null) { + + CAttribute parent = cObject.getParent(); + CObject owningObject = parent.getParent(); + if (parent.getDifferentialPath() != null && flatParentArchetype != null) { + CAttribute attributeFromParent = (CAttribute) AOMUtils.getDifferentialPathFromParent(flatParentArchetype, parent); + if(attributeFromParent != null) { + owningObject = attributeFromParent.getParent(); + } + + } + if(owningObject != null) { + return metaModel.isMultiple(owningObject.getRmTypeName(), parent.getRmAttributeName()); + } + } + return false; + } } diff --git a/aom/src/main/java/com/nedap/archie/rminfo/MetaModel.java b/aom/src/main/java/com/nedap/archie/rminfo/MetaModel.java index 2a8bae9d4..d8277f198 100644 --- a/aom/src/main/java/com/nedap/archie/rminfo/MetaModel.java +++ b/aom/src/main/java/com/nedap/archie/rminfo/MetaModel.java @@ -111,6 +111,10 @@ public ObjectMapper getJsonObjectMapper() { return jsonObjectMapper; } + /** + * determine if a property on a type is multiple or not. If the property cannot be found, returns false. + * Works both on properties on a type, or on path based lookup. + */ @Override public boolean isMultiple(String typeName, String attributeNameOrPath) { MultiplicityInterval multiplicityInterval = referenceModelPropMultiplicity(typeName, attributeNameOrPath); diff --git a/aom/src/main/java/com/nedap/archie/rminfo/MetaModelInterface.java b/aom/src/main/java/com/nedap/archie/rminfo/MetaModelInterface.java index 1dbda1879..ac4dccb2f 100644 --- a/aom/src/main/java/com/nedap/archie/rminfo/MetaModelInterface.java +++ b/aom/src/main/java/com/nedap/archie/rminfo/MetaModelInterface.java @@ -3,6 +3,10 @@ import com.nedap.archie.aom.CPrimitiveObject; import com.nedap.archie.base.MultiplicityInterval; +/** + * @deprecated Use {@link MetaModel} instead. + */ +@Deprecated public interface MetaModelInterface { /** * determine if a property on a type is multiple or not. If the property cannot be found, returns false. diff --git a/aom/src/main/java/com/nedap/archie/rminfo/MetaModelProvider.java b/aom/src/main/java/com/nedap/archie/rminfo/MetaModelProvider.java new file mode 100644 index 000000000..a34584847 --- /dev/null +++ b/aom/src/main/java/com/nedap/archie/rminfo/MetaModelProvider.java @@ -0,0 +1,75 @@ +package com.nedap.archie.rminfo; + +import com.nedap.archie.aom.Archetype; + +/** + * A provider for meta models, which can be used to retrieve the meta model for a specific reference model based on an + * archetype or reference model publisher, package and release version. + */ +public interface MetaModelProvider { + /** + * Get a meta model based on an archetype. + * + * @param archetype the archetype to find the meta model for + * @return the meta model for the reference model that the archetype is based on + * @throws ModelNotFoundException when no BMM and no ModelInfoLookup model has been found matching the archetype + */ + public default MetaModel getMetaModel(Archetype archetype) throws ModelNotFoundException { + return getMetaModel(archetype, archetype.getRmRelease()); + } + + /** + * Get a meta model based on an archetype, but override the RM release version from the archetype with the given RM + * release version. + * + * @param archetype the archetype to find the meta model for + * @param rmRelease the release version of the reference model. This will override the RM release version in the + * archetype. + * @return the meta model for the reference model that the archetype is based on + * @throws ModelNotFoundException when no BMM and no ModelInfoLookup model has been found matching the archetype and + * RM version + */ + public default MetaModel getMetaModel(Archetype archetype, String rmRelease) throws ModelNotFoundException { + return getMetaModel( + archetype.getArchetypeId().getRmPublisher(), + archetype.getArchetypeId().getRmPackage(), + rmRelease + ); + } + + /** + * Get a model based on a reference model publisher, package and release version. + * + * @param rmPublisher the publisher of the reference model + * @param rmPackage the package of the reference model + * @param rmRelease the release version of the reference model + * @return the meta model + * @throws ModelNotFoundException when no BMM and no ModelInfoLookup model has been found matching the publisher, + * package and release version + */ + public abstract MetaModel getMetaModel(String rmPublisher, String rmPackage, String rmRelease) throws ModelNotFoundException; + + /** + * @deprecated For backwards compatibility only. Use {@link #getMetaModel(Archetype)} instead. + */ + @Deprecated + public default MetaModel selectAndGetMetaModel(Archetype archetype) throws ModelNotFoundException { + return getMetaModel(archetype); + } + + /** + * @deprecated For backwards compatibility only. Use {@link #getMetaModel(Archetype, String)} instead. + */ + @Deprecated + public default MetaModel selectAndGetMetaModel(Archetype archetype, String rmVersion) throws ModelNotFoundException { + return getMetaModel(archetype, rmVersion); + } + + /** + * @deprecated For backwards compatibility only. Use {@link #getMetaModel(String, String, String)} instead. + */ + @Deprecated + public default MetaModel selectAndGetMetaModel(String rmPublisher, String rmPackage, String rmRelease) throws ModelNotFoundException { + return getMetaModel(rmPublisher, rmPackage, rmRelease); + } +} diff --git a/aom/src/main/java/com/nedap/archie/rminfo/MetaModels.java b/aom/src/main/java/com/nedap/archie/rminfo/MetaModels.java index 56d80e63d..eb491715e 100644 --- a/aom/src/main/java/com/nedap/archie/rminfo/MetaModels.java +++ b/aom/src/main/java/com/nedap/archie/rminfo/MetaModels.java @@ -6,12 +6,7 @@ import com.nedap.archie.aom.profile.AomProfiles; import com.nedap.archie.base.MultiplicityInterval; import org.openehr.bmm.core.BmmModel; -import org.openehr.bmm.persistence.validation.BmmDefinitions; import org.openehr.bmm.v2.validation.BmmRepository; -import org.openehr.bmm.v2.validation.BmmValidationResult; - -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; /** * MetaModel class that provides some opertaions for archetype validation and flattener that is either based on @@ -27,32 +22,28 @@ * * Note that this class is NOT thread-safe and is to be used by a single thread only. * + * @deprecated Use {@link SimpleMetaModelProvider}, {@link OverridingMetaModelProvider} or {@link MetaModel} instead. */ -public class MetaModels implements MetaModelInterface { - +@Deprecated +public class MetaModels implements MetaModelInterface, MetaModelProvider { private final ReferenceModels models; private final BmmRepository bmmRepository; - private AomProfiles aomProfiles; + private final AomProfiles aomProfiles; + private final OverridingMetaModelProvider overridingMetaModelProvider; private MetaModel selectedModel; - private AomProfile selectedAomProfile; - - /** - * Allows to set a specific RM version for a specific RM model, so that one is used instead of the one in the archetype - */ - private Map overriddenMetaModelVersions = new ConcurrentHashMap<>(); - public MetaModels(ReferenceModels models, BmmRepository repository) { - this.models = models; - this.bmmRepository = repository; - aomProfiles = new AomProfiles(); + this(models, repository, new AomProfiles()); } public MetaModels(ReferenceModels models, BmmRepository repository, AomProfiles profiles) { this.models = models; this.bmmRepository = repository; aomProfiles = profiles; + this.overridingMetaModelProvider = new OverridingMetaModelProvider( + new SimpleMetaModelProvider(models, repository, profiles) + ); } /** @@ -64,10 +55,7 @@ public MetaModels(ReferenceModels models, BmmRepository repository, AomProfiles * @param version the version that should be chosen */ public void overrideModelVersion(String rmPublisher, String rmPackage, String version) { - this.overriddenMetaModelVersions.put( - BmmDefinitions.publisherQualifiedRmClosureName(rmPublisher, rmPackage), - version - ); + overridingMetaModelProvider.overrideModelVersion(rmPublisher, rmPackage, version); } /** @@ -76,12 +64,47 @@ public void overrideModelVersion(String rmPublisher, String rmPackage, String ve * @param rmPackage the RM Package to remove the model version for */ public void removeOverridenModelVersion(String rmPublisher, String rmPackage) { - this.overriddenMetaModelVersions.remove(BmmDefinitions.publisherQualifiedRmClosureName(rmPublisher, rmPackage)); + overridingMetaModelProvider.removeOverridenModelVersion(rmPublisher, rmPackage); } - public String getOverriddenModelVersion(String rmPublisher, String rmPackage) { - return this.overriddenMetaModelVersions.get(BmmDefinitions.publisherQualifiedRmClosureName(rmPublisher, rmPackage)); + return overridingMetaModelProvider.getOverriddenModelVersion(rmPublisher, rmPackage); + } + + @Override + public MetaModel getMetaModel(Archetype archetype) throws ModelNotFoundException { + return overridingMetaModelProvider.getMetaModel(archetype); + } + + @Override + public MetaModel getMetaModel(Archetype archetype, String rmVersion) throws ModelNotFoundException { + return overridingMetaModelProvider.getMetaModel(archetype, rmVersion); + } + + @Override + public MetaModel getMetaModel(String rmPublisher, String rmPackage, String rmRelease) throws ModelNotFoundException { + return overridingMetaModelProvider.getMetaModel(rmPublisher, rmPackage, rmRelease); + } + + @Override + public MetaModel selectAndGetMetaModel(Archetype archetype) throws ModelNotFoundException { + MetaModel result = getMetaModel(archetype); + this.selectedModel = result; + return result; + } + + @Override + public MetaModel selectAndGetMetaModel(Archetype archetype, String rmVersion) throws ModelNotFoundException { + MetaModel result = getMetaModel(archetype, rmVersion); + this.selectedModel = result; + return result; + } + + @Override + public MetaModel selectAndGetMetaModel(String rmPublisher, String rmPackage, String rmRelease) throws ModelNotFoundException { + MetaModel result = getMetaModel(rmPublisher, rmPackage, rmRelease); + this.selectedModel = result; + return result; } /** @@ -90,8 +113,7 @@ public String getOverriddenModelVersion(String rmPublisher, String rmPackage) { * @throws ModelNotFoundException when no BMM and no ModelInfoLookup model has been found matching the archetype */ public void selectModel(Archetype archetype) throws ModelNotFoundException { ; - String overriddenVersion = getOverriddenModelVersion(archetype.getArchetypeId().getRmPublisher(), archetype.getArchetypeId().getRmPackage()); - selectModel(archetype, overriddenVersion == null ? archetype.getRmRelease(): overriddenVersion); + selectAndGetMetaModel(archetype); } /** @@ -101,7 +123,7 @@ public String getOverriddenModelVersion(String rmPublisher, String rmPackage) { * @throws ModelNotFoundException */ public void selectModel(Archetype archetype, String rmVersion) throws ModelNotFoundException { ; - selectModel(archetype.getArchetypeId().getRmPublisher(), archetype.getArchetypeId().getRmPackage(), rmVersion); + selectAndGetMetaModel(archetype, rmVersion); } /** @@ -113,48 +135,7 @@ public String getOverriddenModelVersion(String rmPublisher, String rmPackage) { * @throws ModelNotFoundException */ public void selectModel(String rmPublisher, String rmPackage, String rmRelease) throws ModelNotFoundException { - ModelInfoLookup selectedModel = null; - BmmModel selectedBmmModel = null; - RMObjectMapperProvider objectMapperProvider = null; - if(models != null) { - selectedModel = models.getModel(rmPublisher, rmPackage); - objectMapperProvider = models.getRmObjectMapperProvider(rmPublisher, rmPackage); - } - if(bmmRepository != null) { - BmmValidationResult validationResult = bmmRepository.getModelByClosure(BmmDefinitions.publisherQualifiedRmClosureName(rmPublisher, rmPackage) + "_" + rmRelease); - selectedBmmModel = validationResult == null ? null : validationResult.getModel(); - } - - this.selectedAomProfile = getAomProfileWithSchemaId(selectedBmmModel); - if(this.selectedAomProfile == null) { - this.selectedAomProfile = getAomProfileOnPublisher(rmPublisher); - } - - if(selectedModel == null && selectedBmmModel == null) { - throw new ModelNotFoundException(String.format("model for %s.%s version %s not found", rmPublisher, rmPackage, rmRelease)); - } - this.selectedModel = new MetaModel(selectedModel, selectedBmmModel, selectedAomProfile, objectMapperProvider); - - } - - private AomProfile getAomProfileWithSchemaId(BmmModel selectedBmmModel) { - if(selectedBmmModel != null) { - for (AomProfile profile : aomProfiles.getProfiles()) { - if (profile.getRmSchemaPattern().stream().anyMatch(pat -> selectedBmmModel.getSchemaId().matches(pat))) { - return profile; - } - } - } - return null; - } - - private AomProfile getAomProfileOnPublisher(String rmPublisher) { - for(AomProfile profile:aomProfiles.getProfiles()) { - if(profile.getProfileName().equalsIgnoreCase(rmPublisher)) { - return profile; - } - } - return null; + selectAndGetMetaModel(rmPublisher, rmPackage, rmRelease); } public ModelInfoLookup getSelectedModelInfoLookup() { @@ -242,7 +223,7 @@ public AomProfiles getAomProfiles() { } public AomProfile getSelectedAomProfile() { - return selectedAomProfile; + return selectedModel == null ? null : selectedModel.getAomProfile(); } diff --git a/aom/src/main/java/com/nedap/archie/rminfo/NoModelSelectedException.java b/aom/src/main/java/com/nedap/archie/rminfo/NoModelSelectedException.java index 2d09f3a64..2b85122e1 100644 --- a/aom/src/main/java/com/nedap/archie/rminfo/NoModelSelectedException.java +++ b/aom/src/main/java/com/nedap/archie/rminfo/NoModelSelectedException.java @@ -1,5 +1,9 @@ package com.nedap.archie.rminfo; +/** + * @deprecated This class will be removed. + */ +@Deprecated public class NoModelSelectedException extends RuntimeException { public NoModelSelectedException(String message) { diff --git a/aom/src/main/java/com/nedap/archie/rminfo/OverridingMetaModelProvider.java b/aom/src/main/java/com/nedap/archie/rminfo/OverridingMetaModelProvider.java new file mode 100644 index 000000000..e86ac527c --- /dev/null +++ b/aom/src/main/java/com/nedap/archie/rminfo/OverridingMetaModelProvider.java @@ -0,0 +1,84 @@ +package com.nedap.archie.rminfo; + +import com.nedap.archie.aom.Archetype; +import org.openehr.bmm.persistence.validation.BmmDefinitions; + +import java.util.Map; +import java.util.Objects; +import java.util.concurrent.ConcurrentHashMap; + +/** + * A MetaModelProvider that allows to override the RM release version for a specific RM publisher and package. + *

+ * When the RM release version is overridden for a specific RM publisher and package, the overridden version will be + * used by the {@link #getMetaModel(Archetype)} method to retrieve the meta model. + */ +public class OverridingMetaModelProvider implements MetaModelProvider { + private final MetaModelProvider delegate; + + /** + * Allows to set a specific RM release version for a specific RM model, so that one is used instead of the one in + * the archetype. + */ + private final Map overriddenMetaModelVersions = new ConcurrentHashMap<>(); + + /** + * Create an OverridingMetaModelProvider that delegates to the given MetaModelProvider. + * + * @param delegate the MetaModelProvider to delegate to + */ + public OverridingMetaModelProvider(MetaModelProvider delegate) { + this.delegate = Objects.requireNonNull(delegate, "delegate must not be null"); + } + + /** + * Indicate that the model version for the given package by the given publisher should be fixed + * to a specific version. Useful for validating archetypes against new RM versions, for example OpenEHR + * RM 1.0.2 archetypes against 1.0.4. + * + * @param rmPublisher the publisher of the RM + * @param rmPackage the package of the RM to override the version for + * @param overridingRmRelease the version that should be chosen + */ + public void overrideModelVersion(String rmPublisher, String rmPackage, String overridingRmRelease) { + overriddenMetaModelVersions.put( + BmmDefinitions.publisherQualifiedRmClosureName(rmPublisher, rmPackage), + overridingRmRelease + ); + } + + /** + * Remove the overriden model version for the given publisher and package. + * + * @param rmPublisher the publisher of the package + * @param rmPackage the RM Package to remove the model version for + */ + public void removeOverridenModelVersion(String rmPublisher, String rmPackage) { + overriddenMetaModelVersions.remove(BmmDefinitions.publisherQualifiedRmClosureName(rmPublisher, rmPackage)); + } + + /** + * Get the overriden model version for the given package, if any. + * + * @param rmPublisher the publisher of the package + * @param rmPackage the RM Package to remove the model version for + * @return the overridden model version, or null if no override has been set + */ + public String getOverriddenModelVersion(String rmPublisher, String rmPackage) { + return overriddenMetaModelVersions.get(BmmDefinitions.publisherQualifiedRmClosureName(rmPublisher, rmPackage)); + } + + @Override + public MetaModel getMetaModel(Archetype archetype) throws ModelNotFoundException { + String overriddenVersion = getOverriddenModelVersion( + archetype.getArchetypeId().getRmPublisher(), + archetype.getArchetypeId().getRmPackage() + ); + return getMetaModel(archetype, overriddenVersion == null ? archetype.getRmRelease() : overriddenVersion); + } + + @Override + public MetaModel getMetaModel(String rmPublisher, String rmPackage, String rmRelease) throws ModelNotFoundException { + return delegate.getMetaModel(rmPublisher, rmPackage, rmRelease); + } +} diff --git a/aom/src/main/java/com/nedap/archie/rminfo/SimpleMetaModelProvider.java b/aom/src/main/java/com/nedap/archie/rminfo/SimpleMetaModelProvider.java new file mode 100644 index 000000000..442803619 --- /dev/null +++ b/aom/src/main/java/com/nedap/archie/rminfo/SimpleMetaModelProvider.java @@ -0,0 +1,98 @@ +package com.nedap.archie.rminfo; + +import com.nedap.archie.aom.profile.AomProfile; +import com.nedap.archie.aom.profile.AomProfiles; +import org.openehr.bmm.core.BmmModel; +import org.openehr.bmm.persistence.validation.BmmDefinitions; +import org.openehr.bmm.v2.validation.BmmRepository; +import org.openehr.bmm.v2.validation.BmmValidationResult; + +import java.util.Objects; + +/** + * A simple implementation of the MetaModelProvider interface that retrieves meta models from either a ReferenceModels + * instance or a BmmRepository. It also supports AOM profiles. + */ +public class SimpleMetaModelProvider implements MetaModelProvider { + private final ReferenceModels referenceModels; + private final BmmRepository bmmRepository; + private final AomProfiles aomProfiles; + + /** + * Create a SimpleMetaModelProvider that retrieves meta models from the given ReferenceModels and BmmRepository. + * + * @param referenceModels the ReferenceModels to use for retrieving meta models or null + * @param bmmRepository the BmmRepository to use for retrieving BMM models or null + * @throws IllegalArgumentException if both referenceModels and bmmRepository are null + */ + public SimpleMetaModelProvider(ReferenceModels referenceModels, BmmRepository bmmRepository) { + this(referenceModels, bmmRepository, new AomProfiles()); + } + + /** + * Create a SimpleMetaModelProvider that retrieves meta models from the given ReferenceModels, BmmRepository, and + * AomProfiles. + * + * @param referenceModels the ReferenceModels to use for retrieving meta models or null + * @param bmmRepository the BmmRepository to use for retrieving BMM models or null + * @param aomProfiles the AomProfiles to use for retrieving AOM profiles + * @throws IllegalArgumentException if both referenceModels and bmmRepository are null + */ + public SimpleMetaModelProvider(ReferenceModels referenceModels, BmmRepository bmmRepository, AomProfiles aomProfiles) { + if (referenceModels == null && bmmRepository == null) { + throw new IllegalArgumentException("Either referenceModels or bmmRepository must be provided"); + } + this.referenceModels = referenceModels; + this.bmmRepository = bmmRepository; + this.aomProfiles = Objects.requireNonNull(aomProfiles, "aomProfiles must not be null"); + } + + @Override + public MetaModel getMetaModel(String rmPublisher, String rmPackage, String rmRelease) throws ModelNotFoundException { + ModelInfoLookup modelInfoLookup = null; + BmmModel bmmModel = null; + RMObjectMapperProvider objectMapperProvider = null; + if (referenceModels != null) { + modelInfoLookup = referenceModels.getModel(rmPublisher, rmPackage); + objectMapperProvider = referenceModels.getRmObjectMapperProvider(rmPublisher, rmPackage); + } + if (bmmRepository != null) { + BmmValidationResult validationResult = bmmRepository.getModelByClosure( + BmmDefinitions.publisherQualifiedRmClosureName(rmPublisher, rmPackage) + "_" + rmRelease + ); + bmmModel = validationResult == null ? null : validationResult.getModel(); + } + + AomProfile aomProfile = getAomProfileWithSchemaId(bmmModel); + if (aomProfile == null) { + aomProfile = getAomProfileOnPublisher(rmPublisher); + } + + if (modelInfoLookup == null && bmmModel == null) { + throw new ModelNotFoundException( + String.format("model for %s.%s version %s not found", rmPublisher, rmPackage, rmRelease) + ); + } + return new MetaModel(modelInfoLookup, bmmModel, aomProfile, objectMapperProvider); + } + + private AomProfile getAomProfileWithSchemaId(BmmModel bmmModel) { + if (bmmModel != null) { + for (AomProfile profile : aomProfiles.getProfiles()) { + if (profile.getRmSchemaPattern().stream().anyMatch(pat -> bmmModel.getSchemaId().matches(pat))) { + return profile; + } + } + } + return null; + } + + private AomProfile getAomProfileOnPublisher(String rmPublisher) { + for (AomProfile profile : aomProfiles.getProfiles()) { + if (profile.getProfileName().equalsIgnoreCase(rmPublisher)) { + return profile; + } + } + return null; + } +} diff --git a/referencemodels/build.gradle b/referencemodels/build.gradle index b947bb68b..9fb6868ef 100644 --- a/referencemodels/build.gradle +++ b/referencemodels/build.gradle @@ -5,5 +5,6 @@ dependencies { api project(':odin') api project(':aom') testImplementation project(':openehr-rm') + testImplementation project(':test-rm') testImplementation project(':archie-utils') } \ No newline at end of file diff --git a/referencemodels/src/main/java/org/openehr/referencemodels/BuiltinReferenceModels.java b/referencemodels/src/main/java/org/openehr/referencemodels/BuiltinReferenceModels.java index 2c89cabf6..8f2e4156b 100644 --- a/referencemodels/src/main/java/org/openehr/referencemodels/BuiltinReferenceModels.java +++ b/referencemodels/src/main/java/org/openehr/referencemodels/BuiltinReferenceModels.java @@ -2,10 +2,7 @@ import com.nedap.archie.aom.profile.AomProfile; import com.nedap.archie.aom.profile.AomProfiles; -import com.nedap.archie.rminfo.MetaModels; -import com.nedap.archie.rminfo.ModelInfoLookup; -import com.nedap.archie.rminfo.RMObjectMapperProvider; -import com.nedap.archie.rminfo.ReferenceModels; +import com.nedap.archie.rminfo.*; import org.openehr.bmm.v2.persistence.odin.BmmOdinParser; import org.openehr.bmm.v2.validation.BmmRepository; import org.openehr.bmm.v2.validation.BmmSchemaConverter; @@ -34,6 +31,8 @@ public class BuiltinReferenceModels { private static BmmRepository bmmRepository; + private static MetaModelProvider metaModelProvider; + public static BmmRepository getBmmRepository() { if(bmmRepository != null) { return bmmRepository; @@ -160,11 +159,24 @@ private static void addModelInfoLookupIfExists(ReferenceModels result, String cl } } + /** + * Returns a MetaModelProvider loaded with all BMM models, ModelInfoLookups and AOM profiles that are available. + */ + public static MetaModelProvider getMetaModelProvider() { + if (metaModelProvider != null) { + return metaModelProvider; + } + metaModelProvider = new SimpleMetaModelProvider(getAvailableModelInfoLookups(), getBmmRepository(), getAomProfiles()); + return metaModelProvider; + } + /** * Returns the MetaModels loaded with all BMM, ModelInfoLookup and AOM profiles that are available. * Returns a new MetaModels instance every call! * @return + * @deprecated Use {@link #getMetaModelProvider()} instead. */ + @Deprecated public static MetaModels getMetaModels() { MetaModels metaModels = new MetaModels(getAvailableModelInfoLookups(), getBmmRepository()); for(AomProfile profile:getAomProfiles().getProfiles()) { diff --git a/referencemodels/src/test/java/com/nedap/archie/rminfo/OverridingMetaModelProviderTest.java b/referencemodels/src/test/java/com/nedap/archie/rminfo/OverridingMetaModelProviderTest.java new file mode 100644 index 000000000..0986eddc3 --- /dev/null +++ b/referencemodels/src/test/java/com/nedap/archie/rminfo/OverridingMetaModelProviderTest.java @@ -0,0 +1,47 @@ +package com.nedap.archie.rminfo; + +import com.nedap.archie.aom.Archetype; +import com.nedap.archie.aom.ArchetypeHRID; +import org.junit.Test; +import org.openehr.referencemodels.BuiltinReferenceModels; + +import static org.junit.Assert.assertEquals; + +public class OverridingMetaModelProviderTest { + @Test + public void overrideModelVersion() { + MetaModelProvider metaModelProvider = BuiltinReferenceModels.getMetaModelProvider(); + OverridingMetaModelProvider overridingMetaModelProvider = new OverridingMetaModelProvider(metaModelProvider); + + Archetype archetype = new Archetype(); + archetype.setArchetypeId(new ArchetypeHRID("openEHR-EHR-CLUSTER.test.v1.0.0")); + archetype.setRmRelease("1.0.3"); + MetaModel metaModel = overridingMetaModelProvider.getMetaModel(archetype); + assertEquals("openehr", metaModel.getBmmModel().getRmPublisher()); + assertEquals("EHR", metaModel.getBmmModel().getModelName()); + assertEquals("1.0.3", metaModel.getBmmModel().getRmRelease()); + + + //now overide the version to 1.0.4, and assert + overridingMetaModelProvider.overrideModelVersion("openEHR", "EHR", "1.0.4"); + + metaModel = overridingMetaModelProvider.getMetaModel(archetype); + assertEquals("openehr", metaModel.getBmmModel().getRmPublisher()); + assertEquals("EHR", metaModel.getBmmModel().getModelName()); + assertEquals("1.0.4", metaModel.getBmmModel().getRmRelease()); + + //select a specific RM + metaModel = overridingMetaModelProvider.getMetaModel(archetype, "1.0.2"); + + assertEquals("openehr", metaModel.getBmmModel().getRmPublisher()); + assertEquals("EHR", metaModel.getBmmModel().getModelName()); + assertEquals("1.0.2", metaModel.getBmmModel().getRmRelease()); + + //remove Override + overridingMetaModelProvider.removeOverridenModelVersion("openEHR", "EHR"); + metaModel = overridingMetaModelProvider.getMetaModel(archetype); + assertEquals("openehr", metaModel.getBmmModel().getRmPublisher()); + assertEquals("EHR", metaModel.getBmmModel().getModelName()); + assertEquals("1.0.3", metaModel.getBmmModel().getRmRelease()); + } +} diff --git a/referencemodels/src/test/java/com/nedap/archie/rminfo/SimpleMetaModelProviderTest.java b/referencemodels/src/test/java/com/nedap/archie/rminfo/SimpleMetaModelProviderTest.java new file mode 100644 index 000000000..6816778ee --- /dev/null +++ b/referencemodels/src/test/java/com/nedap/archie/rminfo/SimpleMetaModelProviderTest.java @@ -0,0 +1,267 @@ +package com.nedap.archie.rminfo; + +import com.nedap.archie.aom.Archetype; +import com.nedap.archie.aom.ArchetypeHRID; +import com.nedap.archie.aom.profile.AomProfiles; +import com.nedap.archie.openehrtestrm.TestRMInfoLookup; +import org.junit.Test; +import org.openehr.referencemodels.BuiltinReferenceModels; + +import static org.junit.Assert.*; + +public class SimpleMetaModelProviderTest { + + @Test + public void testConstructors() { + IllegalArgumentException ex = assertThrows(IllegalArgumentException.class, () -> new SimpleMetaModelProvider(null, null)); + assertEquals("Either referenceModels or bmmRepository must be provided", ex.getMessage()); + + ex = assertThrows(IllegalArgumentException.class, () -> new SimpleMetaModelProvider(null, null, new AomProfiles())); + assertEquals("Either referenceModels or bmmRepository must be provided", ex.getMessage()); + } + + @Test + public void testGetMetaModel() { + MetaModelProvider metaModelProvider = new SimpleMetaModelProvider( + BuiltinReferenceModels.getAvailableModelInfoLookups(), + BuiltinReferenceModels.getBmmRepository(), + BuiltinReferenceModels.getAomProfiles() + ); + + Archetype archetype = new Archetype(); + archetype.setArchetypeId(new ArchetypeHRID("openEHR-EHR-CLUSTER.test.v1.0.0")); + archetype.setRmRelease("1.0.3"); + + MetaModel metaModel = metaModelProvider.getMetaModel(archetype); + assertTrue(metaModel.getModelInfoLookup() instanceof ArchieRMInfoLookup); + assertEquals("openehr", metaModel.getBmmModel().getRmPublisher()); + assertEquals("EHR", metaModel.getBmmModel().getModelName()); + assertEquals("1.0.3", metaModel.getBmmModel().getRmRelease()); + assertEquals("openEHR", metaModel.getAomProfile().getProfileName()); + assertNotNull(metaModel.getOdinInputObjectMapper()); + assertNotNull(metaModel.getOdinOutputObjectMapper()); + assertNotNull(metaModel.getJsonObjectMapper()); + + archetype.setRmRelease("1.0.4"); + + metaModel = metaModelProvider.getMetaModel(archetype); + assertTrue(metaModel.getModelInfoLookup() instanceof ArchieRMInfoLookup); + assertEquals("openehr", metaModel.getBmmModel().getRmPublisher()); + assertEquals("EHR", metaModel.getBmmModel().getModelName()); + assertEquals("1.0.4", metaModel.getBmmModel().getRmRelease()); + assertEquals("openEHR", metaModel.getAomProfile().getProfileName()); + assertNotNull(metaModel.getOdinInputObjectMapper()); + assertNotNull(metaModel.getOdinOutputObjectMapper()); + assertNotNull(metaModel.getJsonObjectMapper()); + + archetype.setRmRelease("1.99.1"); + + metaModel = metaModelProvider.getMetaModel(archetype); + assertTrue(metaModel.getModelInfoLookup() instanceof ArchieRMInfoLookup); + assertNull(metaModel.getBmmModel()); + assertEquals("openEHR", metaModel.getAomProfile().getProfileName()); + assertNotNull(metaModel.getOdinInputObjectMapper()); + assertNotNull(metaModel.getOdinOutputObjectMapper()); + assertNotNull(metaModel.getJsonObjectMapper()); + + archetype.setArchetypeId(new ArchetypeHRID("openEHR-TEST_PKG-CLUSTER.test.v1.0.0")); + archetype.setRmRelease("1.0.2"); + + metaModel = metaModelProvider.getMetaModel(archetype); + assertTrue(metaModel.getModelInfoLookup() instanceof TestRMInfoLookup); + assertEquals("openehr", metaModel.getBmmModel().getRmPublisher()); + assertEquals("TEST_PKG", metaModel.getBmmModel().getModelName()); + assertEquals("1.0.2", metaModel.getBmmModel().getRmRelease()); + assertEquals("openEHR", metaModel.getAomProfile().getProfileName()); + assertNull(metaModel.getOdinInputObjectMapper()); + assertNull(metaModel.getOdinOutputObjectMapper()); + assertNull(metaModel.getJsonObjectMapper()); + + archetype.setArchetypeId(new ArchetypeHRID("other-OTHER-CLUSTER.test.v1.0.0")); + archetype.setRmRelease("0.9.0"); + + ModelNotFoundException ex = assertThrows(ModelNotFoundException.class, () -> metaModelProvider.getMetaModel(archetype)); + assertEquals("model for other.OTHER version 0.9.0 not found", ex.getMessage()); + } + + @Test + public void testGetMetaModelModelInfoLookupOnly() { + MetaModelProvider metaModelProvider = new SimpleMetaModelProvider( + BuiltinReferenceModels.getAvailableModelInfoLookups(), + null, + BuiltinReferenceModels.getAomProfiles() + ); + + Archetype archetype = new Archetype(); + archetype.setArchetypeId(new ArchetypeHRID("openEHR-EHR-CLUSTER.test.v1.0.0")); + archetype.setRmRelease("1.0.3"); + + MetaModel metaModel = metaModelProvider.getMetaModel(archetype); + assertTrue(metaModel.getModelInfoLookup() instanceof ArchieRMInfoLookup); + assertNull(metaModel.getBmmModel()); + assertEquals("openEHR", metaModel.getAomProfile().getProfileName()); + assertNotNull(metaModel.getOdinInputObjectMapper()); + assertNotNull(metaModel.getOdinOutputObjectMapper()); + assertNotNull(metaModel.getJsonObjectMapper()); + + archetype.setRmRelease("1.0.4"); + + metaModel = metaModelProvider.getMetaModel(archetype); + assertTrue(metaModel.getModelInfoLookup() instanceof ArchieRMInfoLookup); + assertNull(metaModel.getBmmModel()); + assertEquals("openEHR", metaModel.getAomProfile().getProfileName()); + assertNotNull(metaModel.getOdinInputObjectMapper()); + assertNotNull(metaModel.getOdinOutputObjectMapper()); + assertNotNull(metaModel.getJsonObjectMapper()); + + archetype.setRmRelease("1.99.1"); + + metaModel = metaModelProvider.getMetaModel(archetype); + assertTrue(metaModel.getModelInfoLookup() instanceof ArchieRMInfoLookup); + assertNull(metaModel.getBmmModel()); + assertEquals("openEHR", metaModel.getAomProfile().getProfileName()); + assertNotNull(metaModel.getOdinInputObjectMapper()); + assertNotNull(metaModel.getOdinOutputObjectMapper()); + assertNotNull(metaModel.getJsonObjectMapper()); + + archetype.setArchetypeId(new ArchetypeHRID("openEHR-TEST_PKG-CLUSTER.test.v1.0.0")); + archetype.setRmRelease("1.0.2"); + + metaModel = metaModelProvider.getMetaModel(archetype); + assertTrue(metaModel.getModelInfoLookup() instanceof TestRMInfoLookup); + assertNull(metaModel.getBmmModel()); + assertEquals("openEHR", metaModel.getAomProfile().getProfileName()); + assertNull(metaModel.getOdinInputObjectMapper()); + assertNull(metaModel.getOdinOutputObjectMapper()); + assertNull(metaModel.getJsonObjectMapper()); + + archetype.setArchetypeId(new ArchetypeHRID("other-OTHER-CLUSTER.test.v1.0.0")); + archetype.setRmRelease("0.9.0"); + + ModelNotFoundException ex = assertThrows(ModelNotFoundException.class, () -> metaModelProvider.getMetaModel(archetype)); + assertEquals("model for other.OTHER version 0.9.0 not found", ex.getMessage()); + } + + @Test + public void testGetMetaModelBmmOnly() { + MetaModelProvider metaModelProvider = new SimpleMetaModelProvider( + null, + BuiltinReferenceModels.getBmmRepository(), + BuiltinReferenceModels.getAomProfiles() + ); + + Archetype archetype = new Archetype(); + archetype.setArchetypeId(new ArchetypeHRID("openEHR-EHR-CLUSTER.test.v1.0.0")); + archetype.setRmRelease("1.0.3"); + + MetaModel metaModel = metaModelProvider.getMetaModel(archetype); + assertNull(metaModel.getModelInfoLookup()); + assertEquals("openehr", metaModel.getBmmModel().getRmPublisher()); + assertEquals("EHR", metaModel.getBmmModel().getModelName()); + assertEquals("1.0.3", metaModel.getBmmModel().getRmRelease()); + assertEquals("openEHR", metaModel.getAomProfile().getProfileName()); + assertNull(metaModel.getOdinInputObjectMapper()); + assertNull(metaModel.getOdinOutputObjectMapper()); + assertNull(metaModel.getJsonObjectMapper()); + + archetype.setRmRelease("1.0.4"); + + metaModel = metaModelProvider.getMetaModel(archetype); + assertNull(metaModel.getModelInfoLookup()); + assertEquals("openehr", metaModel.getBmmModel().getRmPublisher()); + assertEquals("EHR", metaModel.getBmmModel().getModelName()); + assertEquals("1.0.4", metaModel.getBmmModel().getRmRelease()); + assertEquals("openEHR", metaModel.getAomProfile().getProfileName()); + assertNull(metaModel.getOdinInputObjectMapper()); + assertNull(metaModel.getOdinOutputObjectMapper()); + assertNull(metaModel.getJsonObjectMapper()); + + archetype.setRmRelease("1.99.1"); + + ModelNotFoundException ex = assertThrows(ModelNotFoundException.class, () -> metaModelProvider.getMetaModel(archetype)); + assertEquals("model for openEHR.EHR version 1.99.1 not found", ex.getMessage()); + + archetype.setArchetypeId(new ArchetypeHRID("openEHR-TEST_PKG-CLUSTER.test.v1.0.0")); + archetype.setRmRelease("1.0.2"); + + metaModel = metaModelProvider.getMetaModel(archetype); + assertNull(metaModel.getModelInfoLookup()); + assertEquals("openehr", metaModel.getBmmModel().getRmPublisher()); + assertEquals("TEST_PKG", metaModel.getBmmModel().getModelName()); + assertEquals("1.0.2", metaModel.getBmmModel().getRmRelease()); + assertEquals("openEHR", metaModel.getAomProfile().getProfileName()); + assertNull(metaModel.getOdinInputObjectMapper()); + assertNull(metaModel.getOdinOutputObjectMapper()); + assertNull(metaModel.getJsonObjectMapper()); + + archetype.setArchetypeId(new ArchetypeHRID("other-OTHER-CLUSTER.test.v1.0.0")); + archetype.setRmRelease("0.9.0"); + + ex = assertThrows(ModelNotFoundException.class, () -> metaModelProvider.getMetaModel(archetype)); + assertEquals("model for other.OTHER version 0.9.0 not found", ex.getMessage()); + } + + + @Test + public void testGetMetaModelNoAomProfiles() { + MetaModelProvider metaModelProvider = new SimpleMetaModelProvider( + BuiltinReferenceModels.getAvailableModelInfoLookups(), + BuiltinReferenceModels.getBmmRepository() + ); + + Archetype archetype = new Archetype(); + archetype.setArchetypeId(new ArchetypeHRID("openEHR-EHR-CLUSTER.test.v1.0.0")); + archetype.setRmRelease("1.0.3"); + + MetaModel metaModel = metaModelProvider.getMetaModel(archetype); + assertTrue(metaModel.getModelInfoLookup() instanceof ArchieRMInfoLookup); + assertEquals("openehr", metaModel.getBmmModel().getRmPublisher()); + assertEquals("EHR", metaModel.getBmmModel().getModelName()); + assertEquals("1.0.3", metaModel.getBmmModel().getRmRelease()); + assertNull(metaModel.getAomProfile()); + assertNotNull(metaModel.getOdinInputObjectMapper()); + assertNotNull(metaModel.getOdinOutputObjectMapper()); + assertNotNull(metaModel.getJsonObjectMapper()); + + archetype.setRmRelease("1.0.4"); + + metaModel = metaModelProvider.getMetaModel(archetype); + assertTrue(metaModel.getModelInfoLookup() instanceof ArchieRMInfoLookup); + assertEquals("openehr", metaModel.getBmmModel().getRmPublisher()); + assertEquals("EHR", metaModel.getBmmModel().getModelName()); + assertEquals("1.0.4", metaModel.getBmmModel().getRmRelease()); + assertNull(metaModel.getAomProfile()); + assertNotNull(metaModel.getOdinInputObjectMapper()); + assertNotNull(metaModel.getOdinOutputObjectMapper()); + assertNotNull(metaModel.getJsonObjectMapper()); + + archetype.setRmRelease("1.99.1"); + + metaModel = metaModelProvider.getMetaModel(archetype); + assertTrue(metaModel.getModelInfoLookup() instanceof ArchieRMInfoLookup); + assertNull(metaModel.getBmmModel()); + assertNull(metaModel.getAomProfile()); + assertNotNull(metaModel.getOdinInputObjectMapper()); + assertNotNull(metaModel.getOdinOutputObjectMapper()); + assertNotNull(metaModel.getJsonObjectMapper()); + + archetype.setArchetypeId(new ArchetypeHRID("openEHR-TEST_PKG-CLUSTER.test.v1.0.0")); + archetype.setRmRelease("1.0.2"); + + metaModel = metaModelProvider.getMetaModel(archetype); + assertTrue(metaModel.getModelInfoLookup() instanceof TestRMInfoLookup); + assertEquals("openehr", metaModel.getBmmModel().getRmPublisher()); + assertEquals("TEST_PKG", metaModel.getBmmModel().getModelName()); + assertEquals("1.0.2", metaModel.getBmmModel().getRmRelease()); + assertNull(metaModel.getAomProfile()); + assertNull(metaModel.getOdinInputObjectMapper()); + assertNull(metaModel.getOdinOutputObjectMapper()); + assertNull(metaModel.getJsonObjectMapper()); + + archetype.setArchetypeId(new ArchetypeHRID("other-OTHER-CLUSTER.test.v1.0.0")); + archetype.setRmRelease("0.9.0"); + + ModelNotFoundException ex = assertThrows(ModelNotFoundException.class, () -> metaModelProvider.getMetaModel(archetype)); + assertEquals("model for other.OTHER version 0.9.0 not found", ex.getMessage()); + } +} diff --git a/referencemodels/src/test/java/org/openehr/referencemodels/BuiltInReferenceModelsTest.java b/referencemodels/src/test/java/org/openehr/referencemodels/BuiltInReferenceModelsTest.java index 3f403f8e5..72b0bbb3b 100644 --- a/referencemodels/src/test/java/org/openehr/referencemodels/BuiltInReferenceModelsTest.java +++ b/referencemodels/src/test/java/org/openehr/referencemodels/BuiltInReferenceModelsTest.java @@ -27,6 +27,7 @@ public void bmmRepository() throws Exception { } @Test + @Deprecated public void overrideModelVersion() throws Exception { MetaModels metaModels = BuiltinReferenceModels.getMetaModels(); Archetype archetype = new Archetype(); diff --git a/tools/src/main/java/com/nedap/archie/adl14/ADL14Converter.java b/tools/src/main/java/com/nedap/archie/adl14/ADL14Converter.java index d8c6ab2c6..b22aec7ca 100644 --- a/tools/src/main/java/com/nedap/archie/adl14/ADL14Converter.java +++ b/tools/src/main/java/com/nedap/archie/adl14/ADL14Converter.java @@ -10,6 +10,7 @@ import com.nedap.archie.diff.Differentiator; import com.nedap.archie.flattener.Flattener; import com.nedap.archie.flattener.InMemoryFullArchetypeRepository; +import com.nedap.archie.rminfo.MetaModelProvider; import com.nedap.archie.rminfo.MetaModels; import java.text.MessageFormat; @@ -20,12 +21,20 @@ public class ADL14Converter { - private final MetaModels metaModels; + private final MetaModelProvider metaModelProvider; private final ADL14ConversionConfiguration conversionConfiguration; private InMemoryFullArchetypeRepository existingRepository; + /** + * @deprecated Use {@link #ADL14Converter(MetaModelProvider, ADL14ConversionConfiguration)} instead. + */ + @Deprecated public ADL14Converter(MetaModels metaModels, ADL14ConversionConfiguration conversionConfiguration) { - this.metaModels = metaModels; + this((MetaModelProvider) metaModels, conversionConfiguration); + } + + public ADL14Converter(MetaModelProvider metaModelProvider, ADL14ConversionConfiguration conversionConfiguration) { + this.metaModelProvider = metaModelProvider; this.conversionConfiguration = conversionConfiguration; } @@ -73,7 +82,7 @@ public ADL2ConversionResultList convert(List archetypes, ADL2Conversi // Process the archetypes ordered by specialization level unprocessed.sort(Comparator.comparingInt(Archetype::specializationDepth)); - Differentiator differentiator = new Differentiator(metaModels); + Differentiator differentiator = new Differentiator(metaModelProvider); for (Archetype archetype : unprocessed) { ADL2ConversionResult result; try { @@ -82,7 +91,7 @@ public ADL2ConversionResultList convert(List archetypes, ADL2Conversi if (parent == null) { throw new RuntimeException(MessageFormat.format("Cannot find parent {0} for archetype {1}", archetype.getParentArchetypeId(), archetype.getArchetypeId())); } - Archetype flatParent = new Flattener(repository, metaModels).flatten(parent); + Archetype flatParent = new Flattener(repository, metaModelProvider).flatten(parent); result = convert(archetype, flatParent, previousConversion); if (result.getArchetype() != null) { if (conversionConfiguration.isApplyDiff()) { @@ -125,16 +134,16 @@ private ADL2ConversionResult convert(Archetype archetype, Archetype flatParent, convertHeader(convertedArchetype); // Correct default multiplicities - new ADL14DefaultMultiplicitiesSetter(metaModels).setDefaults(convertedArchetype); + new ADL14DefaultMultiplicitiesSetter(metaModelProvider).setDefaults(convertedArchetype); // Convert nodeId's ADL2ConversionResult result = new ADL2ConversionResult(convertedArchetype); - ADL14NodeIDConverter adl14NodeIDConverter = new ADL14NodeIDConverter(this.metaModels, convertedArchetype, flatParent, conversionConfiguration, previousLog, result); + ADL14NodeIDConverter adl14NodeIDConverter = new ADL14NodeIDConverter(metaModelProvider, convertedArchetype, flatParent, conversionConfiguration, previousLog, result); ADL2ConversionLog conversionLog = adl14NodeIDConverter.convert(); result.setConversionLog(conversionLog); // Remove structures that are not default in ADL1.4, but are default in ADL2 - new DefaultRmStructureRemover(metaModels, true).removeRMDefaults(convertedArchetype); + new DefaultRmStructureRemover(metaModelProvider, true).removeRMDefaults(convertedArchetype); // Set some values that are not directly in ODIN or ADL ArchetypeParsePostProcessor.fixArchetype(convertedArchetype); diff --git a/tools/src/main/java/com/nedap/archie/adl14/DefaultRmStructureRemover.java b/tools/src/main/java/com/nedap/archie/adl14/DefaultRmStructureRemover.java index e69eb9675..069b3674d 100644 --- a/tools/src/main/java/com/nedap/archie/adl14/DefaultRmStructureRemover.java +++ b/tools/src/main/java/com/nedap/archie/adl14/DefaultRmStructureRemover.java @@ -3,6 +3,8 @@ import com.nedap.archie.adlparser.modelconstraints.BMMConstraintImposer; import com.nedap.archie.aom.*; import com.nedap.archie.base.MultiplicityInterval; +import com.nedap.archie.rminfo.MetaModel; +import com.nedap.archie.rminfo.MetaModelProvider; import com.nedap.archie.rminfo.MetaModels; import java.util.ArrayList; @@ -18,43 +20,63 @@ */ public class DefaultRmStructureRemover { - private final MetaModels metaModels; + private final MetaModelProvider metaModelProvider; private final boolean removeEmptyAttributes; + + private MetaModel metaModel; private BMMConstraintImposer constraintImposer; /** * Construct a DefaultRmStructureRemover that does not remove empty attributes * @param metaModels the metamodels containing metamodel information for the preset archetypes - * Part of the public API, do not remove + * @deprecated Use {@link #DefaultRmStructureRemover(MetaModelProvider)} instead. */ + @Deprecated public DefaultRmStructureRemover(MetaModels metaModels) { this(metaModels, false); } + /** + * Construct a DefaultRmStructureRemover that does not remove empty attributes + * @param metaModelProvider the metamodel provider for the preset archetypes + */ + public DefaultRmStructureRemover(MetaModelProvider metaModelProvider) { + this(metaModelProvider, false); + } + /** * Construct a DefaultRmStructureRemover * * @param metaModels the metamodels containing metamodel information for the preset archetypes * @param removeEmptyAttributes if true, will remove empty attributes. If false, will not + * @deprecated Use {@link #DefaultRmStructureRemover(MetaModelProvider, boolean)} instead. */ + @Deprecated public DefaultRmStructureRemover(MetaModels metaModels, boolean removeEmptyAttributes) { - this.metaModels = metaModels; + this((MetaModelProvider) metaModels, removeEmptyAttributes); + } + + /** + * Construct a DefaultRmStructureRemover + * + * @param metaModelProvider the metamodel provider for the preset archetypes + * @param removeEmptyAttributes if true, will remove empty attributes. If false, will not + */ + public DefaultRmStructureRemover(MetaModelProvider metaModelProvider, boolean removeEmptyAttributes) { + this.metaModelProvider = metaModelProvider; this.removeEmptyAttributes = removeEmptyAttributes; } public void removeRMDefaults(Archetype archetype) { - this.metaModels.selectModel(archetype); - if (metaModels.getSelectedModel() == null) { - throw new IllegalArgumentException("cannot find model for argument, so cannot remove default multiplicity"); - } - this.constraintImposer = new BMMConstraintImposer(metaModels.getSelectedBmmModel()); + metaModel = this.metaModelProvider.selectAndGetMetaModel(archetype); + this.constraintImposer = new BMMConstraintImposer(metaModel.getBmmModel()); removeRMDefaults(archetype.getDefinition()); } private void removeRMDefaults(CObject object) { // Remove occurrences if they are equal to the default occurrences of the object if (object.getOccurrences() != null) { - MultiplicityInterval defaultRMOccurrences = object.getDefaultRMOccurrences(metaModels::referenceModelPropMultiplicity); + MultiplicityInterval defaultRMOccurrences = object.getDefaultRMOccurrences(metaModel::referenceModelPropMultiplicity); if (defaultRMOccurrences.equals(object.getOccurrences())) { object.setOccurrences(null); } diff --git a/tools/src/main/java/com/nedap/archie/archetypevalidator/ArchetypeValidation.java b/tools/src/main/java/com/nedap/archie/archetypevalidator/ArchetypeValidation.java index b3da270dd..f62e89ba6 100644 --- a/tools/src/main/java/com/nedap/archie/archetypevalidator/ArchetypeValidation.java +++ b/tools/src/main/java/com/nedap/archie/archetypevalidator/ArchetypeValidation.java @@ -2,15 +2,25 @@ import com.nedap.archie.aom.Archetype; import com.nedap.archie.flattener.FullArchetypeRepository; +import com.nedap.archie.rminfo.MetaModel; import com.nedap.archie.rminfo.MetaModels; import java.util.List; +import java.util.Objects; /** * Created by pieter.bos on 31/03/2017. */ public interface ArchetypeValidation { - List validate(MetaModels models, Archetype archetype, Archetype flatParent, FullArchetypeRepository repository, ArchetypeValidationSettings settings); + /** + * @deprecated Use {@link #validate(MetaModel, Archetype, Archetype, FullArchetypeRepository, ArchetypeValidationSettings)} instead. + */ + @Deprecated + default List validate(MetaModels models, Archetype archetype, Archetype flatParent, FullArchetypeRepository repository, ArchetypeValidationSettings settings) { + return validate(Objects.requireNonNull(models.getSelectedModel(), "No MetaModel selected"), archetype, flatParent, repository, settings); + } + + List validate(MetaModel metaModel, Archetype archetype, Archetype flatParent, FullArchetypeRepository repository, ArchetypeValidationSettings settings); } diff --git a/tools/src/main/java/com/nedap/archie/archetypevalidator/ArchetypeValidationBase.java b/tools/src/main/java/com/nedap/archie/archetypevalidator/ArchetypeValidationBase.java index 2cf5684a4..b5a098af5 100644 --- a/tools/src/main/java/com/nedap/archie/archetypevalidator/ArchetypeValidationBase.java +++ b/tools/src/main/java/com/nedap/archie/archetypevalidator/ArchetypeValidationBase.java @@ -3,7 +3,7 @@ import com.nedap.archie.aom.Archetype; import com.nedap.archie.flattener.ArchetypeRepository; import com.nedap.archie.flattener.FullArchetypeRepository; -import com.nedap.archie.rminfo.MetaModels; +import com.nedap.archie.rminfo.MetaModel; import com.nedap.archie.rminfo.ModelInfoLookup; import java.util.ArrayList; @@ -16,19 +16,19 @@ public abstract class ArchetypeValidationBase implements ArchetypeValidation { protected FullArchetypeRepository repository; protected List messages; protected ModelInfoLookup lookup; - protected MetaModels combinedModels; + protected MetaModel metaModel; protected ArchetypeValidationSettings settings; public ArchetypeValidationBase() { } @Override - public List validate(MetaModels models, Archetype archetype, Archetype flatParent, FullArchetypeRepository repository, ArchetypeValidationSettings settings) { + public List validate(MetaModel metaModel, Archetype archetype, Archetype flatParent, FullArchetypeRepository repository, ArchetypeValidationSettings settings) { this.archetype = archetype; this.flatParent = flatParent; this.repository = repository; - this.lookup = models.getSelectedModelInfoLookup(); - this.combinedModels = models; + this.lookup = metaModel.getModelInfoLookup(); + this.metaModel = metaModel; this.settings = settings; messages = new ArrayList<>(); diff --git a/tools/src/main/java/com/nedap/archie/archetypevalidator/ArchetypeValidator.java b/tools/src/main/java/com/nedap/archie/archetypevalidator/ArchetypeValidator.java index 1b6dbe460..0336d9321 100644 --- a/tools/src/main/java/com/nedap/archie/archetypevalidator/ArchetypeValidator.java +++ b/tools/src/main/java/com/nedap/archie/archetypevalidator/ArchetypeValidator.java @@ -11,8 +11,7 @@ import com.nedap.archie.flattener.FlattenerConfiguration; import com.nedap.archie.flattener.FullArchetypeRepository; import com.nedap.archie.flattener.OverridingInMemFullArchetypeRepository; -import com.nedap.archie.rminfo.MetaModels; -import com.nedap.archie.rminfo.ReferenceModels; +import com.nedap.archie.rminfo.*; import org.openehr.utils.message.I18n; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -28,7 +27,7 @@ public class ArchetypeValidator { private static final Logger logger = LoggerFactory.getLogger(ArchetypeValidator.class); - private MetaModels combinedModels; + private final MetaModelProvider metaModelProvider; private FlattenerConfiguration flattenerConfiguration = FlattenerConfiguration.forFlattened(); //see comment on why there is a phase 0 @@ -41,11 +40,19 @@ public class ArchetypeValidator { private List validationsPhase3; public ArchetypeValidator(ReferenceModels models) { - this(new MetaModels(models, null)); + this(new SimpleMetaModelProvider(models, null)); } + /** + * @deprecated Use {@link #ArchetypeValidator(MetaModelProvider)} instead. + */ + @Deprecated public ArchetypeValidator(MetaModels models) { - this.combinedModels = models; + this((MetaModelProvider) models); + } + + public ArchetypeValidator(MetaModelProvider metaModelProvider) { + this.metaModelProvider = metaModelProvider; validationsPhase0 = new ArrayList<>(); //defined in spec, but not in three phase validator and not in grammar //eiffel checks these in the parser @@ -120,14 +127,11 @@ public ValidationResult validate(Archetype archetype, FullArchetypeRepository re } repository = extraRepository; - combinedModels.selectModel(archetype); + MetaModel metaModel = metaModelProvider.selectAndGetMetaModel(archetype); - if(combinedModels.getSelectedModelInfoLookup() == null && combinedModels.getSelectedBmmModel() == null) { - throw new UnsupportedOperationException("reference model unknown for archetype " + archetype.getArchetypeId()); - } //we assume we always want a new validation to be run, for example because the archetype //has been updated. Therefore, do not retrieve the old result from the repository - archetype = cloneAndPreprocess(combinedModels, archetype);//this clones the actual archetype so the source does not get changed + archetype = cloneAndPreprocess(metaModel, archetype);//this clones the actual archetype so the source does not get changed Archetype flatParent = null; if(archetype.isSpecialized()) { ValidationResult infiniteLoopResult = checkForInfiniteLoopInSpecialisation(repository, archetype); @@ -135,7 +139,7 @@ public ValidationResult validate(Archetype archetype, FullArchetypeRepository re return infiniteLoopResult; } ValidationResult parentValidationResult = repository.compileAndRetrieveValidationResult(archetype.getParentArchetypeId(), this); - combinedModels.selectModel(archetype); + metaModelProvider.selectAndGetMetaModel(archetype); // For backwards compatibility if(parentValidationResult != null) { if(parentValidationResult.passes()) { flatParent = parentValidationResult.getFlattened(); @@ -171,23 +175,23 @@ public ValidationResult validate(Archetype archetype, FullArchetypeRepository re for(TemplateOverlay overlay:((Template) archetype).getTemplateOverlays()) { //validate the overlays first, but make sure to do that only once (so don't call this same method!) extraRepository.compileAndRetrieveValidationResult(overlay.getArchetypeId().toString(), this); - combinedModels.selectModel(archetype); + metaModelProvider.selectAndGetMetaModel(archetype); // For backwards compatibility } } - List messages = runValidations(archetype, repository, settings, flatParent, validationsPhase0); + List messages = runValidations(metaModel, archetype, repository, settings, flatParent, validationsPhase0); ValidationResult result = new ValidationResult(archetype); result.setErrors(messages); if(result.passes()) { //continue running only if the basic phase 0 validation run, otherwise we get annoying exceptions - messages.addAll(runValidations(archetype, repository, settings, flatParent, validationsPhase1)); + messages.addAll(runValidations(metaModel, archetype, repository, settings, flatParent, validationsPhase1)); //the separate validations will check if the archtype is specialized and if they need this in phase 2 //because the RM validations are technically phase 2 and required to run //also the separate validations are implemented so that they can run with errors in phase 1 without exceptions //plus exceptions will nicely be logged as an OTHER error type - we can safely run it and you will get //more errors in one go - could be useful - messages.addAll(runValidations(archetype, repository, settings, flatParent, validationsPhase2)); + messages.addAll(runValidations(metaModel, archetype, repository, settings, flatParent, validationsPhase2)); } result.setErrors(messages); @@ -203,10 +207,10 @@ public ValidationResult validate(Archetype archetype, FullArchetypeRepository re if(result.passes() || settings.isAlwaysTryToFlatten()) { try { - Archetype flattened = new Flattener(repository, combinedModels, flattenerConfiguration).flatten(archetype); + Archetype flattened = new Flattener(repository, metaModelProvider, flattenerConfiguration).flatten(archetype); try { - OperationalTemplate operationalTemplate = (OperationalTemplate) new Flattener(repository, combinedModels).createOperationalTemplate(true).flatten(archetype); + OperationalTemplate operationalTemplate = (OperationalTemplate) new Flattener(repository, metaModelProvider).createOperationalTemplate(true).flatten(archetype); extraRepository.addExtraOperationalTemplate(operationalTemplate); } catch (Exception e) { //this is probably an error in an included archetype, so ignore it here @@ -217,7 +221,7 @@ public ValidationResult validate(Archetype archetype, FullArchetypeRepository re } result.setFlattened(flattened); if(result.passes()) { - messages.addAll(runValidations(flattened, repository, settings, flatParent, validationsPhase3)); + messages.addAll(runValidations(metaModel, flattened, repository, settings, flatParent, validationsPhase3)); } } catch (Exception e) { messages.add(new ValidationMessage(ErrorType.OTHER, null, "flattening failed with exception " + e)); @@ -229,18 +233,18 @@ public ValidationResult validate(Archetype archetype, FullArchetypeRepository re return result; } - private Archetype cloneAndPreprocess(MetaModels models, Archetype archetype) { + private Archetype cloneAndPreprocess(MetaModel metaModel, Archetype archetype) { Archetype preprocessed = archetype.clone(); - new ReflectionConstraintImposer(models).setSingleOrMultiple(preprocessed.getDefinition()); + new ReflectionConstraintImposer(metaModel).setSingleOrMultiple(preprocessed.getDefinition()); return preprocessed; } - private List runValidations(Archetype archetype, FullArchetypeRepository repository, ArchetypeValidationSettings settings, Archetype flatParent, List validations) { + private List runValidations(MetaModel metaModel, Archetype archetype, FullArchetypeRepository repository, ArchetypeValidationSettings settings, Archetype flatParent, List validations) { List messages = new ArrayList<>(); for(ArchetypeValidation validation: validations) { try { - messages.addAll(validation.validate(combinedModels, archetype, flatParent, repository, settings)); + messages.addAll(validation.validate(metaModel, archetype, flatParent, repository, settings)); } catch (Exception e) { logger.error("error running validation processor", e); e.printStackTrace(); diff --git a/tools/src/main/java/com/nedap/archie/archetypevalidator/validations/AnnotationsValidation.java b/tools/src/main/java/com/nedap/archie/archetypevalidator/validations/AnnotationsValidation.java index 122d4a2ad..35bcae8f3 100644 --- a/tools/src/main/java/com/nedap/archie/archetypevalidator/validations/AnnotationsValidation.java +++ b/tools/src/main/java/com/nedap/archie/archetypevalidator/validations/AnnotationsValidation.java @@ -32,7 +32,7 @@ public void validate() { //apparently the operational template creation failed. Try to lookup the path anyway in the original archetype operationalTemplate = archetype; } - if(!AOMUtils.isPathInArchetypeOrRm(combinedModels.getSelectedModel(), path, operationalTemplate)) { + if(!AOMUtils.isPathInArchetypeOrRm(metaModel, path, operationalTemplate)) { addMessage(ErrorType.VRANP, I18n.t("The path {0} referenced in the annotations does not exist in the flat archetype or reference model", path)); } } diff --git a/tools/src/main/java/com/nedap/archie/archetypevalidator/validations/AttributeTupleValidation.java b/tools/src/main/java/com/nedap/archie/archetypevalidator/validations/AttributeTupleValidation.java index 5896869ef..bca9cd5ce 100644 --- a/tools/src/main/java/com/nedap/archie/archetypevalidator/validations/AttributeTupleValidation.java +++ b/tools/src/main/java/com/nedap/archie/archetypevalidator/validations/AttributeTupleValidation.java @@ -25,7 +25,7 @@ protected void validate(CComplexObject cObject) { addMessageWithPath(ErrorType.OTHER, cObject.getPath(), "An attribute tuple must have members"); } else { for(CAttribute cAttribute:tuple.getMembers()) { - if (!combinedModels.attributeExists(cObject.getRmTypeName(), cAttribute.getRmAttributeName())) { + if (!metaModel.attributeExists(cObject.getRmTypeName(), cAttribute.getRmAttributeName())) { addMessageWithPath(ErrorType.VCARM, cObject.getPath(), I18n.t("Tuple member attribute {0} is not an attribute of type {1}", cAttribute.getRmAttributeName(), cObject.getRmTypeName())); } diff --git a/tools/src/main/java/com/nedap/archie/archetypevalidator/validations/BasicTerminologyValidation.java b/tools/src/main/java/com/nedap/archie/archetypevalidator/validations/BasicTerminologyValidation.java index 6e4d8cc7d..35bddbcd5 100644 --- a/tools/src/main/java/com/nedap/archie/archetypevalidator/validations/BasicTerminologyValidation.java +++ b/tools/src/main/java/com/nedap/archie/archetypevalidator/validations/BasicTerminologyValidation.java @@ -80,7 +80,7 @@ private void validateTerminologyBindings() { //if not a valid path, fine } if (!AOMUtils.isValidCode(constraintCodeOrPath) && !( - archetypeHasPath || combinedModels.hasReferenceModelPath(archetype.getDefinition().getRmTypeName(), constraintCodeOrPath) + archetypeHasPath || metaModel.hasReferenceModelPath(archetype.getDefinition().getRmTypeName(), constraintCodeOrPath) ) ) { addMessage(ErrorType.VTTBK, I18n.t("Term binding key {0} in path format is not present in archetype", constraintCodeOrPath)); diff --git a/tools/src/main/java/com/nedap/archie/archetypevalidator/validations/CodeValidation.java b/tools/src/main/java/com/nedap/archie/archetypevalidator/validations/CodeValidation.java index e1bcf560e..da52929ab 100644 --- a/tools/src/main/java/com/nedap/archie/archetypevalidator/validations/CodeValidation.java +++ b/tools/src/main/java/com/nedap/archie/archetypevalidator/validations/CodeValidation.java @@ -29,7 +29,7 @@ public void validate(CObject cObject) { addMessageWithPath(ErrorType.VTSD, cObject.path(), I18n.t("The code specialization depth of code {0} is {1}, which is greater than archetype specialization depth {2}", nodeId, codeSpecializationDepth, archetypeSpecializationDepth)); - } else if (cObject.isRoot() || parentIsMultiple(cObject, flatParent, combinedModels)) { + } else if (cObject.isRoot() || parentIsMultiple(cObject, flatParent, metaModel)) { if ((codeSpecializationDepth < archetypeSpecializationDepth && flatParent != null && !flatParent.getTerminology().hasIdCode(nodeId)) || (codeSpecializationDepth == archetypeSpecializationDepth && !archetype.getTerminology().hasIdCode(nodeId))) { addMessageWithPath(ErrorType.VATID, cObject.path(), diff --git a/tools/src/main/java/com/nedap/archie/archetypevalidator/validations/DefinitionStructureValidation.java b/tools/src/main/java/com/nedap/archie/archetypevalidator/validations/DefinitionStructureValidation.java index c6f0818a2..42a6707e7 100644 --- a/tools/src/main/java/com/nedap/archie/archetypevalidator/validations/DefinitionStructureValidation.java +++ b/tools/src/main/java/com/nedap/archie/archetypevalidator/validations/DefinitionStructureValidation.java @@ -58,7 +58,7 @@ protected void validate(CAttribute cAttribute) { addPathNotFoundInParentError(cAttribute); } else { PathSegment terminalNode = pathSegments.get(pathSegments.size() - 1); - if (!combinedModels.attributeExists(parent.getRmTypeName(), terminalNode.getNodeName())) { + if (!metaModel.attributeExists(parent.getRmTypeName(), terminalNode.getNodeName())) { addPathNotFoundInParentError(cAttribute); } } diff --git a/tools/src/main/java/com/nedap/archie/archetypevalidator/validations/FlatFormValidation.java b/tools/src/main/java/com/nedap/archie/archetypevalidator/validations/FlatFormValidation.java index 010a7edbf..e68b15d8b 100644 --- a/tools/src/main/java/com/nedap/archie/archetypevalidator/validations/FlatFormValidation.java +++ b/tools/src/main/java/com/nedap/archie/archetypevalidator/validations/FlatFormValidation.java @@ -35,7 +35,7 @@ protected void validate(CComplexObjectProxy cObject) { CComplexObject replacementComplexObject = complexObjectProxyReplacement.getReplacement(); - if(!combinedModels.rmTypesConformant(replacementComplexObject.getRmTypeName(), cObject.getRmTypeName())) { + if(!metaModel.rmTypesConformant(replacementComplexObject.getRmTypeName(), cObject.getRmTypeName())) { addMessageWithPath(ErrorType.VUNT, cObject.path(), I18n.t("Use_node (C_COMPLEX_OBJECT_PROXY) points to type {0}, which does not conform to type {1}", replacementComplexObject.getRmTypeName(), cObject.getRmTypeName())); } } else { @@ -78,7 +78,7 @@ private void validateTerminologyBindings() { //if not a valid path, fine } if(!AOMUtils.isValidCode(constraintCodeOrPath) && !( - archetypeHasPath || combinedModels.hasReferenceModelPath(archetype.getDefinition().getRmTypeName(), constraintCodeOrPath) + archetypeHasPath || metaModel.hasReferenceModelPath(archetype.getDefinition().getRmTypeName(), constraintCodeOrPath) ) ) { addMessage(ErrorType.VTTBK, I18n.t("Term binding key {0} points to a path that cannot be found in the archetype", constraintCodeOrPath)); diff --git a/tools/src/main/java/com/nedap/archie/archetypevalidator/validations/RmOverlayValidation.java b/tools/src/main/java/com/nedap/archie/archetypevalidator/validations/RmOverlayValidation.java index 5f618e33b..dc119dbe5 100644 --- a/tools/src/main/java/com/nedap/archie/archetypevalidator/validations/RmOverlayValidation.java +++ b/tools/src/main/java/com/nedap/archie/archetypevalidator/validations/RmOverlayValidation.java @@ -30,7 +30,7 @@ public void validate() { //apparently the operational template creation failed. Try to lookup the path anyway in the original archetype operationalTemplate = archetype; } - if(!AOMUtils.isPathInArchetypeOrRm(combinedModels.getSelectedModel(), path, operationalTemplate)) { + if(!AOMUtils.isPathInArchetypeOrRm(metaModel, path, operationalTemplate)) { addMessage(ErrorType.VRANP, I18n.t("The path {0} referenced in the rm visibility does not exist in the flat archetype", path)); } diff --git a/tools/src/main/java/com/nedap/archie/archetypevalidator/validations/SpecializedDefinitionValidation.java b/tools/src/main/java/com/nedap/archie/archetypevalidator/validations/SpecializedDefinitionValidation.java index e13859cba..0056af95b 100644 --- a/tools/src/main/java/com/nedap/archie/archetypevalidator/validations/SpecializedDefinitionValidation.java +++ b/tools/src/main/java/com/nedap/archie/archetypevalidator/validations/SpecializedDefinitionValidation.java @@ -139,7 +139,7 @@ private boolean hasAssertions(List assertions) { } private void validateConformsTo(CObject cObject, CObject parentCObject) { - ConformanceCheckResult conformanceCheckResult = cObject.cConformsTo(parentCObject, combinedModels::rmTypesConformant); + ConformanceCheckResult conformanceCheckResult = cObject.cConformsTo(parentCObject, metaModel::rmTypesConformant); if(!conformanceCheckResult.doesConform()) { if(conformanceCheckResult.getErrorType() != null) { @@ -156,7 +156,7 @@ private void validateConformsTo(CObject cObject, CObject parentCObject) { if(cComplexObject.getAttributeTuples() != null && parentCComplexObject.getAttributeTuples() != null) { for(CAttributeTuple tuple:cComplexObject.getAttributeTuples()) { CAttributeTuple matchingTuple = AOMUtils.findMatchingTuple(parentCComplexObject.getAttributeTuples(), tuple); - if(matchingTuple != null && ! tuple.cConformsTo(matchingTuple, combinedModels::rmTypesConformant)) { + if(matchingTuple != null && ! tuple.cConformsTo(matchingTuple, metaModel::rmTypesConformant)) { //tuple does not conform addMessageWithPath(ErrorType.VTPNC, cObject.path(), @@ -187,7 +187,7 @@ private void validateConformsTo(CObject cObject, CObject parentCObject) { private boolean hasConformingParent(CAttribute parentAttribute, CPrimitiveObject member) { for(CObject parentCObject:parentAttribute.getChildren()) { - ConformanceCheckResult result = member.cConformsTo(parentCObject, (a, b) -> combinedModels.rmTypesConformant(a, b)); + ConformanceCheckResult result = member.cConformsTo(parentCObject, (a, b) -> metaModel.rmTypesConformant(a, b)); if(result.doesConform()) { return true; } @@ -257,12 +257,12 @@ private boolean rootMatchesSlotType(ArchetypeSlot slot, CArchetypeRoot root) { String rootRmTypeName = root.getRmTypeName(); String rootReferenceRmTypeName = new ArchetypeHRID(root.getArchetypeRef()).getRmClass(); - if(!combinedModels.typeNameExists(rootRmTypeName) || !combinedModels.typeNameExists(rootReferenceRmTypeName)) { + if(!metaModel.typeNameExists(rootRmTypeName) || !metaModel.typeNameExists(rootReferenceRmTypeName)) { return false; } - else if(!combinedModels.rmTypesConformant(rootRmTypeName, slotRmTypeName)) { + else if(!metaModel.rmTypesConformant(rootRmTypeName, slotRmTypeName)) { return false; - } else if (!combinedModels.rmTypesConformant(rootReferenceRmTypeName, slotRmTypeName)) { + } else if (!metaModel.rmTypesConformant(rootReferenceRmTypeName, slotRmTypeName)) { return false; } return true; diff --git a/tools/src/main/java/com/nedap/archie/archetypevalidator/validations/SpecializedOccurrencesValidation.java b/tools/src/main/java/com/nedap/archie/archetypevalidator/validations/SpecializedOccurrencesValidation.java index edb055089..a74619dfd 100644 --- a/tools/src/main/java/com/nedap/archie/archetypevalidator/validations/SpecializedOccurrencesValidation.java +++ b/tools/src/main/java/com/nedap/archie/archetypevalidator/validations/SpecializedOccurrencesValidation.java @@ -81,8 +81,8 @@ private ConformanceCheckResult childNodesConformToParent(CObject childCObject, C return ConformanceCheckResult.conforms(); } - MultiplicityInterval parentNodeOccurrences = parentCObject.effectiveOccurrences(combinedModels::referenceModelPropMultiplicity); - MultiplicityInterval childNodeOccurrences = childCObject.effectiveOccurrences(combinedModels::referenceModelPropMultiplicity); + MultiplicityInterval parentNodeOccurrences = parentCObject.effectiveOccurrences(metaModel::referenceModelPropMultiplicity); + MultiplicityInterval childNodeOccurrences = childCObject.effectiveOccurrences(metaModel::referenceModelPropMultiplicity); if(parentCObject.getNodeId().equals(childCObject.getNodeId()) && parentNodeOccurrences.equals(childNodeOccurrences)) { //this is the parent node appearing in the flattened child archetype without change in occurrence. That is guaranteed to be valid @@ -97,7 +97,7 @@ private ConformanceCheckResult childNodesConformToParent(CObject childCObject, C if (allRedefinedNodeOccurrencesSummed.isOpen()) { break; } - MultiplicityInterval redefinedOccurrences = childNode.effectiveOccurrences(combinedModels::referenceModelPropMultiplicity); + MultiplicityInterval redefinedOccurrences = childNode.effectiveOccurrences(metaModel::referenceModelPropMultiplicity); if (!allRedefinedNodeOccurrencesSummed.isLowerUnbounded()) { Integer lower = allRedefinedNodeOccurrencesSummed.getLower(); if (!redefinedOccurrences.isLowerUnbounded()) { @@ -119,7 +119,7 @@ private ConformanceCheckResult childNodesConformToParent(CObject childCObject, C } MultiplicityInterval cardinality = childCObject.getParent().getCardinality() == null ? null : childCObject.getParent().getCardinality().getInterval(); if(cardinality == null) { - cardinality = combinedModels.referenceModelPropMultiplicity(childCObject.getParent().getParent().getRmTypeName(), childCObject.getParent().getRmAttributeName()); + cardinality = metaModel.referenceModelPropMultiplicity(childCObject.getParent().getParent().getRmTypeName(), childCObject.getParent().getRmAttributeName()); } if(cardinality != null && !cardinality.isUpperUnbounded() && (allRedefinedNodeOccurrencesSummed.isUpperUnbounded() || allRedefinedNodeOccurrencesSummed.getUpper() > cardinality.getUpper())) { @@ -132,7 +132,7 @@ private ConformanceCheckResult childNodesConformToParent(CObject childCObject, C } return ConformanceCheckResult.fails(ErrorType.VSONCO, I18n.t("Occurrences {0}, which is the sum of {1}, does not conform to {2}", allRedefinedNodeOccurrencesSummed, - allRedefinedNodes.stream().map(c -> c.effectiveOccurrences(combinedModels::referenceModelPropMultiplicity).toString()).collect(Collectors.joining(", ")), + allRedefinedNodes.stream().map(c -> c.effectiveOccurrences(metaModel::referenceModelPropMultiplicity).toString()).collect(Collectors.joining(", ")), parentCObject.getOccurrences())); } } diff --git a/tools/src/main/java/com/nedap/archie/archetypevalidator/validations/ValidateAgainstReferenceModel.java b/tools/src/main/java/com/nedap/archie/archetypevalidator/validations/ValidateAgainstReferenceModel.java index c53a068b2..205abf1cc 100644 --- a/tools/src/main/java/com/nedap/archie/archetypevalidator/validations/ValidateAgainstReferenceModel.java +++ b/tools/src/main/java/com/nedap/archie/archetypevalidator/validations/ValidateAgainstReferenceModel.java @@ -24,7 +24,7 @@ protected void validate(CComplexObject cObject) { } private void validateTypes(CObject cObject) { - if (!combinedModels.typeNameExists(cObject.getRmTypeName())) { + if (!metaModel.typeNameExists(cObject.getRmTypeName())) { addMessageWithPath(ErrorType.VCORM, cObject.getPath(), I18n.t("Type name {0} does not exist", cObject.getRmTypeName())); } else { CAttribute owningAttribute = cObject.getParent(); @@ -36,7 +36,7 @@ private void validateTypes(CObject cObject) { owningObject = differentialPathFromParent == null ? null : differentialPathFromParent.getParent(); } if (owningObject != null) { - if(!combinedModels.typeConformant(owningObject.getRmTypeName(), owningAttribute.getRmAttributeName(), cObject.getRmTypeName())) { + if(!metaModel.typeConformant(owningObject.getRmTypeName(), owningAttribute.getRmAttributeName(), cObject.getRmTypeName())) { addMessageWithPath(ErrorType.VCORMT, cObject.getPath(), I18n.t("Attribute {0}.{1} cannot contain type {2}", owningObject.getRmTypeName(), owningAttribute.getRmAttributeName(), cObject.getRmTypeName())); @@ -58,7 +58,7 @@ protected void validate(CPrimitiveObject cObject) { CAttribute attribute = cObject.getParent(); if(attribute.getDifferentialPath() == null) { CObject parentConstraint = attribute.getParent(); - if(!combinedModels.validatePrimitiveType(parentConstraint.getRmTypeName(), attribute.getRmAttributeName(), cObject)) { + if(!metaModel.validatePrimitiveType(parentConstraint.getRmTypeName(), attribute.getRmAttributeName(), cObject)) { addMessageWithPath(ErrorType.VCORMT, cObject.path(), I18n.t("Attribute {0}.{1} cannot be constrained by a {2}", parentConstraint.getRmTypeName(), attribute.getRmAttributeName(), cObject == null ? null : cObject.getClass().getSimpleName())); @@ -71,7 +71,7 @@ protected void validate(CPrimitiveObject cObject) { if(differentialPathFromParent instanceof CAttribute) { CAttribute parentAttribute = (CAttribute) differentialPathFromParent; CObject parentConstraint = parentAttribute.getParent(); - if(!combinedModels.validatePrimitiveType(parentConstraint.getRmTypeName(), parentAttribute.getRmAttributeName(), cObject)) { + if(!metaModel.validatePrimitiveType(parentConstraint.getRmTypeName(), parentAttribute.getRmAttributeName(), cObject)) { I18n.t("Attribute {0}.{1} cannot be constrained by a {2}", parentConstraint.getRmTypeName(), parentAttribute.getRmAttributeName(), cObject == null ? null : cObject.getClass().getSimpleName()); } @@ -94,11 +94,11 @@ public void validate(CAttribute cAttribute) { owningObject = differentialPathFromParent == null ? null : differentialPathFromParent.getParent(); } if(owningObject != null) { - if (!combinedModels.attributeExists(owningObject.getRmTypeName(), cAttribute.getRmAttributeName())) { + if (!metaModel.attributeExists(owningObject.getRmTypeName(), cAttribute.getRmAttributeName())) { addMessageWithPath(ErrorType.VCARM, cAttribute.getPath(), I18n.t("{0} is not a known attribute of {1}", cAttribute.getRmAttributeName(), owningObject.getRmTypeName())); } else { - CAttribute defaultAttribute = new ReflectionConstraintImposer(combinedModels).getDefaultAttribute(owningObject.getRmTypeName(), cAttribute.getRmAttributeName()); + CAttribute defaultAttribute = new ReflectionConstraintImposer(metaModel).getDefaultAttribute(owningObject.getRmTypeName(), cAttribute.getRmAttributeName()); if(defaultAttribute != null) { if(cAttribute.getExistence() != null) { if(!defaultAttribute.getExistence().contains(cAttribute.getExistence())) { diff --git a/tools/src/main/java/com/nedap/archie/archetypevalidator/validations/VariousStructureValidation.java b/tools/src/main/java/com/nedap/archie/archetypevalidator/validations/VariousStructureValidation.java index 3d4935d7b..aa185bc0e 100644 --- a/tools/src/main/java/com/nedap/archie/archetypevalidator/validations/VariousStructureValidation.java +++ b/tools/src/main/java/com/nedap/archie/archetypevalidator/validations/VariousStructureValidation.java @@ -53,12 +53,12 @@ protected void validate(CComplexObject cComplexObject) { String archetypeRootTypeName = cComplexObject.getRmTypeName(); String archetypeReferenceTypeName = hrId.getRmClass(); - if (combinedModels.typeNameExists(archetypeRootTypeName)) { + if (metaModel.typeNameExists(archetypeRootTypeName)) { //if parent type info not found will be checked later in phase 2 - if (!combinedModels.typeNameExists(archetypeReferenceTypeName)) { + if (!metaModel.typeNameExists(archetypeReferenceTypeName)) { addMessageWithPath(ErrorType.VCORM, cComplexObject.getPath(), I18n.t("Archetype referenced in use_archetype points to class {0}, which does not exist in this reference model", cComplexObject.getRmTypeName())); - } else if (!combinedModels.rmTypesConformant(archetypeReferenceTypeName, archetypeRootTypeName)) { + } else if (!metaModel.rmTypesConformant(archetypeReferenceTypeName, archetypeRootTypeName)) { addMessageWithPath(ErrorType.VARXTV, cComplexObject.getPath(), I18n.t("Use_archetype points to type {0}, which is not conformant for type {1} of the archetype root used", cComplexObject.getRmTypeName(), archetypeRootTypeName)); diff --git a/tools/src/main/java/com/nedap/archie/creation/ExampleJsonInstanceGenerator.java b/tools/src/main/java/com/nedap/archie/creation/ExampleJsonInstanceGenerator.java index d8347502f..ee302ad85 100644 --- a/tools/src/main/java/com/nedap/archie/creation/ExampleJsonInstanceGenerator.java +++ b/tools/src/main/java/com/nedap/archie/creation/ExampleJsonInstanceGenerator.java @@ -10,6 +10,8 @@ import com.nedap.archie.aom.terminology.ValueSet; import com.nedap.archie.base.Interval; import com.nedap.archie.base.MultiplicityInterval; +import com.nedap.archie.rminfo.MetaModel; +import com.nedap.archie.rminfo.MetaModelProvider; import com.nedap.archie.rminfo.MetaModels; import org.openehr.bmm.core.*; import org.openehr.bmm.persistence.validation.BmmDefinitions; @@ -36,9 +38,10 @@ public class ExampleJsonInstanceGenerator { public static final String MISSING_TERM_IN_ARCHETYPE_FOR_LANGUAGE = "missing term in archetype for language "; private final String language; - private final MetaModels models; + private final MetaModelProvider metaModelProvider; private OperationalTemplate archetype; private String rmRelease; + private MetaModel metaModel; private BmmModel bmm; private AomProfile aomProfile; @@ -49,9 +52,17 @@ public class ExampleJsonInstanceGenerator { OpenEhrRmInstanceGenerator openEhrRmInstanceGenerator; + /** + * @deprecated Use {@link #ExampleJsonInstanceGenerator(MetaModelProvider, String)} instead. + */ + @Deprecated public ExampleJsonInstanceGenerator(MetaModels models, String language) { + this((MetaModelProvider) models, language); + } + + public ExampleJsonInstanceGenerator(MetaModelProvider metaModelProvider, String language) { this.language = language; - this.models = models; + this.metaModelProvider = metaModelProvider; openEhrRmInstanceGenerator = new OpenEhrRmInstanceGenerator(this, typePropertyName); } @@ -63,9 +74,9 @@ public Map generate(OperationalTemplate archetype) { !(rmRelease.equalsIgnoreCase("1.0.4") || rmRelease.equalsIgnoreCase("1.1.0"))) { rmRelease = "1.1.0"; } - models.selectModel(archetype, rmRelease); - aomProfile = models.getSelectedAomProfile(); - bmm = models.getSelectedBmmModel(); + metaModel = metaModelProvider.selectAndGetMetaModel(archetype, rmRelease); + aomProfile = metaModel.getAomProfile(); + bmm = metaModel.getBmmModel(); return generate(archetype.getDefinition()); } @@ -129,7 +140,7 @@ private Map generate(CComplexObject cObject) { List children = new ArrayList<>(); for (CObject child : attribute.getChildren()) { - MultiplicityInterval multiplicityInterval = child.effectiveOccurrences(models.getSelectedModel()::referenceModelPropMultiplicity); + MultiplicityInterval multiplicityInterval = child.effectiveOccurrences(metaModel::referenceModelPropMultiplicity); int occurrences = Math.max(1, multiplicityInterval.getLower()); if(multiplicityInterval.isProhibited()) { occurrences = 0; diff --git a/tools/src/main/java/com/nedap/archie/diff/Differentiator.java b/tools/src/main/java/com/nedap/archie/diff/Differentiator.java index 1c382ba77..51337baeb 100644 --- a/tools/src/main/java/com/nedap/archie/diff/Differentiator.java +++ b/tools/src/main/java/com/nedap/archie/diff/Differentiator.java @@ -5,34 +5,43 @@ import com.nedap.archie.adlparser.modelconstraints.ModelConstraintImposer; import com.nedap.archie.adlparser.modelconstraints.ReflectionConstraintImposer; import com.nedap.archie.aom.Archetype; +import com.nedap.archie.rminfo.MetaModel; +import com.nedap.archie.rminfo.MetaModelProvider; import com.nedap.archie.rminfo.MetaModels; public class Differentiator { - private final MetaModels metaModels; + private final MetaModelProvider metaModelProvider; + /** + * @deprecated Use {@link #Differentiator(MetaModelProvider)} instead. + */ + @Deprecated public Differentiator(MetaModels metaModels) { - this.metaModels = metaModels; + this((MetaModelProvider) metaModels); } + public Differentiator(MetaModelProvider metaModelProvider) { + this.metaModelProvider = metaModelProvider; + } public Archetype differentiate(Archetype flatChild, Archetype flatParent) { return differentiate(flatChild, flatParent, true); } public Archetype differentiate(Archetype flatChild, Archetype flatParent, boolean addSiblingOrder) { - metaModels.selectModel(flatChild); + MetaModel metaModel = metaModelProvider.selectAndGetMetaModel(flatChild); ModelConstraintImposer constraintImposer; - if(metaModels.getSelectedBmmModel() != null) { - constraintImposer = new BMMConstraintImposer(metaModels.getSelectedBmmModel()); + if(metaModel.getBmmModel() != null) { + constraintImposer = new BMMConstraintImposer(metaModel.getBmmModel()); } else { - constraintImposer = new ReflectionConstraintImposer(metaModels.getSelectedModelInfoLookup()); + constraintImposer = new ReflectionConstraintImposer(metaModel.getModelInfoLookup()); } Archetype result = flatChild.clone(); UnconstrainedIntervalRemover.removeUnconstrainedIntervals(result); if(addSiblingOrder) { - new LCSOrderingDiff(metaModels).addSiblingOrder(result, flatChild, flatParent); + new LCSOrderingDiff(metaModel).addSiblingOrder(result, flatChild, flatParent); } new ConstraintDifferentiator(constraintImposer, flatParent).removeUnspecializedConstraints(result, flatParent); new AnnotationDifferentiator().differentiate(result, flatParent); @@ -40,7 +49,7 @@ public Archetype differentiate(Archetype flatChild, Archetype flatParent, boolea new DifferentialPathGenerator().replace(result); new TerminologyDifferentiator().differentiate(result); - new DefaultRmStructureRemover(metaModels, false).removeRMDefaults(result); + new DefaultRmStructureRemover(metaModelProvider, false).removeRMDefaults(result); result.setDifferential(true); return result; diff --git a/tools/src/main/java/com/nedap/archie/diff/LCSOrderingDiff.java b/tools/src/main/java/com/nedap/archie/diff/LCSOrderingDiff.java index da4d597db..a3984092e 100644 --- a/tools/src/main/java/com/nedap/archie/diff/LCSOrderingDiff.java +++ b/tools/src/main/java/com/nedap/archie/diff/LCSOrderingDiff.java @@ -3,7 +3,7 @@ import com.nedap.archie.aom.*; import com.nedap.archie.aom.utils.AOMUtils; import com.nedap.archie.aom.utils.CodeRedefinitionStatus; -import com.nedap.archie.rminfo.MetaModels; +import com.nedap.archie.rminfo.MetaModel; import java.util.LinkedHashMap; import java.util.List; @@ -18,10 +18,10 @@ */ public class LCSOrderingDiff { - private final MetaModels metaModels; + private final MetaModel metaModel; - LCSOrderingDiff(MetaModels metaModels) { - this.metaModels = metaModels; + LCSOrderingDiff(MetaModel metaModel) { + this.metaModel = metaModel; } public void addSiblingOrder(Archetype result, Archetype flatChild, Archetype flatParent) { @@ -68,11 +68,11 @@ public void addSiblingOrder(CComplexObject result, CComplexObject flatChild, CCo //descend into children first addSiblingOrder(resultAttribute, flatChildAttribute, parentAttribute); - if(!metaModels.isMultiple(parentAttribute.getParent().getRmTypeName(), parentAttribute.getRmAttributeName())){ + if(!metaModel.isMultiple(parentAttribute.getParent().getRmTypeName(), parentAttribute.getRmAttributeName())){ continue; } - if(!metaModels.isOrdered(parentAttribute.getParent().getRmTypeName(), parentAttribute.getRmAttributeName())){ + if(!metaModel.isOrdered(parentAttribute.getParent().getRmTypeName(), parentAttribute.getRmAttributeName())){ continue; } diff --git a/tools/src/main/java/com/nedap/archie/flattener/CAttributeFlattener.java b/tools/src/main/java/com/nedap/archie/flattener/CAttributeFlattener.java index 916867d54..c37c6c4e4 100644 --- a/tools/src/main/java/com/nedap/archie/flattener/CAttributeFlattener.java +++ b/tools/src/main/java/com/nedap/archie/flattener/CAttributeFlattener.java @@ -315,7 +315,7 @@ private boolean shouldRemoveParent(CObject specializedChildCObject, CObject matc private boolean shouldReplaceSpecializedParent(CObject parent, List differentialNodes) { - MultiplicityInterval occurrences = parent.effectiveOccurrences(flattener.getMetaModels()::referenceModelPropMultiplicity); + MultiplicityInterval occurrences = parent.effectiveOccurrences(flattener.getMetaModel()::referenceModelPropMultiplicity); //isSingle/isMultiple is tricky and not doable just in the parser. Don't use those if(isSingle(parent.getParent())) { return true; @@ -332,9 +332,9 @@ private boolean shouldReplaceSpecializedParent(CObject parent, List dif //in the rm, data maps to an ITEM_STRUCTURE that does not have the attribute items. //in the parent archetype, that is then an ITEM_TREE. We need to use ITEM_TREE here, which is what this code accomplishes. if(parent.getParent() == null || parent.getParent().getParent() == null) { - effectiveOccurrences = differentialNodes.get(0).effectiveOccurrences(flattener.getMetaModels()::referenceModelPropMultiplicity); + effectiveOccurrences = differentialNodes.get(0).effectiveOccurrences(flattener.getMetaModel()::referenceModelPropMultiplicity); } else { - effectiveOccurrences = differentialNodes.get(0).effectiveOccurrences((s, s2) -> flattener.getMetaModels().referenceModelPropMultiplicity( + effectiveOccurrences = differentialNodes.get(0).effectiveOccurrences((s, s2) -> flattener.getMetaModel().referenceModelPropMultiplicity( parent.getParent().getParent().getRmTypeName(), parent.getParent().getRmAttributeName())); } if(effectiveOccurrences != null && effectiveOccurrences.upperIsOne()) { @@ -347,7 +347,7 @@ private boolean shouldReplaceSpecializedParent(CObject parent, List dif private boolean isSingle(CAttribute attribute) { if(attribute != null && attribute.getParent() != null && attribute.getDifferentialPath() == null) { - return !flattener.getMetaModels().isMultiple(attribute.getParent().getRmTypeName(), attribute.getRmAttributeName()); + return !flattener.getMetaModel().isMultiple(attribute.getParent().getRmTypeName(), attribute.getRmAttributeName()); } return false; } diff --git a/tools/src/main/java/com/nedap/archie/flattener/Flattener.java b/tools/src/main/java/com/nedap/archie/flattener/Flattener.java index 8f57246d0..7b56e59f3 100644 --- a/tools/src/main/java/com/nedap/archie/flattener/Flattener.java +++ b/tools/src/main/java/com/nedap/archie/flattener/Flattener.java @@ -3,9 +3,7 @@ import com.nedap.archie.adlparser.modelconstraints.ReflectionConstraintImposer; import com.nedap.archie.aom.*; import com.nedap.archie.aom.utils.ArchetypeParsePostProcessor; -import com.nedap.archie.rminfo.MetaModels; -import com.nedap.archie.rminfo.ReferenceModels; -import org.openehr.bmm.v2.validation.BmmRepository; +import com.nedap.archie.rminfo.*; import java.util.ArrayList; import java.util.Collections; @@ -22,10 +20,12 @@ */ public class Flattener implements IAttributeFlattenerSupport { - private final MetaModels metaModels; + private final MetaModelProvider metaModelProvider; //to be able to store Template Overlays transparently during flattening private OverridingArchetypeRepository repository; + private MetaModel metaModel; + private Archetype parent; private Archetype child; @@ -43,20 +43,32 @@ public class Flattener implements IAttributeFlattenerSupport { public Flattener(ArchetypeRepository repository, ReferenceModels models) { - this.repository = new OverridingArchetypeRepository(repository); - this.metaModels = new MetaModels(models, (BmmRepository) null); - config = FlattenerConfiguration.forFlattened(); + this(repository, new SimpleMetaModelProvider(models, null)); } + /** + * @deprecated Use {@link #Flattener(ArchetypeRepository, MetaModelProvider)} instead. + */ + @Deprecated public Flattener(ArchetypeRepository repository, MetaModels models) { - this.repository = new OverridingArchetypeRepository(repository); - this.metaModels = models; - config = FlattenerConfiguration.forFlattened(); + this(repository, (MetaModelProvider) models); + } + + public Flattener(ArchetypeRepository repository, MetaModelProvider metaModelProvider) { + this(repository, metaModelProvider, FlattenerConfiguration.forFlattened()); } + /** + * @deprecated Use {@link #Flattener(ArchetypeRepository, MetaModelProvider, FlattenerConfiguration)} instead. + */ + @Deprecated public Flattener(ArchetypeRepository repository, MetaModels models, FlattenerConfiguration configuration) { + this(repository, (MetaModelProvider) models, configuration); + } + + public Flattener(ArchetypeRepository repository, MetaModelProvider metaModelProvider, FlattenerConfiguration configuration) { this.repository = new OverridingArchetypeRepository(repository); - this.metaModels = models; + this.metaModelProvider = metaModelProvider; this.config = configuration.clone(); } @@ -106,7 +118,7 @@ public Archetype flatten(Archetype toFlatten) { throw new IllegalStateException("You've used this flattener before - single use instance, please create a new one!"); } - metaModels.selectModel(toFlatten); + metaModel = metaModelProvider.selectAndGetMetaModel(toFlatten); //validate that we can legally flatten first String parentId = toFlatten.getParentArchetypeId(); @@ -234,7 +246,7 @@ public Archetype flatten(Archetype toFlatten) { ArchetypeParsePostProcessor.fixArchetype(result); //set the single/multiple attributes correctly - new ReflectionConstraintImposer(metaModels.getSelectedModel()) + new ReflectionConstraintImposer(metaModel) .setSingleOrMultiple(result.getDefinition()); return result; @@ -415,7 +427,7 @@ private void flattenCComplexObject(CComplexObject newObject, CComplexObject spec * @return */ protected Flattener getNewFlattenerForParent() { - Flattener result = new Flattener(repository, metaModels, config) + Flattener result = new Flattener(repository, metaModelProvider, config) .createOperationalTemplate(false); //do not create operational template except at the end. if(config.isRemoveZeroOccurrencesInParents()) { //remove all zero occurrences objects EXCEPT in the top level archetype @@ -433,7 +445,7 @@ protected Flattener getNewFlattenerForParent() { * @return */ protected Flattener getNewFlattener() { - return new Flattener(repository, metaModels, config); + return new Flattener(repository, metaModelProvider, config); } private Flattener useComplexObjectForArchetypeSlotReplacement(boolean useComplexObjectForArchetypeSlotReplacement) { @@ -446,8 +458,18 @@ public boolean isUseComplexObjectForArchetypeSlotReplacement() { } @Override + public MetaModel getMetaModel() { + return metaModel; + } + + @Override + @Deprecated public MetaModels getMetaModels() { - return metaModels; + if(metaModelProvider instanceof MetaModels) { + return (MetaModels) metaModelProvider; + } else { + throw new IllegalStateException("MetaModels not available"); + } } @Override diff --git a/tools/src/main/java/com/nedap/archie/flattener/FullArchetypeRepository.java b/tools/src/main/java/com/nedap/archie/flattener/FullArchetypeRepository.java index 70c020d81..09b8da517 100644 --- a/tools/src/main/java/com/nedap/archie/flattener/FullArchetypeRepository.java +++ b/tools/src/main/java/com/nedap/archie/flattener/FullArchetypeRepository.java @@ -5,6 +5,7 @@ import com.nedap.archie.archetypevalidator.ArchetypeValidationSettings; import com.nedap.archie.archetypevalidator.ArchetypeValidator; import com.nedap.archie.archetypevalidator.ValidationResult; +import com.nedap.archie.rminfo.MetaModelProvider; import com.nedap.archie.rminfo.MetaModels; import com.nedap.archie.rminfo.ReferenceModels; @@ -40,18 +41,26 @@ default void compile(ReferenceModels models) { compile(validator); } + /** + * @deprecated Use {@link #compile(MetaModelProvider)} instead. + */ + @Deprecated default void compile(MetaModels models) { - ArchetypeValidator validator = new ArchetypeValidator(models); + compile((MetaModelProvider) models); + } + + default void compile(MetaModelProvider metaModelProvider) { + ArchetypeValidator validator = new ArchetypeValidator(metaModelProvider); compile(validator); } /** * validate the validation result if necessary, and return either the newly validated one or * the existing validation result - * @param models + * @param metaModelProvider * @return */ - default ValidationResult compileAndRetrieveValidationResult(String archetypeId, MetaModels models) { + default ValidationResult compileAndRetrieveValidationResult(String archetypeId, MetaModelProvider metaModelProvider) { Archetype archetype = getArchetype(archetypeId); if(archetype == null) { return null; @@ -63,10 +72,21 @@ default ValidationResult compileAndRetrieveValidationResult(String archetypeId, return validationResult; } - ArchetypeValidator validator = new ArchetypeValidator(models); + ArchetypeValidator validator = new ArchetypeValidator(metaModelProvider); return validator.validate(archetype, this); } + /** + * validate the validation result if necessary, and return either the newly validated one or + * the existing validation result + * @param models + * @return + */ + @Deprecated + default ValidationResult compileAndRetrieveValidationResult(String archetypeId, MetaModels models) { + return compileAndRetrieveValidationResult(archetypeId, (MetaModelProvider) models); + } + /** * validate the validation result if necessary, and return either the newly validated one or * the existing validation result diff --git a/tools/src/main/java/com/nedap/archie/flattener/IAttributeFlattenerSupport.java b/tools/src/main/java/com/nedap/archie/flattener/IAttributeFlattenerSupport.java index d9b6db9f0..1c6219649 100644 --- a/tools/src/main/java/com/nedap/archie/flattener/IAttributeFlattenerSupport.java +++ b/tools/src/main/java/com/nedap/archie/flattener/IAttributeFlattenerSupport.java @@ -2,12 +2,20 @@ import com.nedap.archie.aom.CAttribute; import com.nedap.archie.aom.CObject; +import com.nedap.archie.rminfo.MetaModel; import com.nedap.archie.rminfo.MetaModels; public interface IAttributeFlattenerSupport { CObject createSpecializeCObject(CAttribute attribute, CObject parent, CObject specialized); + + /** + * @deprecated Use {@link #getMetaModel()} instead. + */ + @Deprecated public MetaModels getMetaModels(); + public MetaModel getMetaModel(); + public FlattenerConfiguration getConfig(); } diff --git a/tools/src/main/java/com/nedap/archie/flattener/OperationalTemplateCreator.java b/tools/src/main/java/com/nedap/archie/flattener/OperationalTemplateCreator.java index 92d053cd3..76e292152 100644 --- a/tools/src/main/java/com/nedap/archie/flattener/OperationalTemplateCreator.java +++ b/tools/src/main/java/com/nedap/archie/flattener/OperationalTemplateCreator.java @@ -99,7 +99,7 @@ public void fillEmptyOccurrences(Archetype archetype) { CObject object = workList.pop(); if( (object instanceof CComplexObject || object instanceof ArchetypeSlot || object instanceof CComplexObjectProxy) && object.getOccurrences() == null) { - object.setOccurrences(object.effectiveOccurrences(flattener.getMetaModels()::referenceModelPropMultiplicity)); + object.setOccurrences(object.effectiveOccurrences(flattener.getMetaModel()::referenceModelPropMultiplicity)); } for (CAttribute attribute : object.getAttributes()) { diff --git a/tools/src/main/java/com/nedap/archie/json/flat/FlatJsonExampleInstanceGenerator.java b/tools/src/main/java/com/nedap/archie/json/flat/FlatJsonExampleInstanceGenerator.java index 0fd9e231e..ed090d616 100644 --- a/tools/src/main/java/com/nedap/archie/json/flat/FlatJsonExampleInstanceGenerator.java +++ b/tools/src/main/java/com/nedap/archie/json/flat/FlatJsonExampleInstanceGenerator.java @@ -5,6 +5,8 @@ import com.nedap.archie.aom.OperationalTemplate; import com.nedap.archie.base.OpenEHRBase; import com.nedap.archie.creation.ExampleJsonInstanceGenerator; +import com.nedap.archie.rminfo.MetaModel; +import com.nedap.archie.rminfo.MetaModelProvider; import com.nedap.archie.rminfo.MetaModels; import java.util.Map; @@ -21,26 +23,40 @@ public class FlatJsonExampleInstanceGenerator { * @return a flat json as generated by the FlatJsonGenerator, to be serialized with an objectmapper * @throws JsonProcessingException in case the ExampleJsonInstanceGenerator generates json that the objectmapper cannot process * @throws DuplicateKeyException in case the FlatJsonGenerator generates incorrect data for this OperationalTemplate + * @deprecated Use {@link #generateExample(OperationalTemplate, MetaModelProvider, String, FlatJsonFormatConfiguration)} instead. */ + @Deprecated public Map generateExample(OperationalTemplate template, MetaModels metaModels, String language, FlatJsonFormatConfiguration jsonFormatConfiguration) throws JsonProcessingException, DuplicateKeyException { - metaModels.selectModel(template); - if(metaModels.getSelectedModel() == null) { - throw new IllegalArgumentException("Cannot find MetaModel for archetype"); - } - if(metaModels.getSelectedModelInfoLookup() == null) { + return generateExample(template, (MetaModelProvider) metaModels, language, jsonFormatConfiguration); + } + + /** + * Generate a flat JSON example instance for the given OperationalTemplate. + * + * @param template the template for which to generate the example + * @param metaModelProvider the metamodels to use. Must contain an actual RM ModelInfoLookup and a JSON Object Mapper + * @param language the language to generate the example in + * @param jsonFormatConfiguration the configuratin of the flat format + * @return a flat json as generated by the FlatJsonGenerator, to be serialized with an objectmapper + * @throws JsonProcessingException in case the ExampleJsonInstanceGenerator generates json that the objectmapper cannot process + * @throws DuplicateKeyException in case the FlatJsonGenerator generates incorrect data for this OperationalTemplate + */ + public Map generateExample(OperationalTemplate template, MetaModelProvider metaModelProvider, String language, FlatJsonFormatConfiguration jsonFormatConfiguration) throws JsonProcessingException, DuplicateKeyException { + MetaModel metaModel = metaModelProvider.selectAndGetMetaModel(template); + if(metaModel.getModelInfoLookup() == null) { throw new IllegalArgumentException("Cannot find ModelInfoLookup for archetype"); } - if(metaModels.getSelectedModel().getJsonObjectMapper() == null) { + if(metaModel.getJsonObjectMapper() == null) { throw new IllegalArgumentException("Cannot find JSON Object mapper in selected metamodel"); } - ExampleJsonInstanceGenerator exampleJsonInstanceGenerator = new ExampleJsonInstanceGenerator(metaModels, language); + ExampleJsonInstanceGenerator exampleJsonInstanceGenerator = new ExampleJsonInstanceGenerator(metaModelProvider, language); exampleJsonInstanceGenerator.setTypePropertyName("_type"); Map generatedExample = exampleJsonInstanceGenerator.generate(template); - ObjectMapper objectMapper = metaModels.getSelectedModel().getJsonObjectMapper(); + ObjectMapper objectMapper = metaModel.getJsonObjectMapper(); String jsonRmObject = objectMapper.writeValueAsString(generatedExample); OpenEHRBase openEHRBase = objectMapper.readValue(jsonRmObject, OpenEHRBase.class); - return new FlatJsonGenerator(metaModels.getSelectedModelInfoLookup(), jsonFormatConfiguration).buildPathsAndValues(openEHRBase, template, "en"); + return new FlatJsonGenerator(metaModel.getModelInfoLookup(), jsonFormatConfiguration).buildPathsAndValues(openEHRBase, template, "en"); } diff --git a/tools/src/test/java/com/nedap/archie/adl14/ADL14DefaultOccurrencesConversionTest.java b/tools/src/test/java/com/nedap/archie/adl14/ADL14DefaultOccurrencesConversionTest.java index 3d85afb28..908cfb46d 100644 --- a/tools/src/test/java/com/nedap/archie/adl14/ADL14DefaultOccurrencesConversionTest.java +++ b/tools/src/test/java/com/nedap/archie/adl14/ADL14DefaultOccurrencesConversionTest.java @@ -19,10 +19,10 @@ public class ADL14DefaultOccurrencesConversionTest { @Test public void testDefaultOccurrencesConversion() throws Exception { ADL14ConversionConfiguration conversionConfiguration = ConversionConfigForTest.getConfig(); - ADL14Converter converter = new ADL14Converter(BuiltinReferenceModels.getMetaModels(), conversionConfiguration); + ADL14Converter converter = new ADL14Converter(BuiltinReferenceModels.getMetaModelProvider(), conversionConfiguration); //apply the first conversion and store the log. It has created an at code to bind to [openehr::124], used in a DV_QUANTITY.property try (InputStream stream = getClass().getResourceAsStream("/adl14/entry/evaluation/openEHR-EHR-EVALUATION.goal.v1.adl")) { - ADL14Parser parser = new ADL14Parser(BuiltinReferenceModels.getMetaModels()); + ADL14Parser parser = new ADL14Parser(BuiltinReferenceModels.getMetaModelProvider()); Archetype parsed = parser.parse(stream, conversionConfiguration); ADL2ConversionResultList result = converter.convert(Lists.newArrayList(parsed)); System.out.println(ADLArchetypeSerializer.serialize(result.getConversionResults().get(0).getArchetype())); diff --git a/tools/src/test/java/com/nedap/archie/adl14/ADL14ExternalTerminologyConversionTest.java b/tools/src/test/java/com/nedap/archie/adl14/ADL14ExternalTerminologyConversionTest.java index 13ebcb689..4afdae905 100644 --- a/tools/src/test/java/com/nedap/archie/adl14/ADL14ExternalTerminologyConversionTest.java +++ b/tools/src/test/java/com/nedap/archie/adl14/ADL14ExternalTerminologyConversionTest.java @@ -22,11 +22,11 @@ public class ADL14ExternalTerminologyConversionTest { @Test public void terminologyBindingsConverted() throws IOException, ADLParseException { ADL14ConversionConfiguration conversionConfiguration = ConversionConfigForTest.getConfig(); - ADL14Converter converter = new ADL14Converter(BuiltinReferenceModels.getMetaModels(), conversionConfiguration); + ADL14Converter converter = new ADL14Converter(BuiltinReferenceModels.getMetaModelProvider(), conversionConfiguration); //apply the first conversion and store the log. It has created an at code to bind to [openehr::124], used in a DV_QUANTITY.property try(InputStream stream = getClass().getResourceAsStream("/adl14/openEHR-EHR-CLUSTER.value_binding.v1.0.0.adl")) { ADL2ConversionResultList result = converter.convert( - Lists.newArrayList(new ADL14Parser(BuiltinReferenceModels.getMetaModels()).parse(stream, conversionConfiguration))); + Lists.newArrayList(new ADL14Parser(BuiltinReferenceModels.getMetaModelProvider()).parse(stream, conversionConfiguration))); Archetype converted = result.getConversionResults().get(0).getArchetype(); CTerminologyCode termCodeConstraint = converted.itemAtPath("/items/value/property[1]"); String atCode = termCodeConstraint.getConstraint().get(0); @@ -43,10 +43,10 @@ public void terminologyBindingsConverted() throws IOException, ADLParseException @Test public void twoTermbindingsInOneConstraint() throws Exception { ADL14ConversionConfiguration conversionConfiguration = ConversionConfigForTest.getConfig(); - ADL14Converter converter = new ADL14Converter(BuiltinReferenceModels.getMetaModels(), conversionConfiguration); + ADL14Converter converter = new ADL14Converter(BuiltinReferenceModels.getMetaModelProvider(), conversionConfiguration); //apply the first conversion and store the log. It has created an at code to bind to [openehr::124], used in a DV_QUANTITY.property try(InputStream stream = getClass().getResourceAsStream("openEHR-EHR-CLUSTER.termbinding.v1.adl")) { - ADL14Parser parser = new ADL14Parser(BuiltinReferenceModels.getMetaModels()); + ADL14Parser parser = new ADL14Parser(BuiltinReferenceModels.getMetaModelProvider()); ADL2ConversionResultList result = converter.convert( Lists.newArrayList(parser.parse(stream, conversionConfiguration))); assertFalse(parser.getErrors().hasErrors()); diff --git a/tools/src/test/java/com/nedap/archie/adl14/ADL14InternalTerminologyTest.java b/tools/src/test/java/com/nedap/archie/adl14/ADL14InternalTerminologyTest.java index 3a9ac0951..b4a29b73b 100644 --- a/tools/src/test/java/com/nedap/archie/adl14/ADL14InternalTerminologyTest.java +++ b/tools/src/test/java/com/nedap/archie/adl14/ADL14InternalTerminologyTest.java @@ -19,11 +19,11 @@ public class ADL14InternalTerminologyTest { @Test public void internalTerminologyRemoved() throws IOException, ADLParseException { ADL14ConversionConfiguration conversionConfiguration = ConversionConfigForTest.getConfig(); - ADL14Converter converter = new ADL14Converter(BuiltinReferenceModels.getMetaModels(), conversionConfiguration); + ADL14Converter converter = new ADL14Converter(BuiltinReferenceModels.getMetaModelProvider(), conversionConfiguration); try(InputStream stream = getClass().getResourceAsStream("/adl14/openEHR-EHR-OBSERVATION.internal_terminology_test.v0.adl")) { ADL2ConversionResultList result = converter.convert( - Lists.newArrayList(new ADL14Parser(BuiltinReferenceModels.getMetaModels()).parse(stream, conversionConfiguration))); + Lists.newArrayList(new ADL14Parser(BuiltinReferenceModels.getMetaModelProvider()).parse(stream, conversionConfiguration))); Archetype converted = result.getConversionResults().get(0).getArchetype(); // A terminology code is unnecessary if: // - The text.length < 19 diff --git a/tools/src/test/java/com/nedap/archie/adl14/ADL14TerminologyConversionTest.java b/tools/src/test/java/com/nedap/archie/adl14/ADL14TerminologyConversionTest.java index 99cf29b0d..9dc1ee02d 100644 --- a/tools/src/test/java/com/nedap/archie/adl14/ADL14TerminologyConversionTest.java +++ b/tools/src/test/java/com/nedap/archie/adl14/ADL14TerminologyConversionTest.java @@ -16,10 +16,10 @@ public class ADL14TerminologyConversionTest { @Test public void twoTermbindingsInOneConstraint() throws Exception { ADL14ConversionConfiguration conversionConfiguration = ConversionConfigForTest.getConfig(); - ADL14Converter converter = new ADL14Converter(BuiltinReferenceModels.getMetaModels(), conversionConfiguration); + ADL14Converter converter = new ADL14Converter(BuiltinReferenceModels.getMetaModelProvider(), conversionConfiguration); //apply the first conversion and store the log. It has created an at code to bind to [openehr::124], used in a DV_QUANTITY.property try(InputStream stream = getClass().getResourceAsStream("openEHR-EHR-CLUSTER.termbinding.v1.adl")) { - ADL14Parser parser = new ADL14Parser(BuiltinReferenceModels.getMetaModels()); + ADL14Parser parser = new ADL14Parser(BuiltinReferenceModels.getMetaModelProvider()); ADL2ConversionResultList result = converter.convert( Lists.newArrayList(parser.parse(stream, conversionConfiguration))); Archetype converted = result.getConversionResults().get(0).getArchetype(); diff --git a/tools/src/test/java/com/nedap/archie/adl14/ArchetypeSlotConversionTest.java b/tools/src/test/java/com/nedap/archie/adl14/ArchetypeSlotConversionTest.java index beecbad18..2f7dd51c0 100644 --- a/tools/src/test/java/com/nedap/archie/adl14/ArchetypeSlotConversionTest.java +++ b/tools/src/test/java/com/nedap/archie/adl14/ArchetypeSlotConversionTest.java @@ -20,12 +20,12 @@ public class ArchetypeSlotConversionTest { @Test public void testSlotConversion() throws Exception { ADL14ConversionConfiguration conversionConfiguration = ConversionConfigForTest.getConfig(); - ADL14Converter converter = new ADL14Converter(BuiltinReferenceModels.getMetaModels(), conversionConfiguration); + ADL14Converter converter = new ADL14Converter(BuiltinReferenceModels.getMetaModelProvider(), conversionConfiguration); ADL2ConversionRunLog log = null; try(InputStream stream = getClass().getResourceAsStream("/com/nedap/archie/adl14/openEHR-EHR-OBSERVATION.respiration.v1.adl")) { ADL2ConversionResultList result = converter.convert( - Lists.newArrayList(new ADL14Parser(BuiltinReferenceModels.getMetaModels()).parse(stream, conversionConfiguration))); + Lists.newArrayList(new ADL14Parser(BuiltinReferenceModels.getMetaModelProvider()).parse(stream, conversionConfiguration))); Archetype archetype = result.getConversionResults().get(0).getArchetype(); ArchetypeSlot slot = archetype.itemAtPath("/data/events[1]/state[id23]/items[id56]"); String includesPattern = getPattern(slot.getIncludes().get(0)); diff --git a/tools/src/test/java/com/nedap/archie/adl14/AssumedValueConversionTest.java b/tools/src/test/java/com/nedap/archie/adl14/AssumedValueConversionTest.java index df7d572db..6d1b81612 100644 --- a/tools/src/test/java/com/nedap/archie/adl14/AssumedValueConversionTest.java +++ b/tools/src/test/java/com/nedap/archie/adl14/AssumedValueConversionTest.java @@ -18,11 +18,11 @@ public class AssumedValueConversionTest { @Test public void testAssumedValueConversion() throws Exception { ADL14ConversionConfiguration conversionConfiguration = ConversionConfigForTest.getConfig(); - ADL14Converter converter = new ADL14Converter(BuiltinReferenceModels.getMetaModels(), conversionConfiguration); + ADL14Converter converter = new ADL14Converter(BuiltinReferenceModels.getMetaModelProvider(), conversionConfiguration); Archetype adl14archetype; try(InputStream stream = getClass().getResourceAsStream("openEHR-EHR-OBSERVATION.height.v2.adl")) { - adl14archetype = new ADL14Parser(BuiltinReferenceModels.getMetaModels()).parse(stream, conversionConfiguration); + adl14archetype = new ADL14Parser(BuiltinReferenceModels.getMetaModelProvider()).parse(stream, conversionConfiguration); } ADL2ConversionResultList result = converter.convert( @@ -35,7 +35,7 @@ public void testAssumedValueConversion() throws Exception { assertNull(cTerminologyCode.getAssumedValue().getTerminologyId()); assertEquals("at17", cTerminologyCode.getAssumedValue().getCodeString()); - ValidationResult validationResult = new ArchetypeValidator(BuiltinReferenceModels.getMetaModels()).validate(archetype); + ValidationResult validationResult = new ArchetypeValidator(BuiltinReferenceModels.getMetaModelProvider()).validate(archetype); assertTrue(validationResult.toString(), validationResult.passes()); } diff --git a/tools/src/test/java/com/nedap/archie/adl14/ConversionConfigurationTest.java b/tools/src/test/java/com/nedap/archie/adl14/ConversionConfigurationTest.java index a2144d322..913ba6e26 100644 --- a/tools/src/test/java/com/nedap/archie/adl14/ConversionConfigurationTest.java +++ b/tools/src/test/java/com/nedap/archie/adl14/ConversionConfigurationTest.java @@ -15,17 +15,17 @@ public class ConversionConfigurationTest { public void testRmRelease() throws Exception { ADL14ConversionConfiguration conversionConfiguration = ConversionConfigForTest.getConfig(); - ADL14Converter converter = new ADL14Converter(BuiltinReferenceModels.getMetaModels(), conversionConfiguration); + ADL14Converter converter = new ADL14Converter(BuiltinReferenceModels.getMetaModelProvider(), conversionConfiguration); try(InputStream stream = getClass().getResourceAsStream("openehr-EHR-COMPOSITION.review.v1.adl")) { - Archetype adl14 = new ADL14Parser(BuiltinReferenceModels.getMetaModels()).parse(stream, conversionConfiguration); + Archetype adl14 = new ADL14Parser(BuiltinReferenceModels.getMetaModelProvider()).parse(stream, conversionConfiguration); ADL2ConversionResultList result = converter.convert(Lists.newArrayList(adl14)); assertEquals("1.1.0", result.getConversionResults().get(0).getArchetype().getRmRelease()); conversionConfiguration.setRmRelease("1.0.4"); - converter = new ADL14Converter(BuiltinReferenceModels.getMetaModels(), conversionConfiguration); + converter = new ADL14Converter(BuiltinReferenceModels.getMetaModelProvider(), conversionConfiguration); result = converter.convert(Lists.newArrayList(adl14)); assertEquals("1.0.4", result.getConversionResults().get(0).getArchetype().getRmRelease()); diff --git a/tools/src/test/java/com/nedap/archie/adl14/DvScaleConversionTest.java b/tools/src/test/java/com/nedap/archie/adl14/DvScaleConversionTest.java index e58ad4e4c..4dbc714a1 100644 --- a/tools/src/test/java/com/nedap/archie/adl14/DvScaleConversionTest.java +++ b/tools/src/test/java/com/nedap/archie/adl14/DvScaleConversionTest.java @@ -18,11 +18,11 @@ public class DvScaleConversionTest { public void testDvScale() throws Exception { ADL14ConversionConfiguration conversionConfiguration = ConversionConfigForTest.getConfig(); - ADL14Converter converter = new ADL14Converter(BuiltinReferenceModels.getMetaModels(), conversionConfiguration); + ADL14Converter converter = new ADL14Converter(BuiltinReferenceModels.getMetaModelProvider(), conversionConfiguration); try(InputStream stream = getClass().getResourceAsStream("openEHR-EHR-CLUSTER.ordinalandscale.v0.adl")) { - ADL14Parser adl14Parser = new ADL14Parser(BuiltinReferenceModels.getMetaModels()); + ADL14Parser adl14Parser = new ADL14Parser(BuiltinReferenceModels.getMetaModelProvider()); Archetype adl14 = adl14Parser.parse(stream, conversionConfiguration); assertFalse(adl14Parser.getErrors().hasErrors()); ADL2ConversionResultList result = converter.convert(Lists.newArrayList(adl14)); diff --git a/tools/src/test/java/com/nedap/archie/adl14/LargeSetOfADL14sTest.java b/tools/src/test/java/com/nedap/archie/adl14/LargeSetOfADL14sTest.java index c407cf774..5d6ba295f 100644 --- a/tools/src/test/java/com/nedap/archie/adl14/LargeSetOfADL14sTest.java +++ b/tools/src/test/java/com/nedap/archie/adl14/LargeSetOfADL14sTest.java @@ -54,14 +54,14 @@ public void parseUrn() { @Test public void testRiskFamilyhistory() throws Exception { - ADL14Parser parser = new ADL14Parser(BuiltinReferenceModels.getMetaModels()); + ADL14Parser parser = new ADL14Parser(BuiltinReferenceModels.getMetaModelProvider()); Archetype riskParent = parser.parse(getClass().getResourceAsStream("/adl14/risk_parent.adl"), conversionConfiguration); Archetype riskFamilyHistory = parser.parse(getClass().getResourceAsStream("/adl14/risk_history.adl"), conversionConfiguration); List archetypes = Arrays.asList(riskParent, riskFamilyHistory); - ADL2ConversionResultList converted = new ADL14Converter(BuiltinReferenceModels.getMetaModels(), conversionConfiguration) + ADL2ConversionResultList converted = new ADL14Converter(BuiltinReferenceModels.getMetaModelProvider(), conversionConfiguration) .convert(archetypes); for(ADL2ConversionResult conversionResult:converted.getConversionResults()) { @@ -81,7 +81,7 @@ public void testRiskFamilyhistory() throws Exception { adl2Repository.addArchetype(conversionResult.getArchetype()); } } - adl2Repository.compile(BuiltinReferenceModels.getMetaModels()); + adl2Repository.compile(BuiltinReferenceModels.getMetaModelProvider()); for(ValidationResult validationResult:adl2Repository.getAllValidationResults()) { if(!validationResult.passes()) { @@ -109,7 +109,7 @@ public void parseLots() throws Exception { } } - ADL2ConversionResultList converted = new ADL14Converter(BuiltinReferenceModels.getMetaModels(), conversionConfiguration) + ADL2ConversionResultList converted = new ADL14Converter(BuiltinReferenceModels.getMetaModelProvider(), conversionConfiguration) .convert(archetypes); for(ADL2ConversionResult result:converted.getConversionResults()) { if(result.getArchetype() != null) {// && result.getArchetype().getParentArchetypeId() != null) { @@ -156,7 +156,7 @@ public void parseLots() throws Exception { adl2Repository.addArchetype(conversionResult.getArchetype()); } } - adl2Repository.compile(BuiltinReferenceModels.getMetaModels()); + adl2Repository.compile(BuiltinReferenceModels.getMetaModelProvider()); int passingValidations = 0; for(ValidationResult validationResult:adl2Repository.getAllValidationResults()) { if(validationResult.passes()) { @@ -189,7 +189,7 @@ public void parseLots() throws Exception { private Archetype parse(Map exceptions, Map parseErrors, String file) { try (InputStream stream = getClass().getResourceAsStream("/" + file)) { logger.info("trying to parse " + file); - ADL14Parser parser = new ADL14Parser(BuiltinReferenceModels.getMetaModels()); + ADL14Parser parser = new ADL14Parser(BuiltinReferenceModels.getMetaModelProvider()); Archetype archetype = parser.parse(stream, conversionConfiguration); //logger.info(JacksonUtil.getObjectMapper().writeValueAsString(conversionResult.getConversionLog())); diff --git a/tools/src/test/java/com/nedap/archie/adl14/PreviousLogConversionTest.java b/tools/src/test/java/com/nedap/archie/adl14/PreviousLogConversionTest.java index 19f865a0c..950a7ecf2 100644 --- a/tools/src/test/java/com/nedap/archie/adl14/PreviousLogConversionTest.java +++ b/tools/src/test/java/com/nedap/archie/adl14/PreviousLogConversionTest.java @@ -25,12 +25,12 @@ public class PreviousLogConversionTest { public void applyConsistentConversion() throws Exception { ADL14ConversionConfiguration conversionConfiguration = ConversionConfigForTest.getConfig(); - ADL14Converter converter = new ADL14Converter(BuiltinReferenceModels.getMetaModels(), conversionConfiguration); + ADL14Converter converter = new ADL14Converter(BuiltinReferenceModels.getMetaModelProvider(), conversionConfiguration); ADL2ConversionRunLog log = null; try(InputStream stream = getClass().getResourceAsStream("openehr-EHR-COMPOSITION.review.v1.adl")) { ADL2ConversionResultList result = converter.convert( - Lists.newArrayList(new ADL14Parser(BuiltinReferenceModels.getMetaModels()).parse(stream, conversionConfiguration))); + Lists.newArrayList(new ADL14Parser(BuiltinReferenceModels.getMetaModelProvider()).parse(stream, conversionConfiguration))); log = result.getConversionLog(); } @@ -38,7 +38,7 @@ public void applyConsistentConversion() throws Exception { try(InputStream stream = getClass().getResourceAsStream("openEHR-EHR-COMPOSITION.review.v1.modified.adl")) { ADL2ConversionResultList result = converter.convert( - Lists.newArrayList(new ADL14Parser(BuiltinReferenceModels.getMetaModels()).parse(stream, conversionConfiguration)), + Lists.newArrayList(new ADL14Parser(BuiltinReferenceModels.getMetaModelProvider()).parse(stream, conversionConfiguration)), log); CAttribute attribute = result.getConversionResults().get(0).getArchetype().itemAtPath("/category"); assertEquals(2, attribute.getChildren().size()); @@ -55,15 +55,15 @@ public void applyConsistentConversion() throws Exception { @Test public void testValueSet() throws Exception { ADL14ConversionConfiguration conversionConfiguration = ConversionConfigForTest.getConfig(); - ADL14Converter converter = new ADL14Converter(BuiltinReferenceModels.getMetaModels(), conversionConfiguration); + ADL14Converter converter = new ADL14Converter(BuiltinReferenceModels.getMetaModelProvider(), conversionConfiguration); ADL2ConversionRunLog log = null; try(InputStream stream = getClass().getResourceAsStream("openEHR-EHR-OBSERVATION.respiration.v1.adl")) { ADL2ConversionResultList result = converter.convert( - Lists.newArrayList(new ADL14Parser(BuiltinReferenceModels.getMetaModels()).parse(stream, conversionConfiguration))); + Lists.newArrayList(new ADL14Parser(BuiltinReferenceModels.getMetaModelProvider()).parse(stream, conversionConfiguration))); log = result.getConversionLog(); Archetype converted = result.getConversionResults().get(0).getArchetype(); - ValidationResult validated = new ArchetypeValidator(BuiltinReferenceModels.getMetaModels()).validate(converted); + ValidationResult validated = new ArchetypeValidator(BuiltinReferenceModels.getMetaModelProvider()).validate(converted); assertTrue(validated.toString(), validated.passes() ); assertTrue(converted.getTerminology().getTermDefinitions().get("nl").containsKey("ac9000")); assertTrue(converted.getTerminology().getTermDefinitions().get("nl").containsKey("ac9001")); @@ -75,11 +75,11 @@ public void testValueSet() throws Exception { try(InputStream stream = getClass().getResourceAsStream("openEHR-EHR-OBSERVATION.respiration.v1.adl")) { ADL2ConversionResultList result = converter.convert( - Lists.newArrayList(new ADL14Parser(BuiltinReferenceModels.getMetaModels()).parse(stream, conversionConfiguration)), + Lists.newArrayList(new ADL14Parser(BuiltinReferenceModels.getMetaModelProvider()).parse(stream, conversionConfiguration)), log); Archetype converted = result.getConversionResults().get(0).getArchetype(); - ValidationResult validated = new ArchetypeValidator(BuiltinReferenceModels.getMetaModels()).validate(converted); + ValidationResult validated = new ArchetypeValidator(BuiltinReferenceModels.getMetaModelProvider()).validate(converted); assertTrue(validated.toString(), validated.passes() ); assertTrue(converted.getTerminology().getTermDefinitions().get("nl").containsKey("ac9000")); assertTrue(converted.getTerminology().getTermDefinitions().get("nl").containsKey("ac9001")); @@ -92,16 +92,16 @@ public void testValueSet() throws Exception { @Test public void unusedValuesAreRemoved() throws Exception { ADL14ConversionConfiguration conversionConfiguration = ConversionConfigForTest.getConfig(); - ADL14Converter converter = new ADL14Converter(BuiltinReferenceModels.getMetaModels(), conversionConfiguration); + ADL14Converter converter = new ADL14Converter(BuiltinReferenceModels.getMetaModelProvider(), conversionConfiguration); ADL2ConversionRunLog log = null; String createdAtCode = null; //apply the first conversion and store the log. It has created an at code to bind to [openehr::124], used in a DV_QUANTITY.property try(InputStream stream = getClass().getResourceAsStream("/adl14/openEHR-EHR-CLUSTER.value_binding.v1.0.0.adl")) { ADL2ConversionResultList result = converter.convert( - Lists.newArrayList(new ADL14Parser(BuiltinReferenceModels.getMetaModels()).parse(stream, conversionConfiguration))); + Lists.newArrayList(new ADL14Parser(BuiltinReferenceModels.getMetaModelProvider()).parse(stream, conversionConfiguration))); log = result.getConversionLog(); Archetype converted = result.getConversionResults().get(0).getArchetype(); - ValidationResult validated = new ArchetypeValidator(BuiltinReferenceModels.getMetaModels()).validate(converted); + ValidationResult validated = new ArchetypeValidator(BuiltinReferenceModels.getMetaModelProvider()).validate(converted); assertTrue(validated.toString(), validated.passes() ); createdAtCode = log.getConversionLog("openEHR-EHR-CLUSTER.value_binding.v1").getCreatedCodes().get("[openehr::124]").getGeneratedCode(); ArchetypeTerm termDefinition = converted.getTerminology().getTermDefinition("en", createdAtCode); @@ -113,10 +113,10 @@ public void unusedValuesAreRemoved() throws Exception { //apply the first conversion. The openehr::124 term binding is gone, and should not be present in the result, but should remain in the conversion log for future readdition try(InputStream stream = getClass().getResourceAsStream("/adl14/openEHR-EHR-CLUSTER.value_binding.v1.0.1.adl")) { ADL2ConversionResultList result = converter.convert( - Lists.newArrayList(new ADL14Parser(BuiltinReferenceModels.getMetaModels()).parse(stream, conversionConfiguration)), + Lists.newArrayList(new ADL14Parser(BuiltinReferenceModels.getMetaModelProvider()).parse(stream, conversionConfiguration)), log); Archetype converted = result.getConversionResults().get(0).getArchetype(); - ValidationResult validated = new ArchetypeValidator(BuiltinReferenceModels.getMetaModels()).validate(converted); + ValidationResult validated = new ArchetypeValidator(BuiltinReferenceModels.getMetaModelProvider()).validate(converted); assertTrue(validated.toString(), validated.passes() ); ArchetypeTerm termDefinition = converted.getTerminology().getTermDefinition("en", "at9000"); @@ -141,12 +141,12 @@ public void unusedValuesAreRemoved() throws Exception { public void acceptExplicitlySetCode() throws Exception { ADL14ConversionConfiguration conversionConfiguration = ConversionConfigForTest.getConfig(); - ADL14Converter converter = new ADL14Converter(BuiltinReferenceModels.getMetaModels(), conversionConfiguration); + ADL14Converter converter = new ADL14Converter(BuiltinReferenceModels.getMetaModelProvider(), conversionConfiguration); ADL2ConversionRunLog log = null; try(InputStream stream = getClass().getResourceAsStream("openehr-EHR-COMPOSITION.review.v1.adl")) { ADL2ConversionResultList result = converter.convert( - Lists.newArrayList(new ADL14Parser(BuiltinReferenceModels.getMetaModels()).parse(stream, conversionConfiguration))); + Lists.newArrayList(new ADL14Parser(BuiltinReferenceModels.getMetaModelProvider()).parse(stream, conversionConfiguration))); log = result.getConversionLog(); } @@ -154,7 +154,7 @@ public void acceptExplicitlySetCode() throws Exception { try(InputStream stream = getClass().getResourceAsStream("openEHR-EHR-COMPOSITION.review.v1.codeadded.adl")) { ADL2ConversionResultList result = converter.convert( - Lists.newArrayList(new ADL14Parser(BuiltinReferenceModels.getMetaModels()).parse(stream, conversionConfiguration)), + Lists.newArrayList(new ADL14Parser(BuiltinReferenceModels.getMetaModelProvider()).parse(stream, conversionConfiguration)), log); CAttribute attribute = result.getConversionResults().get(0).getArchetype().itemAtPath("/category"); diff --git a/tools/src/test/java/com/nedap/archie/adlparser/AomUtilsPathFindingTest.java b/tools/src/test/java/com/nedap/archie/adlparser/AomUtilsPathFindingTest.java index 149e5b259..d7cc0f0b6 100644 --- a/tools/src/test/java/com/nedap/archie/adlparser/AomUtilsPathFindingTest.java +++ b/tools/src/test/java/com/nedap/archie/adlparser/AomUtilsPathFindingTest.java @@ -2,7 +2,7 @@ import com.nedap.archie.aom.Archetype; import com.nedap.archie.aom.utils.AOMUtils; -import com.nedap.archie.rminfo.MetaModels; +import com.nedap.archie.rminfo.MetaModel; import com.nedap.archie.testutil.TestUtil; import org.junit.Test; import org.openehr.referencemodels.BuiltinReferenceModels; @@ -15,15 +15,14 @@ public class AomUtilsPathFindingTest { @Test public void isPathInArchetypeOrRm() throws Exception{ Archetype archetype = TestUtil.parseFailOnErrors("/basic.adl"); - MetaModels metaModels = BuiltinReferenceModels.getMetaModels(); - metaModels.selectModel(archetype); + MetaModel metaModel = BuiltinReferenceModels.getMetaModelProvider().getMetaModel(archetype); //AOM path - assertTrue(AOMUtils.isPathInArchetypeOrRm(metaModels.getSelectedModel(), "/context[id11]", archetype)); + assertTrue(AOMUtils.isPathInArchetypeOrRm(metaModel, "/context[id11]", archetype)); //mixed aom + RM path - assertTrue(AOMUtils.isPathInArchetypeOrRm(metaModels.getSelectedModel(), "/context[id11]/health_care_facility/name", archetype)); + assertTrue(AOMUtils.isPathInArchetypeOrRm(metaModel, "/context[id11]/health_care_facility/name", archetype)); //path not in AOM, only in RM - assertTrue(AOMUtils.isPathInArchetypeOrRm(metaModels.getSelectedModel(), "/composer/external_ref", archetype)); + assertTrue(AOMUtils.isPathInArchetypeOrRm(metaModel, "/composer/external_ref", archetype)); //non-existing path - assertFalse(AOMUtils.isPathInArchetypeOrRm(metaModels.getSelectedModel(), "/doesnot_exists", archetype)); + assertFalse(AOMUtils.isPathInArchetypeOrRm(metaModel, "/doesnot_exists", archetype)); } } diff --git a/tools/src/test/java/com/nedap/archie/adlparser/RMPathQueryTest.java b/tools/src/test/java/com/nedap/archie/adlparser/RMPathQueryTest.java index 812b291fb..e3a26a967 100644 --- a/tools/src/test/java/com/nedap/archie/adlparser/RMPathQueryTest.java +++ b/tools/src/test/java/com/nedap/archie/adlparser/RMPathQueryTest.java @@ -121,7 +121,7 @@ public void findMatchSpecialisedNodes() throws Exception { inMemoryFullArchetypeRepository.addArchetype(archetype); Archetype archetype_specialised = TestUtil.parseFailOnErrors("/basic_specialised.adls"); inMemoryFullArchetypeRepository.addArchetype(archetype_specialised); - Flattener flattener = new Flattener(inMemoryFullArchetypeRepository, BuiltinReferenceModels.getMetaModels(), FlattenerConfiguration.forOperationalTemplate()); + Flattener flattener = new Flattener(inMemoryFullArchetypeRepository, BuiltinReferenceModels.getMetaModelProvider(), FlattenerConfiguration.forOperationalTemplate()); OperationalTemplate opt = (OperationalTemplate) flattener.flatten(archetype_specialised); root = (Pathable) testUtil.constructEmptyRMObject(opt.getDefinition()); @@ -136,7 +136,7 @@ public void findListMatchSpecialisedNodes() throws Exception { inMemoryFullArchetypeRepository.addArchetype(archetype); Archetype archetype_specialised = TestUtil.parseFailOnErrors("/basic_specialised.adls"); inMemoryFullArchetypeRepository.addArchetype(archetype_specialised); - Flattener flattener = new Flattener(inMemoryFullArchetypeRepository, BuiltinReferenceModels.getMetaModels(), FlattenerConfiguration.forOperationalTemplate()); + Flattener flattener = new Flattener(inMemoryFullArchetypeRepository, BuiltinReferenceModels.getMetaModelProvider(), FlattenerConfiguration.forOperationalTemplate()); OperationalTemplate opt = (OperationalTemplate) flattener.flatten(archetype_specialised); root = (Pathable) testUtil.constructEmptyRMObject(opt.getDefinition()); @@ -153,7 +153,7 @@ public void findListMatchTwiceSpecialisedNodes() throws Exception { Archetype archetype_specialised_twice = TestUtil.parseFailOnErrors("/basic_specialised2.adls"); inMemoryFullArchetypeRepository.addArchetype(archetype_specialised); inMemoryFullArchetypeRepository.addArchetype(archetype_specialised_twice); - Flattener flattener = new Flattener(inMemoryFullArchetypeRepository, BuiltinReferenceModels.getMetaModels(), FlattenerConfiguration.forOperationalTemplate()); + Flattener flattener = new Flattener(inMemoryFullArchetypeRepository, BuiltinReferenceModels.getMetaModelProvider(), FlattenerConfiguration.forOperationalTemplate()); OperationalTemplate opt = (OperationalTemplate) flattener.flatten(archetype_specialised_twice); root = (Pathable) testUtil.constructEmptyRMObject(opt.getDefinition()); diff --git a/tools/src/test/java/com/nedap/archie/aom/ArchetypeTerminologyTest.java b/tools/src/test/java/com/nedap/archie/aom/ArchetypeTerminologyTest.java index 6efbfd200..2f2e31771 100644 --- a/tools/src/test/java/com/nedap/archie/aom/ArchetypeTerminologyTest.java +++ b/tools/src/test/java/com/nedap/archie/aom/ArchetypeTerminologyTest.java @@ -31,11 +31,11 @@ public void termForUseArchetype() throws IOException, ADLParseException { repository.addArchetype(FlattenerTestUtil.parse("/com/nedap/archie/aom/openEHR-EHR-GENERIC_ENTRY.included.v1.0.0.adls")); //check that they are valid, just to be sure - repository.compile(BuiltinReferenceModels.getMetaModels()); + repository.compile(BuiltinReferenceModels.getMetaModelProvider()); repository.getAllValidationResults().forEach(s -> assertTrue(s.getErrors().toString(), s.getErrors().isEmpty())); //create operational template - Flattener flattener = new Flattener(repository, BuiltinReferenceModels.getMetaModels(), FlattenerConfiguration.forOperationalTemplate()); + Flattener flattener = new Flattener(repository, BuiltinReferenceModels.getMetaModelProvider(), FlattenerConfiguration.forOperationalTemplate()); OperationalTemplate opt = (OperationalTemplate) flattener.flatten(repository.getArchetype("openEHR-EHR-COMPOSITION.parent.v1.0.0")); //and check the getTerm() functionality diff --git a/tools/src/test/java/com/nedap/archie/aom/TerminologyCodeConstraintsTest.java b/tools/src/test/java/com/nedap/archie/aom/TerminologyCodeConstraintsTest.java index 0776536c5..e33656d30 100644 --- a/tools/src/test/java/com/nedap/archie/aom/TerminologyCodeConstraintsTest.java +++ b/tools/src/test/java/com/nedap/archie/aom/TerminologyCodeConstraintsTest.java @@ -186,7 +186,7 @@ public void validationInOptTest() throws Exception { repository.addArchetype(FlattenerTestUtil.parse("/com/nedap/archie/aom/openEHR-EHR-GENERIC_ENTRY.included.v1.0.0.adls")); //create operational template - Flattener flattener = new Flattener(repository, BuiltinReferenceModels.getMetaModels(), FlattenerConfiguration.forOperationalTemplate()); + Flattener flattener = new Flattener(repository, BuiltinReferenceModels.getMetaModelProvider(), FlattenerConfiguration.forOperationalTemplate()); OperationalTemplate opt = (OperationalTemplate) flattener.flatten(repository.getArchetype("openEHR-EHR-COMPOSITION.parent.v1.0.0")); CTerminologyCode code = opt.itemAtPath("/content/data/items/value/defining_code[1]"); assertEquals(Lists.newArrayList("at4", "at5", "at6"), code.getValueSetExpanded()); diff --git a/tools/src/test/java/com/nedap/archie/archetypevalidator/ArchetypeValidatorTest.java b/tools/src/test/java/com/nedap/archie/archetypevalidator/ArchetypeValidatorTest.java index bf3efb42f..e8dea76cc 100644 --- a/tools/src/test/java/com/nedap/archie/archetypevalidator/ArchetypeValidatorTest.java +++ b/tools/src/test/java/com/nedap/archie/archetypevalidator/ArchetypeValidatorTest.java @@ -212,7 +212,7 @@ public void parentWithDifferentRmRelease() throws IOException, ADLParseException repository.addArchetype(child); repository.addArchetype(parent); - ArchetypeValidator archetypeValidator = new ArchetypeValidator(BuiltinReferenceModels.getMetaModels()); + ArchetypeValidator archetypeValidator = new ArchetypeValidator(BuiltinReferenceModels.getMetaModelProvider()); ValidationResult validatedChild = archetypeValidator.validate(child, repository); ValidationResult validatedParent = archetypeValidator.validate(parent, repository); @@ -224,7 +224,7 @@ public void parentWithDifferentRmRelease() throws IOException, ADLParseException repository.addArchetype(child); repository.addArchetype(parent); - ArchetypeValidator archetypeValidator = new ArchetypeValidator(BuiltinReferenceModels.getMetaModels()); + ArchetypeValidator archetypeValidator = new ArchetypeValidator(BuiltinReferenceModels.getMetaModelProvider()); ValidationResult validatedParent = archetypeValidator.validate(parent, repository); ValidationResult validatedChild = archetypeValidator.validate(child, repository); @@ -295,7 +295,7 @@ public void infiniteSpecialisationTreeLoopTest() throws IOException, ADLParseExc repository.addArchetype(child1); repository.addArchetype(child2); - ArchetypeValidator archetypeValidator = new ArchetypeValidator(BuiltinReferenceModels.getMetaModels()); + ArchetypeValidator archetypeValidator = new ArchetypeValidator(BuiltinReferenceModels.getMetaModelProvider()); ValidationResult result = archetypeValidator.validate(child1, repository); assertFalse(result.passes()); assertEquals("Infinite loop caused by specialising: openEHR-EHR-CLUSTER.infinite_loop_child1.v0.0.1 in openEHR-EHR-CLUSTER.infinite_loop_child2.v0.0.1", result.getErrors().get(0).getMessage()); @@ -312,7 +312,7 @@ public void specializationAfterExclusionTest() throws IOException, ADLParseExcep repository.addArchetype(parent); repository.addArchetype(childWithSpecializationAfterExclusion); - ArchetypeValidator archetypeValidator = new ArchetypeValidator(BuiltinReferenceModels.getMetaModels()); + ArchetypeValidator archetypeValidator = new ArchetypeValidator(BuiltinReferenceModels.getMetaModelProvider()); ValidationResult result = archetypeValidator.validate(childWithSpecializationAfterExclusion, repository); assertTrue(result.passes()); assertEquals(2, result.getErrors().size()); @@ -327,7 +327,7 @@ public void incompatibleNodeIdValidationTest() throws IOException, ADLParseExcep { InMemoryFullArchetypeRepository repository = new InMemoryFullArchetypeRepository(); repository.addArchetype(archetypeWithIncompatibleNodeId); - ArchetypeValidator archetypeValidator = new ArchetypeValidator(BuiltinReferenceModels.getMetaModels()); + ArchetypeValidator archetypeValidator = new ArchetypeValidator(BuiltinReferenceModels.getMetaModelProvider()); ValidationResult result = archetypeValidator.validate(archetypeWithIncompatibleNodeId, repository); assertTrue(result.passes()); assertEquals(6, result.getErrors().size()); diff --git a/tools/src/test/java/com/nedap/archie/archetypevalidator/ArchetypeValidatorVersionsTest.java b/tools/src/test/java/com/nedap/archie/archetypevalidator/ArchetypeValidatorVersionsTest.java index e018b36e0..4a706638f 100644 --- a/tools/src/test/java/com/nedap/archie/archetypevalidator/ArchetypeValidatorVersionsTest.java +++ b/tools/src/test/java/com/nedap/archie/archetypevalidator/ArchetypeValidatorVersionsTest.java @@ -23,7 +23,7 @@ public void testMultipleVersions() throws IOException, ADLParseException { repo.addArchetype(parentv1); repo.addArchetype(parentv11); repo.addArchetype(child); - ArchetypeValidator archetypeValidator = new ArchetypeValidator(BuiltinReferenceModels.getMetaModels()); + ArchetypeValidator archetypeValidator = new ArchetypeValidator(BuiltinReferenceModels.getMetaModelProvider()); //the order of validation is important for this test! //first validate the first parent, which is valid assertTrue(archetypeValidator.validate(parentv1, repo).passes()); @@ -47,7 +47,7 @@ public void testMultipleVersionsFullyCompile() throws Exception { repo.addArchetype(parentv1); repo.addArchetype(parentv11); repo.addArchetype(child); - repo.compile(new ArchetypeValidator(BuiltinReferenceModels.getMetaModels())); + repo.compile(new ArchetypeValidator(BuiltinReferenceModels.getMetaModelProvider())); for(ValidationResult result:repo.getAllValidationResults()) { assertTrue(result.getErrors().toString(), result.passes()); } diff --git a/tools/src/test/java/com/nedap/archie/archetypevalidator/BigArchetypeValidatorTest.java b/tools/src/test/java/com/nedap/archie/archetypevalidator/BigArchetypeValidatorTest.java index 41563a17c..10d7a98a1 100644 --- a/tools/src/test/java/com/nedap/archie/archetypevalidator/BigArchetypeValidatorTest.java +++ b/tools/src/test/java/com/nedap/archie/archetypevalidator/BigArchetypeValidatorTest.java @@ -10,8 +10,9 @@ import com.nedap.archie.flattener.FullArchetypeRepository; import com.nedap.archie.flattener.InMemoryFullArchetypeRepository; import com.nedap.archie.rminfo.ArchieRMInfoLookup; -import com.nedap.archie.rminfo.MetaModels; +import com.nedap.archie.rminfo.MetaModelProvider; import com.nedap.archie.rminfo.ReferenceModels; +import com.nedap.archie.rminfo.SimpleMetaModelProvider; import org.apache.commons.io.FilenameUtils; import org.junit.Assert; import org.junit.Test; @@ -118,7 +119,7 @@ private FullArchetypeRepository parseAll() { @Test public void testFullValidityPackageBmm() { - testInner(new MetaModels(null, BuiltinReferenceModels.getBmmRepository(), BuiltinReferenceModels.getAomProfiles())); + testInner(new SimpleMetaModelProvider(null, BuiltinReferenceModels.getBmmRepository(), BuiltinReferenceModels.getAomProfiles())); } @@ -130,11 +131,11 @@ public void testFullValidityPackageModelInfoLookup() { models.registerModel(com.nedap.archie.openehrtestrm.TestRMInfoLookup.getInstance()); // access.initializeAll(schemaDirectories); - testInner(new MetaModels(models, (BmmRepository) null)); + testInner(new SimpleMetaModelProvider(models, null)); } - public void testInner(MetaModels metaModels) { + public void testInner(MetaModelProvider metaModelProvider) { Reflections reflections = new Reflections("adl2-tests.validity", Scanners.Resources); List adlFiles = new ArrayList<>(reflections.getResources(Pattern.compile(".*\\.adls"))); @@ -148,7 +149,7 @@ public void testInner(MetaModels metaModels) { int unexpectedParseErrors = 0; int wrongMessageCount = 0; List errorStrings = new ArrayList<>(); - ArchetypeValidator validator = new ArchetypeValidator(metaModels); + ArchetypeValidator validator = new ArchetypeValidator(metaModelProvider); InMemoryFullArchetypeRepository repository = new InMemoryFullArchetypeRepository(); for(String file:adlFiles) { if (file.contains("legacy_adl_1.4")) { diff --git a/tools/src/test/java/com/nedap/archie/archetypevalidator/CKMArchetypeValidatorTest.java b/tools/src/test/java/com/nedap/archie/archetypevalidator/CKMArchetypeValidatorTest.java index 4f4ca699f..e09dbd10a 100644 --- a/tools/src/test/java/com/nedap/archie/archetypevalidator/CKMArchetypeValidatorTest.java +++ b/tools/src/test/java/com/nedap/archie/archetypevalidator/CKMArchetypeValidatorTest.java @@ -2,8 +2,9 @@ import com.nedap.archie.flattener.FullArchetypeRepository; import com.nedap.archie.rminfo.ArchieRMInfoLookup; -import com.nedap.archie.rminfo.MetaModels; +import com.nedap.archie.rminfo.MetaModelProvider; import com.nedap.archie.rminfo.ReferenceModels; +import com.nedap.archie.rminfo.SimpleMetaModelProvider; import com.nedap.archie.testutil.TestUtil; import org.junit.Test; import org.openehr.referencemodels.BuiltinReferenceModels; @@ -58,11 +59,11 @@ public void fullCKMTest() { @Test public void fullCKMTestBmm() { - MetaModels bmmReferenceModels = new MetaModels(null, BuiltinReferenceModels.getBmmRepository(), BuiltinReferenceModels.getAomProfiles()); + MetaModelProvider bmmReferenceModelProvider = new SimpleMetaModelProvider(null, BuiltinReferenceModels.getBmmRepository(), BuiltinReferenceModels.getAomProfiles()); FullArchetypeRepository repository = TestUtil.parseCKM(); logger.info("archetypes parsed: " + repository.getAllArchetypes().size()); - repository.compile(bmmReferenceModels); + repository.compile(bmmReferenceModelProvider); runTest(repository); diff --git a/tools/src/test/java/com/nedap/archie/archetypevalidator/TermCodeSpecializationTest.java b/tools/src/test/java/com/nedap/archie/archetypevalidator/TermCodeSpecializationTest.java index 3c3862542..49da00b3c 100644 --- a/tools/src/test/java/com/nedap/archie/archetypevalidator/TermCodeSpecializationTest.java +++ b/tools/src/test/java/com/nedap/archie/archetypevalidator/TermCodeSpecializationTest.java @@ -26,12 +26,12 @@ public void validRequiredBindingStrength() throws Exception { InMemoryFullArchetypeRepository repo = new InMemoryFullArchetypeRepository(); repo.addArchetype(parent); repo.addArchetype(child); - ArchetypeValidator archetypeValidator = new ArchetypeValidator(BuiltinReferenceModels.getMetaModels()); + ArchetypeValidator archetypeValidator = new ArchetypeValidator(BuiltinReferenceModels.getMetaModelProvider()); repo.compile(archetypeValidator); for(ValidationResult validationResult:repo.getAllValidationResults()) { assertTrue(validationResult.toString(), validationResult.passes()); } - Flattener flattener = new Flattener(repo, BuiltinReferenceModels.getMetaModels(), FlattenerConfiguration.forOperationalTemplate()); + Flattener flattener = new Flattener(repo, BuiltinReferenceModels.getMetaModelProvider(), FlattenerConfiguration.forOperationalTemplate()); OperationalTemplate opt = (OperationalTemplate) flattener.flatten(child); ValueSet valueSet = opt.getTerminology().getValueSets().get("ac0.2"); assertEquals(new LinkedHashSet<>(Arrays.asList("at1", "at2", "at3", "at0.1")), valueSet.getMembers()); @@ -44,7 +44,7 @@ public void invalidRequiredBindingStrength() throws Exception { InMemoryFullArchetypeRepository repo = new InMemoryFullArchetypeRepository(); repo.addArchetype(parent); repo.addArchetype(child); - ArchetypeValidator archetypeValidator = new ArchetypeValidator(BuiltinReferenceModels.getMetaModels()); + ArchetypeValidator archetypeValidator = new ArchetypeValidator(BuiltinReferenceModels.getMetaModelProvider()); repo.compile(archetypeValidator); ValidationResult validationResult = repo.getValidationResult("openEHR-EHR-CLUSTER.constraint_strength_invalid_child.v1.0.0"); assertFalse(validationResult.toString(), validationResult.passes()); @@ -58,7 +58,7 @@ public void invalidConstraintStrengthRedefinition() throws Exception { InMemoryFullArchetypeRepository repo = new InMemoryFullArchetypeRepository(); repo.addArchetype(parent); repo.addArchetype(child); - ArchetypeValidator archetypeValidator = new ArchetypeValidator(BuiltinReferenceModels.getMetaModels()); + ArchetypeValidator archetypeValidator = new ArchetypeValidator(BuiltinReferenceModels.getMetaModelProvider()); repo.compile(archetypeValidator); ValidationResult validationResult = repo.getValidationResult("openEHR-EHR-CLUSTER.constraint_strength_invalid_redefinition.v1.0.0"); assertFalse(validationResult.toString(), validationResult.passes()); @@ -72,7 +72,7 @@ public void valueSetCodeChanges() throws IOException, ADLParseException { InMemoryFullArchetypeRepository repo = new InMemoryFullArchetypeRepository(); repo.addArchetype(parent); repo.addArchetype(child); - ArchetypeValidator archetypeValidator = new ArchetypeValidator(BuiltinReferenceModels.getMetaModels()); + ArchetypeValidator archetypeValidator = new ArchetypeValidator(BuiltinReferenceModels.getMetaModelProvider()); repo.compile(archetypeValidator); ValidationResult validationResult = repo.getValidationResult("openEHR-EHR-CLUSTER.constraint_strength_change_valueset_code.v1.0.0"); assertFalse(validationResult.toString(), validationResult.passes()); @@ -96,7 +96,7 @@ public void invalidValueSetRedefinition() throws IOException, ADLParseException InMemoryFullArchetypeRepository repo = new InMemoryFullArchetypeRepository(); repo.addArchetype(parent); repo.addArchetype(child); - ArchetypeValidator archetypeValidator = new ArchetypeValidator(BuiltinReferenceModels.getMetaModels()); + ArchetypeValidator archetypeValidator = new ArchetypeValidator(BuiltinReferenceModels.getMetaModelProvider()); repo.compile(archetypeValidator); ValidationResult validationResult = repo.getValidationResult("openEHR-EHR-CLUSTER.constraint_strength_invalid_redefined_value-set.v1.0.0"); assertFalse(validationResult.toString(), validationResult.passes()); @@ -110,7 +110,7 @@ public void nonExistingParentValueSet() throws IOException, ADLParseException { InMemoryFullArchetypeRepository repo = new InMemoryFullArchetypeRepository(); repo.addArchetype(parent); repo.addArchetype(child); - ArchetypeValidator archetypeValidator = new ArchetypeValidator(BuiltinReferenceModels.getMetaModels()); + ArchetypeValidator archetypeValidator = new ArchetypeValidator(BuiltinReferenceModels.getMetaModelProvider()); repo.compile(archetypeValidator); ValidationResult validationResult = repo.getValidationResult("openEHR-EHR-CLUSTER.incorrect_parent_valueset_code.v1.0.0"); assertFalse(validationResult.toString(), validationResult.passes()); diff --git a/tools/src/test/java/com/nedap/archie/creation/ExampleJsonInstanceGeneratorTest.java b/tools/src/test/java/com/nedap/archie/creation/ExampleJsonInstanceGeneratorTest.java index 6087fd158..f39680895 100644 --- a/tools/src/test/java/com/nedap/archie/creation/ExampleJsonInstanceGeneratorTest.java +++ b/tools/src/test/java/com/nedap/archie/creation/ExampleJsonInstanceGeneratorTest.java @@ -198,7 +198,7 @@ public void generateAllCKMExamples() throws Exception { int numberCreated = 0, validationFailed = 0, generatedException = 0, jsonSchemaValidationRan = 0, jsonSchemaValidationFailed = 0; int secondJsonSchemaValidationRan = 0, reserializedJsonSchemaValidationFailed = 0; int rmObjectValidatorRan = 0, rmObjectValidatorFailed = 0; - repository.compile(BuiltinReferenceModels.getMetaModels()); + repository.compile(BuiltinReferenceModels.getMetaModelProvider()); BmmModel model = BuiltinReferenceModels.getBmmRepository().getModel("openehr_rm_1.0.4").getModel(); JsonSchemaValidator firstValidator = new JsonSchemaValidator(model, true); JsonSchemaValidator secondValidator = new JsonSchemaValidator(model,false); @@ -210,7 +210,7 @@ public void generateAllCKMExamples() throws Exception { if(result.passes()) { String json = ""; try { - Flattener flattener = new Flattener(repository, BuiltinReferenceModels.getMetaModels()).createOperationalTemplate(true); + Flattener flattener = new Flattener(repository, BuiltinReferenceModels.getMetaModelProvider()).createOperationalTemplate(true); OperationalTemplate template = (OperationalTemplate) flattener.flatten(result.getSourceArchetype()); Map example = structureGenerator.generate(template); json = mapper.writeValueAsString(example); @@ -282,7 +282,7 @@ public void generateAllCKMExamples() throws Exception { } private ExampleJsonInstanceGenerator createExampleJsonInstanceGenerator() { - ExampleJsonInstanceGenerator structureGenerator = new ExampleJsonInstanceGenerator(BuiltinReferenceModels.getMetaModels(), "en"); + ExampleJsonInstanceGenerator structureGenerator = new ExampleJsonInstanceGenerator(BuiltinReferenceModels.getMetaModelProvider(), "en"); structureGenerator.setTypePropertyName(TYPE_PROPERTY_NAME); return structureGenerator; } @@ -292,7 +292,7 @@ private OperationalTemplate createOPT(String s2) throws IOException, ADLParseExc Archetype archetype = parse(s2); InMemoryFullArchetypeRepository repository = new InMemoryFullArchetypeRepository(); repository.addArchetype(archetype); - return (OperationalTemplate) new Flattener(repository, BuiltinReferenceModels.getMetaModels()).createOperationalTemplate(true).flatten(archetype); + return (OperationalTemplate) new Flattener(repository, BuiltinReferenceModels.getMetaModelProvider()).createOperationalTemplate(true).flatten(archetype); } private Archetype parse(String filename) throws IOException, ADLParseException { diff --git a/tools/src/test/java/com/nedap/archie/diff/DiffTestUtil.java b/tools/src/test/java/com/nedap/archie/diff/DiffTestUtil.java index 5f4587c99..5e2866156 100644 --- a/tools/src/test/java/com/nedap/archie/diff/DiffTestUtil.java +++ b/tools/src/test/java/com/nedap/archie/diff/DiffTestUtil.java @@ -4,7 +4,8 @@ import com.nedap.archie.flattener.Flattener; import com.nedap.archie.flattener.InMemoryFullArchetypeRepository; import com.nedap.archie.flattener.specexamples.FlattenerTestUtil; -import com.nedap.archie.rminfo.MetaModels; +import com.nedap.archie.rminfo.MetaModelProvider; +import com.nedap.archie.rminfo.SimpleMetaModelProvider; import com.nedap.archie.serializer.adl.ADLArchetypeSerializer; import com.nedap.archie.testutil.TestUtil; import org.openehr.bmm.v2.validation.BmmRepository; @@ -20,23 +21,23 @@ public class DiffTestUtil { private String expectationsResourceLocation; private InMemoryFullArchetypeRepository repository; - private MetaModels models; + private final MetaModelProvider metaModelProvider; public DiffTestUtil(String archetypesResourceLocation, String expectationsResourceLocation) { this.archetypesResourceLocation = archetypesResourceLocation; this.expectationsResourceLocation = expectationsResourceLocation; repository = new InMemoryFullArchetypeRepository(); - models = new MetaModels(BuiltinReferenceModels.getAvailableModelInfoLookups(), (BmmRepository) null); + metaModelProvider = new SimpleMetaModelProvider(BuiltinReferenceModels.getAvailableModelInfoLookups(), null); } public void test(String parentFileName, String childFileName) throws Exception { Archetype parent = FlattenerTestUtil.parse(archetypesResourceLocation + parentFileName); repository.addArchetype(parent); Archetype child = FlattenerTestUtil.parse(archetypesResourceLocation + childFileName); - Archetype flattened = new Flattener(repository, models).flatten(child); + Archetype flattened = new Flattener(repository, metaModelProvider).flatten(child); assertEquals(child.getParentArchetypeId(), flattened.getParentArchetypeId()); - Archetype diffed = new Differentiator(BuiltinReferenceModels.getMetaModels()).differentiate(flattened, parent); + Archetype diffed = new Differentiator(BuiltinReferenceModels.getMetaModelProvider()).differentiate(flattened, parent); child.setGenerated(true);//this is set by the diff tool :) String originalSerialized = ADLArchetypeSerializer.serialize(child); String diffedSerialized = ADLArchetypeSerializer.serialize(diffed); @@ -53,10 +54,10 @@ public void testWithExplicitExpect(String parentFileName, String childFileName) repository.addArchetype(parent); Archetype child = FlattenerTestUtil.parse(archetypesResourceLocation + childFileName); Archetype expectedDiff = FlattenerTestUtil.parse(expectationsResourceLocation + childFileName); - Archetype flattened = new Flattener(repository, models).flatten(child); + Archetype flattened = new Flattener(repository, metaModelProvider).flatten(child); assertEquals(child.getParentArchetypeId(), flattened.getParentArchetypeId()); - Archetype diffed = new Differentiator(BuiltinReferenceModels.getMetaModels()).differentiate(flattened, parent); + Archetype diffed = new Differentiator(BuiltinReferenceModels.getMetaModelProvider()).differentiate(flattened, parent); expectedDiff.setGenerated(true);//this is set by the diff tool :) String expectedSerialized = ADLArchetypeSerializer.serialize(expectedDiff); String diffedSerialized = ADLArchetypeSerializer.serialize(diffed); diff --git a/tools/src/test/java/com/nedap/archie/flattener/OperationalTemplateCreatorTest.java b/tools/src/test/java/com/nedap/archie/flattener/OperationalTemplateCreatorTest.java index f3ae2b575..d8e7d21b9 100644 --- a/tools/src/test/java/com/nedap/archie/flattener/OperationalTemplateCreatorTest.java +++ b/tools/src/test/java/com/nedap/archie/flattener/OperationalTemplateCreatorTest.java @@ -49,8 +49,8 @@ public void includeZeroExistence() throws Exception { @Test public void fillEmptyOccurrences() throws Exception { try(InputStream stream = getClass().getResourceAsStream("openEHR-EHR-CLUSTER.cluster_with_annotations.v1.adls")) { - Archetype archetype = new ADLParser(BuiltinReferenceModels.getMetaModels()).parse(stream); - Flattener flattener = new Flattener(new SimpleArchetypeRepository(), BuiltinReferenceModels.getMetaModels(), FlattenerConfiguration.forOperationalTemplate()); + Archetype archetype = new ADLParser(BuiltinReferenceModels.getMetaModelProvider()).parse(stream); + Flattener flattener = new Flattener(new SimpleArchetypeRepository(), BuiltinReferenceModels.getMetaModelProvider(), FlattenerConfiguration.forOperationalTemplate()); OperationalTemplate template = (OperationalTemplate) flattener.flatten(archetype); Stack workList = new Stack<>(); @@ -72,10 +72,10 @@ public void fillEmptyOccurrences() throws Exception { @Test public void dontFillEmptyOccurrencesUnlessSet() throws Exception { try(InputStream stream = getClass().getResourceAsStream("openEHR-EHR-CLUSTER.cluster_with_annotations.v1.adls")) { - Archetype archetype = new ADLParser(BuiltinReferenceModels.getMetaModels()).parse(stream); + Archetype archetype = new ADLParser(BuiltinReferenceModels.getMetaModelProvider()).parse(stream); FlattenerConfiguration flattenerConfiguration = FlattenerConfiguration.forOperationalTemplate(); flattenerConfiguration.setFillEmptyOccurrences(false); - Flattener flattener = new Flattener(new SimpleArchetypeRepository(), BuiltinReferenceModels.getMetaModels(), flattenerConfiguration); + Flattener flattener = new Flattener(new SimpleArchetypeRepository(), BuiltinReferenceModels.getMetaModelProvider(), flattenerConfiguration); OperationalTemplate template = (OperationalTemplate) flattener.flatten(archetype); Stack workList = new Stack<>(); @@ -97,9 +97,9 @@ public void dontFillEmptyOccurrencesUnlessSet() throws Exception { public void failOnMissingArchetypeEnabled() throws Exception { SimpleArchetypeRepository repository = new SimpleArchetypeRepository(); try(InputStream stream = getClass().getResourceAsStream("openEHR-EHR-OBSERVATION.with_used_archetype.v1.adls")) { - Archetype archetype = new ADLParser(BuiltinReferenceModels.getMetaModels()).parse(stream); + Archetype archetype = new ADLParser(BuiltinReferenceModels.getMetaModelProvider()).parse(stream); FlattenerConfiguration flattenerConfiguration = FlattenerConfiguration.forOperationalTemplate(); - Flattener flattener = new Flattener(repository, BuiltinReferenceModels.getMetaModels(), flattenerConfiguration); + Flattener flattener = new Flattener(repository, BuiltinReferenceModels.getMetaModelProvider(), flattenerConfiguration); OperationalTemplate template = (OperationalTemplate) flattener.flatten(archetype); fail(); } @@ -108,10 +108,10 @@ public void failOnMissingArchetypeEnabled() throws Exception { @Test public void failOnMissingArchetypeDisabled() throws Exception { try(InputStream stream = getClass().getResourceAsStream("openEHR-EHR-OBSERVATION.with_used_archetype.v1.adls")) { - Archetype archetype = new ADLParser(BuiltinReferenceModels.getMetaModels()).parse(stream); + Archetype archetype = new ADLParser(BuiltinReferenceModels.getMetaModelProvider()).parse(stream); FlattenerConfiguration flattenerConfiguration = FlattenerConfiguration.forOperationalTemplate(); flattenerConfiguration.setFailOnMissingUsedArchetype(false); - Flattener flattener = new Flattener(new SimpleArchetypeRepository(), BuiltinReferenceModels.getMetaModels(), flattenerConfiguration); + Flattener flattener = new Flattener(new SimpleArchetypeRepository(), BuiltinReferenceModels.getMetaModelProvider(), flattenerConfiguration); OperationalTemplate template = (OperationalTemplate) flattener.flatten(archetype); CArchetypeRoot archetypeRoot = template.getDefinition().itemAtPath("/data[id2]/events[id3]/data[id4]/items[id8]"); @@ -163,7 +163,7 @@ private Archetype parseAndCreateOPTWithConfig(String fileName, InMemoryFullArche models.registerModel(ArchieRMInfoLookup.getInstance()); ValidationResult validationResult = new ArchetypeValidator(models).validate(result, repository); assertTrue(validationResult.getErrors().toString(), validationResult.passes()); - return new Flattener(repository, BuiltinReferenceModels.getMetaModels(), config).flatten(parse(fileName)); + return new Flattener(repository, BuiltinReferenceModels.getMetaModelProvider(), config).flatten(parse(fileName)); } private Archetype parse(String filePath) throws IOException, ADLParseException { diff --git a/tools/src/test/java/com/nedap/archie/flattener/RMOverlayFlattenerTest.java b/tools/src/test/java/com/nedap/archie/flattener/RMOverlayFlattenerTest.java index f297c67a5..24e794f17 100644 --- a/tools/src/test/java/com/nedap/archie/flattener/RMOverlayFlattenerTest.java +++ b/tools/src/test/java/com/nedap/archie/flattener/RMOverlayFlattenerTest.java @@ -19,7 +19,7 @@ public void flattenParentChild() throws Exception{ InMemoryFullArchetypeRepository repository = new InMemoryFullArchetypeRepository(); repository.addArchetype(parent); repository.addArchetype(child); - repository.compile(new ArchetypeValidator(BuiltinReferenceModels.getMetaModels())); + repository.compile(new ArchetypeValidator(BuiltinReferenceModels.getMetaModelProvider())); repository.getAllValidationResults().forEach(v -> assertTrue(v.getErrors().toString(), !v.hasWarningsOrErrors())); Archetype flattenedChild = repository.getFlattenedArchetype("openEHR-EHR-OBSERVATION.to_flatten_child_with_overlay.v1.0.0"); @@ -39,10 +39,10 @@ public void flattenIncludedArchetype() throws Exception { InMemoryFullArchetypeRepository repository = new InMemoryFullArchetypeRepository(); repository.addArchetype(parent); repository.addArchetype(composition); - repository.compile(new ArchetypeValidator(BuiltinReferenceModels.getMetaModels())); + repository.compile(new ArchetypeValidator(BuiltinReferenceModels.getMetaModelProvider())); repository.getAllValidationResults().forEach(v -> assertTrue(v.getErrors().toString(), !v.hasWarningsOrErrors())); - OperationalTemplate opt = (OperationalTemplate) new Flattener(repository, BuiltinReferenceModels.getMetaModels(), FlattenerConfiguration.forOperationalTemplate()).flatten(composition); + OperationalTemplate opt = (OperationalTemplate) new Flattener(repository, BuiltinReferenceModels.getMetaModelProvider(), FlattenerConfiguration.forOperationalTemplate()).flatten(composition); assertEquals(VisibilityType.HIDE, opt.getRmOverlay().getRmVisibility().get("/content[id2]/subject").getVisibility()); assertEquals("at12", opt.getRmOverlay().getRmVisibility().get("/content[id2]/subject").getAlias().getCodeString()); } diff --git a/tools/src/test/java/com/nedap/archie/flattener/SiblingOrderFlattenerTest.java b/tools/src/test/java/com/nedap/archie/flattener/SiblingOrderFlattenerTest.java index b97de4458..e64653ec9 100644 --- a/tools/src/test/java/com/nedap/archie/flattener/SiblingOrderFlattenerTest.java +++ b/tools/src/test/java/com/nedap/archie/flattener/SiblingOrderFlattenerTest.java @@ -230,7 +230,7 @@ private Archetype parseAndCreateOPT(String fileName) throws IOException, ADLPars ValidationResult validationResult = new ArchetypeValidator(models).validate(result, repository); assertTrue(validationResult.getErrors().toString(), validationResult.passes()); - return new Flattener(repository, BuiltinReferenceModels.getMetaModels(), FlattenerConfiguration.forOperationalTemplate()).flatten(parse(fileName)); + return new Flattener(repository, BuiltinReferenceModels.getMetaModelProvider(), FlattenerConfiguration.forOperationalTemplate()).flatten(parse(fileName)); } private Archetype parseAndFlattenRemoveZeroOccurrences(String fileName) throws IOException, ADLParseException { @@ -241,6 +241,6 @@ private Archetype parseAndFlattenRemoveZeroOccurrences(String fileName) throws I assertTrue(validationResult.getErrors().toString(), validationResult.passes()); FlattenerConfiguration config = FlattenerConfiguration.forFlattened(); config.setRemoveZeroOccurrencesObjects(true); - return new Flattener(repository, BuiltinReferenceModels.getMetaModels(), config).flatten(parse(fileName)); + return new Flattener(repository, BuiltinReferenceModels.getMetaModelProvider(), config).flatten(parse(fileName)); } } diff --git a/tools/src/test/java/com/nedap/archie/flattener/specexamples/FlattenerExamplesFromSpecBMMTest.java b/tools/src/test/java/com/nedap/archie/flattener/specexamples/FlattenerExamplesFromSpecBMMTest.java index 2a26a2738..0edf0dbf0 100644 --- a/tools/src/test/java/com/nedap/archie/flattener/specexamples/FlattenerExamplesFromSpecBMMTest.java +++ b/tools/src/test/java/com/nedap/archie/flattener/specexamples/FlattenerExamplesFromSpecBMMTest.java @@ -1,7 +1,7 @@ package com.nedap.archie.flattener.specexamples; import com.nedap.archie.flattener.SimpleArchetypeRepository; -import com.nedap.archie.rminfo.MetaModels; +import com.nedap.archie.rminfo.SimpleMetaModelProvider; import org.junit.Before; import org.openehr.referencemodels.BuiltinReferenceModels; @@ -10,6 +10,6 @@ public class FlattenerExamplesFromSpecBMMTest extends FlattenerExamplesFromSpecT @Before public void setup() throws Exception { repository = new SimpleArchetypeRepository(); - models = new MetaModels(null, BuiltinReferenceModels.getBmmRepository(), BuiltinReferenceModels.getAomProfiles()); + metaModelProvider = new SimpleMetaModelProvider(null, BuiltinReferenceModels.getBmmRepository(), BuiltinReferenceModels.getAomProfiles()); } } diff --git a/tools/src/test/java/com/nedap/archie/flattener/specexamples/FlattenerExamplesFromSpecTest.java b/tools/src/test/java/com/nedap/archie/flattener/specexamples/FlattenerExamplesFromSpecTest.java index d208686bf..b5991cde7 100644 --- a/tools/src/test/java/com/nedap/archie/flattener/specexamples/FlattenerExamplesFromSpecTest.java +++ b/tools/src/test/java/com/nedap/archie/flattener/specexamples/FlattenerExamplesFromSpecTest.java @@ -9,7 +9,8 @@ import com.nedap.archie.base.MultiplicityInterval; import com.nedap.archie.flattener.Flattener; import com.nedap.archie.flattener.SimpleArchetypeRepository; -import com.nedap.archie.rminfo.MetaModels; +import com.nedap.archie.rminfo.MetaModelProvider; +import com.nedap.archie.rminfo.SimpleMetaModelProvider; import org.junit.Before; import org.junit.Test; import org.openehr.bmm.v2.validation.BmmRepository; @@ -26,12 +27,12 @@ public class FlattenerExamplesFromSpecTest { protected SimpleArchetypeRepository repository; - protected MetaModels models; + protected MetaModelProvider metaModelProvider; @Before public void setup() throws Exception { repository = new SimpleArchetypeRepository(); - models = new MetaModels(BuiltinReferenceModels.getAvailableModelInfoLookups(), (BmmRepository) null); + metaModelProvider = new SimpleMetaModelProvider(BuiltinReferenceModels.getAvailableModelInfoLookups(), null); } @Test @@ -39,7 +40,7 @@ public void specializationPaths() throws Exception { Archetype labTest = parse("openEHR-EHR-OBSERVATION.lab-test.v1.0.0.adls"); repository.addArchetype(labTest); Archetype specializationPaths = parse("specialization_paths.adls"); - Archetype flattened = new Flattener(repository, models).flatten(specializationPaths); + Archetype flattened = new Flattener(repository, metaModelProvider).flatten(specializationPaths); assertEquals(specializationPaths.getParentArchetypeId(), flattened.getParentArchetypeId()); CObject originalConstraint = flattened.itemAtPath("/data[id2]/events[id3]/data[id4]/items[id79]"); @@ -64,7 +65,7 @@ public void redefinitionForRefinement() throws Exception { Archetype problem = parse("problem.adls"); repository.addArchetype(problem); Archetype diagnosis = parse("diagnosis.adls"); - Archetype flattenedDiagnosis = new Flattener(repository, models).flatten(diagnosis); + Archetype flattenedDiagnosis = new Flattener(repository, metaModelProvider).flatten(diagnosis); assertEquals("Recording of diagnosis", flattenedDiagnosis.getDefinition().getTerm().getText()); @@ -101,7 +102,7 @@ public void specialisationWithCloning() throws Exception { Archetype labTestPanel = parse("openEHR-EHR-CLUSTER.laboratory_test_panel.v1.0.0.adls"); repository.addArchetype(labTestPanel); Archetype lipidStudiesPanel = parse("openEHR-EHR-CLUSTER.lipid_studies_panel.adls"); - Archetype flattenedLipidStudies = new Flattener(repository, models).flatten(lipidStudiesPanel); + Archetype flattenedLipidStudies = new Flattener(repository, metaModelProvider).flatten(lipidStudiesPanel); List itemNodes = flattenedLipidStudies.getDefinition().getAttribute("items").getChildren(); List nodeIds = itemNodes.stream().map(cObject -> cObject.getNodeId()).collect(Collectors.toList()); @@ -131,8 +132,8 @@ public void existenceRedefinition() throws Exception { Archetype mandatory = parse("openEHR-EHR-OBSERVATION.protocol_mandatory.v1.0.0.adls"); Archetype exclusion = parse("openEHR-EHR-OBSERVATION.protocol_exclusion.v1.0.0.adls"); - Archetype mandatoryFlat = new Flattener(repository, models).flatten(mandatory); - Archetype exclusionFlat = new Flattener(repository, models).flatten(exclusion); + Archetype mandatoryFlat = new Flattener(repository, metaModelProvider).flatten(mandatory); + Archetype exclusionFlat = new Flattener(repository, metaModelProvider).flatten(exclusion); CAttribute mandatoryProtocol = mandatoryFlat.getDefinition().getAttribute("protocol"); assertTrue(mandatoryProtocol.getExistence().isMandatory()); @@ -150,7 +151,7 @@ public void cardinalityRedefinition() throws Exception { repository.addArchetype(cardinalityParent); Archetype specialized = parse("openEHR-EHR-CLUSTER.cardinality_specialized.v1.0.0.adls"); - Archetype flat = new Flattener(repository, models).flatten(specialized); + Archetype flat = new Flattener(repository, metaModelProvider).flatten(specialized); CAttribute items = flat.getDefinition().getAttribute("items").getChildren().get(0).getAttribute("items"); assertEquals(new Cardinality(3, 10), items.getCardinality()); @@ -173,7 +174,7 @@ public void exclusionRemoval() throws Exception { Archetype occurrencesSpecialized = parse("openEHR-EHR-CLUSTER.occurrences_specialized.v1.0.0.adls"); - Archetype flat = new Flattener(repository, models).removeZeroOccurrencesConstraints(true).flatten(occurrencesSpecialized); + Archetype flat = new Flattener(repository, metaModelProvider).removeZeroOccurrencesConstraints(true).flatten(occurrencesSpecialized); CAttribute attribute = flat.itemAtPath("/items[id3]/value"); assertNotNull(flat.itemAtPath("/items[id3]/value[id5]")); assertNotNull(flat.itemAtPath("/items[id3]/value[id6]")); @@ -190,7 +191,7 @@ public void exclusionDefault() throws Exception { Archetype occurrencesSpecialized = parse("openEHR-EHR-CLUSTER.occurrences_specialized.v1.0.0.adls"); - Archetype flat = new Flattener(repository, models).flatten(occurrencesSpecialized); + Archetype flat = new Flattener(repository, metaModelProvider).flatten(occurrencesSpecialized); CAttribute attribute = flat.itemAtPath("/items[id3]/value"); assertNotNull(flat.itemAtPath("/items[id3]/value[id5]")); assertNotNull(flat.itemAtPath("/items[id3]/value[id6]")); @@ -214,7 +215,7 @@ public void RMTypeRefinement() throws Exception { Archetype specialized = parse("openEHR-EHR-ELEMENT.type_refinement_specialized.v1.0.0.adls"); repository.addArchetype(rmTypeRefinement); - Archetype flat = new Flattener(repository, models).flatten(specialized); + Archetype flat = new Flattener(repository, metaModelProvider).flatten(specialized); CAttribute value = flat.itemAtPath("/value"); assertEquals(3, value.getChildren().size()); @@ -241,7 +242,7 @@ public void internalReferenceRedefinition() throws Exception { repository.addArchetype(parent); Archetype specialized = parse("openEHR-EHR-ENTRY.reference_redefinition_specialized.v1.0.0.adls"); - Archetype flat = new Flattener(repository, models).flatten(specialized); + Archetype flat = new Flattener(repository, metaModelProvider).flatten(specialized); assertNotNull(flat.itemAtPath("/data[id3]/items[id4]")); assertNotNull(flat.itemAtPath("/data[id3]/items[id0.1]")); assertNull(flat.itemAtPath("/data[id2]/items[id0.1]")); @@ -254,7 +255,7 @@ public void internalReferenceRedefinitionNoReplacement() throws Exception { Archetype parent = parse("openEHR-EHR-ENTRY.reference_redefinition_parent.v1.0.0.adls"); repository.addArchetype(parent); Archetype specialized = parse("openEHR-EHR-ENTRY.reference_redefinition_no_replacement.v1.0.0.adls"); - Archetype flat = new Flattener(repository, models).flatten(specialized); + Archetype flat = new Flattener(repository, metaModelProvider).flatten(specialized); ArchetypeModelObject cluster = flat.itemAtPath("/data[id3]"); assertEquals(CComplexObjectProxy.class, cluster.getClass()); @@ -267,7 +268,7 @@ public void numericPrimitiveRedefinition() throws Exception { Archetype parent = parse("openEHR-EHR-ELEMENT.numeric_primitive_parent.v1.0.0.adls"); repository.addArchetype(parent); Archetype specialized = parse("openEHR-EHR-ELEMENT.numeric_primitive_specialized.v1.0.0.adls"); - Archetype flat = new Flattener(repository, models).flatten(specialized); + Archetype flat = new Flattener(repository, metaModelProvider).flatten(specialized); CReal flatConstraint = flat.itemAtPath("/value[id3]/magnitude[1]"); assertEquals(4.0d, flatConstraint.getConstraint().get(0).getLower(), 0.0001d); @@ -283,7 +284,7 @@ public void tupleRedefinition() throws Exception { Archetype parent = parse("openEHR-EHR-ELEMENT.tuple_parent.v1.0.0.adls"); repository.addArchetype(parent); Archetype specialized = parse("openEHR-EHR-ELEMENT.tuple_specialized.v1.0.0.adls"); - Archetype flat = new Flattener(repository, models).flatten(specialized); + Archetype flat = new Flattener(repository, metaModelProvider).flatten(specialized); //the tuple should be completely replaced with the new tuple //the attributes should be correct CComplexObject dvQuantity = flat.itemAtPath("/value[1]"); @@ -311,7 +312,7 @@ public void addTuple() throws Exception { Archetype parent = parse("openEHR-EHR-ELEMENT.type_refinement_parent.v1.0.0.adls"); repository.addArchetype(parent); Archetype specialized = parse("openEHR-EHR-ELEMENT.add_tuple.v1.0.0.adls"); - Archetype flat = new Flattener(repository, models).flatten(specialized); + Archetype flat = new Flattener(repository, metaModelProvider).flatten(specialized); //the tuple should be completely replaced with the new tuple //the attributes should be correct CComplexObject dvQuantity = flat.itemAtPath("/value[1]"); diff --git a/tools/src/test/java/com/nedap/archie/json/AOMJacksonTest.java b/tools/src/test/java/com/nedap/archie/json/AOMJacksonTest.java index 11d036810..9d416eff5 100644 --- a/tools/src/test/java/com/nedap/archie/json/AOMJacksonTest.java +++ b/tools/src/test/java/com/nedap/archie/json/AOMJacksonTest.java @@ -74,7 +74,7 @@ public void roundTripDeliriumObservationScreening() throws Exception { @Test public void motricityIndex() throws Exception { try(InputStream stream = getClass().getResourceAsStream( "/com/nedap/archie/rules/evaluation/openEHR-EHR-OBSERVATION.motricity_index.v1.0.0.adls")) { - Archetype archetype = new ADLParser(BuiltinReferenceModels.getMetaModels()).parse(stream); + Archetype archetype = new ADLParser(BuiltinReferenceModels.getMetaModelProvider()).parse(stream); String serialized = JacksonUtil.getObjectMapper(ArchieJacksonConfiguration.createStandardsCompliant()).writeValueAsString(archetype); //System.out.println(serialized); assertTrue(serialized.contains("EXPR_BINARY_OPERATOR")); @@ -116,7 +116,7 @@ public void motricityIndexRulesOldFormatAsList() throws Exception { @Test public void motriciyIndexJavascriptFormat() throws Exception { try(InputStream stream = getClass().getResourceAsStream( "/com/nedap/archie/rules/evaluation/openEHR-EHR-OBSERVATION.motricity_index.v1.0.0.adls")) { - Archetype archetype = new ADLParser(BuiltinReferenceModels.getMetaModels()).parse(stream); + Archetype archetype = new ADLParser(BuiltinReferenceModels.getMetaModelProvider()).parse(stream); String serialized = JacksonUtil.getObjectMapper(ArchieJacksonConfiguration.createConfigForJavascriptUsage()).writeValueAsString(archetype); //System.out.println(serialized); assertTrue(serialized.contains("EXPR_BINARY_OPERATOR")); @@ -136,7 +136,7 @@ public void motriciyIndexJavascriptFormat() throws Exception { @Test public void motricityIndexOldFormat() throws Exception { try(InputStream stream = getClass().getResourceAsStream( "/com/nedap/archie/rules/evaluation/openEHR-EHR-OBSERVATION.motricity_index.v1.0.0.adls")) { - Archetype archetype = new ADLParser(BuiltinReferenceModels.getMetaModels()).parse(stream); + Archetype archetype = new ADLParser(BuiltinReferenceModels.getMetaModelProvider()).parse(stream); ArchieJacksonConfiguration config = ArchieJacksonConfiguration.createStandardsCompliant(); config.setStandardsCompliantExpressions(false); String serialized = JacksonUtil.getObjectMapper(config).writeValueAsString(archetype); @@ -155,7 +155,7 @@ public void motricityIndexOldFormat() throws Exception { @Test public void archetypeSlot() throws Exception { try(InputStream stream = getClass().getResourceAsStream( "/basic.adl")) { - Archetype archetype = new ADLParser(BuiltinReferenceModels.getMetaModels()).parse(stream); + Archetype archetype = new ADLParser(BuiltinReferenceModels.getMetaModelProvider()).parse(stream); ObjectMapper objectMapper = new ObjectMapper(); JacksonUtil.configureObjectMapper(objectMapper, ArchieJacksonConfiguration.createStandardsCompliant()); objectMapper.disable(SerializationFeature.INDENT_OUTPUT); @@ -181,7 +181,7 @@ private void assertArchetypeSlot(ObjectMapper objectMapper, String serialized) t @Test public void archetypeSlotOldExpressionClassNames() throws Exception { try(InputStream stream = getClass().getResourceAsStream( "/basic.adl")) { - Archetype archetype = new ADLParser(BuiltinReferenceModels.getMetaModels()).parse(stream); + Archetype archetype = new ADLParser(BuiltinReferenceModels.getMetaModelProvider()).parse(stream); ArchieJacksonConfiguration config = ArchieJacksonConfiguration.createStandardsCompliant(); config.setStandardsCompliantExpressions(false); ObjectMapper objectMapper = JacksonUtil.getObjectMapper(config); diff --git a/tools/src/test/java/com/nedap/archie/json/flat/FlatJsonGeneratorTest.java b/tools/src/test/java/com/nedap/archie/json/flat/FlatJsonGeneratorTest.java index ad6f38389..bf1664362 100644 --- a/tools/src/test/java/com/nedap/archie/json/flat/FlatJsonGeneratorTest.java +++ b/tools/src/test/java/com/nedap/archie/json/flat/FlatJsonGeneratorTest.java @@ -19,7 +19,8 @@ import com.nedap.archie.rm.datavalues.encapsulated.DvMultimedia; import com.nedap.archie.rm.datavalues.quantity.DvCount; import com.nedap.archie.rminfo.ArchieRMInfoLookup; -import com.nedap.archie.rminfo.MetaModels; +import com.nedap.archie.rminfo.MetaModel; +import com.nedap.archie.rminfo.MetaModelProvider; import org.junit.After; import org.junit.Test; import org.openehr.referencemodels.BuiltinReferenceModels; @@ -181,7 +182,7 @@ public void dontSerializeNames() throws Exception { config.setFilterNames(true); config.setFilterTypes(false); //config.getIgnoredAttributes().add(new AttributeReference("LOCATABLE", "name")); - Map stringObjectMap = new FlatJsonExampleInstanceGenerator().generateExample(bloodPressureOpt, BuiltinReferenceModels.getMetaModels(), "en", config); + Map stringObjectMap = new FlatJsonExampleInstanceGenerator().generateExample(bloodPressureOpt, BuiltinReferenceModels.getMetaModelProvider(), "en", config); System.out.println(JacksonUtil.getObjectMapper().writeValueAsString(stringObjectMap)); @@ -210,13 +211,13 @@ public void dontSerializeTypes() throws Exception { config.setFilterNames(true); config.setFilterTypes(true); //config.getIgnoredAttributes().add(new AttributeReference("LOCATABLE", "name")); - MetaModels metaModels = BuiltinReferenceModels.getMetaModels(); - metaModels.selectModel(bloodPressureOpt); + MetaModelProvider metaModelProvider = BuiltinReferenceModels.getMetaModelProvider(); + MetaModel metaModel = metaModelProvider.getMetaModel(bloodPressureOpt); - ExampleJsonInstanceGenerator exampleJsonInstanceGenerator = new ExampleJsonInstanceGenerator(metaModels, "en"); + ExampleJsonInstanceGenerator exampleJsonInstanceGenerator = new ExampleJsonInstanceGenerator(metaModelProvider, "en"); exampleJsonInstanceGenerator.setTypePropertyName("_type"); Map generatedExample = exampleJsonInstanceGenerator.generate(bloodPressureOpt); - ObjectMapper objectMapper = metaModels.getSelectedModel().getJsonObjectMapper(); + ObjectMapper objectMapper = metaModel.getJsonObjectMapper(); String jsonRmObject = objectMapper.writeValueAsString(generatedExample); Observation bloodPressure = objectMapper.readValue(jsonRmObject, Observation.class); //set the name to be different from the archetype, so it will be added here @@ -224,7 +225,7 @@ public void dontSerializeTypes() throws Exception { - Map stringObjectMap = new FlatJsonGenerator(metaModels.getSelectedModelInfoLookup(), config).buildPathsAndValues(bloodPressure, bloodPressureOpt, "en"); + Map stringObjectMap = new FlatJsonGenerator(metaModel.getModelInfoLookup(), config).buildPathsAndValues(bloodPressure, bloodPressureOpt, "en"); System.out.println(JacksonUtil.getObjectMapper().writeValueAsString(stringObjectMap)); @@ -259,19 +260,19 @@ public void restoresThreadLocalDescriptiongAndMeaningLanguage() throws Exceptio OperationalTemplate bloodPressureOpt = parseBloodPressure(); FlatJsonFormatConfiguration config = FlatJsonFormatConfiguration.nedapInternalFormat(); - MetaModels metaModels = BuiltinReferenceModels.getMetaModels(); - metaModels.selectModel(bloodPressureOpt); + MetaModelProvider metaModelProvider = BuiltinReferenceModels.getMetaModelProvider(); + MetaModel metaModel = metaModelProvider.getMetaModel(bloodPressureOpt); - ExampleJsonInstanceGenerator exampleJsonInstanceGenerator = new ExampleJsonInstanceGenerator(metaModels, "en"); + ExampleJsonInstanceGenerator exampleJsonInstanceGenerator = new ExampleJsonInstanceGenerator(metaModelProvider, "en"); exampleJsonInstanceGenerator.setTypePropertyName("_type"); Map generatedExample = exampleJsonInstanceGenerator.generate(bloodPressureOpt); - ObjectMapper objectMapper = metaModels.getSelectedModel().getJsonObjectMapper(); + ObjectMapper objectMapper = metaModel.getJsonObjectMapper(); String jsonRmObject = objectMapper.writeValueAsString(generatedExample); Observation bloodPressure = objectMapper.readValue(jsonRmObject, Observation.class); ArchieLanguageConfiguration.setThreadLocalDescriptiongAndMeaningLanguage("nl"); - new FlatJsonGenerator(metaModels.getSelectedModelInfoLookup(), config).buildPathsAndValues(bloodPressure, bloodPressureOpt, "en"); + new FlatJsonGenerator(metaModel.getModelInfoLookup(), config).buildPathsAndValues(bloodPressure, bloodPressureOpt, "en"); // The ThreadLocalDescriptiongAndMeaningLanguage should be restored to nl after the buildPathsAndValues call. assertEquals("nl", ArchieLanguageConfiguration.getThreadLocalDescriptiongAndMeaningLanguage()); @@ -287,7 +288,7 @@ public void filterTypesWithAlternatives() throws Exception { config.setFilterNames(true); config.setFilterTypes(true); //config.getIgnoredAttributes().add(new AttributeReference("LOCATABLE", "name")); - Map stringObjectMap = new FlatJsonExampleInstanceGenerator().generateExample(bloodPressureOpt, BuiltinReferenceModels.getMetaModels(), "en", config); + Map stringObjectMap = new FlatJsonExampleInstanceGenerator().generateExample(bloodPressureOpt, BuiltinReferenceModels.getMetaModelProvider(), "en", config); System.out.println(JacksonUtil.getObjectMapper().writeValueAsString(stringObjectMap)); @@ -303,21 +304,21 @@ public void filterTypesWithAlternatives() throws Exception { private OperationalTemplate parseBloodPressure() throws IOException, ADLParseException { try (InputStream stream = getClass().getResourceAsStream(BLOOD_PRESSURE_PATH)) { - Archetype bloodPressure = new ADLParser(BuiltinReferenceModels.getMetaModels()).parse(stream); - Flattener flattener = new Flattener(new SimpleArchetypeRepository(), BuiltinReferenceModels.getMetaModels(), FlattenerConfiguration.forOperationalTemplate()); + Archetype bloodPressure = new ADLParser(BuiltinReferenceModels.getMetaModelProvider()).parse(stream); + Flattener flattener = new Flattener(new SimpleArchetypeRepository(), BuiltinReferenceModels.getMetaModelProvider(), FlattenerConfiguration.forOperationalTemplate()); return (OperationalTemplate) flattener.flatten(bloodPressure); } } private OperationalTemplate parseTypeAlternatives() throws IOException, ADLParseException { try (InputStream stream = getClass().getResourceAsStream("openEHR-EHR-CLUSTER.element_with_two_dv_types.v1.0.0.adls")) { - Archetype typeAlternatives = new ADLParser(BuiltinReferenceModels.getMetaModels()).parse(stream); - Flattener flattener = new Flattener(new SimpleArchetypeRepository(), BuiltinReferenceModels.getMetaModels(), FlattenerConfiguration.forOperationalTemplate()); + Archetype typeAlternatives = new ADLParser(BuiltinReferenceModels.getMetaModelProvider()).parse(stream); + Flattener flattener = new Flattener(new SimpleArchetypeRepository(), BuiltinReferenceModels.getMetaModelProvider(), FlattenerConfiguration.forOperationalTemplate()); return (OperationalTemplate) flattener.flatten(typeAlternatives); } } private Map createExampleInstance(OperationalTemplate bloodPressureOpt, FlatJsonFormatConfiguration config) throws IOException, DuplicateKeyException { - return new FlatJsonExampleInstanceGenerator().generateExample(bloodPressureOpt, BuiltinReferenceModels.getMetaModels(), "en", config); + return new FlatJsonExampleInstanceGenerator().generateExample(bloodPressureOpt, BuiltinReferenceModels.getMetaModelProvider(), "en", config); } } diff --git a/tools/src/test/java/com/nedap/archie/rmobjectvalidator/RmObjectValidatorTest.java b/tools/src/test/java/com/nedap/archie/rmobjectvalidator/RmObjectValidatorTest.java index 569fc5820..7f965e921 100644 --- a/tools/src/test/java/com/nedap/archie/rmobjectvalidator/RmObjectValidatorTest.java +++ b/tools/src/test/java/com/nedap/archie/rmobjectvalidator/RmObjectValidatorTest.java @@ -86,7 +86,7 @@ public void cardinalityMismatchValidation() throws Exception { } private OperationalTemplate createOpt(Archetype archetype) { - return (OperationalTemplate) new Flattener(emptyRepo, BuiltinReferenceModels.getMetaModels(), FlattenerConfiguration.forOperationalTemplate()).flatten(archetype); + return (OperationalTemplate) new Flattener(emptyRepo, BuiltinReferenceModels.getMetaModelProvider(), FlattenerConfiguration.forOperationalTemplate()).flatten(archetype); } @Test diff --git a/tools/src/test/java/com/nedap/archie/rmobjectvalidator/TerminologyCodeConstraintsTest.java b/tools/src/test/java/com/nedap/archie/rmobjectvalidator/TerminologyCodeConstraintsTest.java index 04d8afb9b..03d2eaa4a 100644 --- a/tools/src/test/java/com/nedap/archie/rmobjectvalidator/TerminologyCodeConstraintsTest.java +++ b/tools/src/test/java/com/nedap/archie/rmobjectvalidator/TerminologyCodeConstraintsTest.java @@ -213,7 +213,7 @@ public void validationInOptTest() throws Exception { repository.addArchetype(FlattenerTestUtil.parse("/com/nedap/archie/aom/openEHR-EHR-GENERIC_ENTRY.included.v1.0.0.adls")); //create operational template - Flattener flattener = new Flattener(repository, BuiltinReferenceModels.getMetaModels(), FlattenerConfiguration.forOperationalTemplate()); + Flattener flattener = new Flattener(repository, BuiltinReferenceModels.getMetaModelProvider(), FlattenerConfiguration.forOperationalTemplate()); OperationalTemplate opt = (OperationalTemplate) flattener.flatten(repository.getArchetype("openEHR-EHR-COMPOSITION.parent.v1.0.0")); CTerminologyCode code = opt.itemAtPath("/content/data/items/value/defining_code[1]"); assertEquals(Lists.newArrayList("at4", "at5", "at6"), code.getValueSetExpanded()); diff --git a/tools/src/test/java/com/nedap/archie/rmobjectvalidator/ValidateArchetypedTest.java b/tools/src/test/java/com/nedap/archie/rmobjectvalidator/ValidateArchetypedTest.java index b6524cee0..7fe9e1799 100644 --- a/tools/src/test/java/com/nedap/archie/rmobjectvalidator/ValidateArchetypedTest.java +++ b/tools/src/test/java/com/nedap/archie/rmobjectvalidator/ValidateArchetypedTest.java @@ -87,7 +87,7 @@ public void testArchetypedOtherDetails() { } private OperationalTemplate createOpt(Archetype archetype) { - return (OperationalTemplate) new Flattener(repo, BuiltinReferenceModels.getMetaModels(), FlattenerConfiguration.forOperationalTemplate()).flatten(archetype); + return (OperationalTemplate) new Flattener(repo, BuiltinReferenceModels.getMetaModelProvider(), FlattenerConfiguration.forOperationalTemplate()).flatten(archetype); } private Archetype parse(String filename) throws IOException, ADLParseException { diff --git a/tools/src/test/java/com/nedap/archie/rmobjectvalidator/validations/ArchetypeSlotValidationTest.java b/tools/src/test/java/com/nedap/archie/rmobjectvalidator/validations/ArchetypeSlotValidationTest.java index ac17ccaea..07c3d80aa 100644 --- a/tools/src/test/java/com/nedap/archie/rmobjectvalidator/validations/ArchetypeSlotValidationTest.java +++ b/tools/src/test/java/com/nedap/archie/rmobjectvalidator/validations/ArchetypeSlotValidationTest.java @@ -62,14 +62,14 @@ public void setup() throws IOException, ADLParseException { repository.setOperationalTemplate(includedOpt); repository.setOperationalTemplate(parentOfIncludedOpt); - generator = new ExampleJsonInstanceGenerator(BuiltinReferenceModels.getMetaModels(), "en"); + generator = new ExampleJsonInstanceGenerator(BuiltinReferenceModels.getMetaModelProvider(), "en"); Map generated = generator.generate(parentOpt); example = JacksonUtil.getObjectMapper().readValue(JacksonUtil.getObjectMapper().writeValueAsString(generated), Section.class); rmObjectValidator = new RMObjectValidator(ArchieRMInfoLookup.getInstance(), repository, new ValidationConfiguration.Builder().build()); } private Flattener createFlattener() { - return new Flattener(repository, BuiltinReferenceModels.getMetaModels(), FlattenerConfiguration.forOperationalTemplate()); + return new Flattener(repository, BuiltinReferenceModels.getMetaModelProvider(), FlattenerConfiguration.forOperationalTemplate()); } @Test diff --git a/tools/src/test/java/com/nedap/archie/rules/evaluation/FixableAssertionsCheckerTest.java b/tools/src/test/java/com/nedap/archie/rules/evaluation/FixableAssertionsCheckerTest.java index b6f611fe1..3fa41d240 100644 --- a/tools/src/test/java/com/nedap/archie/rules/evaluation/FixableAssertionsCheckerTest.java +++ b/tools/src/test/java/com/nedap/archie/rules/evaluation/FixableAssertionsCheckerTest.java @@ -38,7 +38,7 @@ public class FixableAssertionsCheckerTest { public void setup() { testUtil = new TestUtil(); rmObjectCreator = new RMObjectCreator(ArchieRMInfoLookup.getInstance()); - parser = new ADLParser(BuiltinReferenceModels.getMetaModels()); + parser = new ADLParser(BuiltinReferenceModels.getMetaModelProvider()); ArchieLanguageConfiguration.setThreadLocalLogicalPathLanguage("en"); ArchieLanguageConfiguration.setThreadLocalDescriptiongAndMeaningLanguage("en"); } diff --git a/tools/src/test/java/com/nedap/archie/rules/evaluation/ParsedRulesEvaluationTest.java b/tools/src/test/java/com/nedap/archie/rules/evaluation/ParsedRulesEvaluationTest.java index 65ea42b23..75d177bf8 100644 --- a/tools/src/test/java/com/nedap/archie/rules/evaluation/ParsedRulesEvaluationTest.java +++ b/tools/src/test/java/com/nedap/archie/rules/evaluation/ParsedRulesEvaluationTest.java @@ -50,7 +50,7 @@ public abstract class ParsedRulesEvaluationTest { @Before public void setup() { testUtil = new TestUtil(); - parser = new ADLParser(BuiltinReferenceModels.getMetaModels()); + parser = new ADLParser(BuiltinReferenceModels.getMetaModelProvider()); } public Archetype getArchetype() { @@ -781,9 +781,9 @@ public void flattenedRules() throws IOException, ADLParseException { InMemoryFullArchetypeRepository repository = new InMemoryFullArchetypeRepository(); repository.addArchetype(parent); repository.addArchetype(valueSet); - Flattener flattener = new Flattener(repository, BuiltinReferenceModels.getMetaModels(), FlattenerConfiguration.forOperationalTemplate()); + Flattener flattener = new Flattener(repository, BuiltinReferenceModels.getMetaModelProvider(), FlattenerConfiguration.forOperationalTemplate()); OperationalTemplate opt = (OperationalTemplate) flattener.flatten(parent); - ExampleJsonInstanceGenerator generator = new ExampleJsonInstanceGenerator(BuiltinReferenceModels.getMetaModels(), "en"); + ExampleJsonInstanceGenerator generator = new ExampleJsonInstanceGenerator(BuiltinReferenceModels.getMetaModelProvider(), "en"); Map exampleInstance = generator.generate(opt); Cluster cluster = JacksonUtil.getObjectMapper().readValue(JacksonUtil.getObjectMapper().writeValueAsString(exampleInstance), Cluster.class); //correct case first diff --git a/tools/src/test/java/com/nedap/archie/serializer/adl/ADLArchetypeSerializerParserRoundtripTest.java b/tools/src/test/java/com/nedap/archie/serializer/adl/ADLArchetypeSerializerParserRoundtripTest.java index 915be2668..42eff84ce 100644 --- a/tools/src/test/java/com/nedap/archie/serializer/adl/ADLArchetypeSerializerParserRoundtripTest.java +++ b/tools/src/test/java/com/nedap/archie/serializer/adl/ADLArchetypeSerializerParserRoundtripTest.java @@ -154,7 +154,7 @@ private Archetype roundtrip(Archetype archetype, RMObjectMapperProvider rmObject String serialized = ADLArchetypeSerializer.serialize(archetype, null, rmObjectMapperProvider); logger.info(serialized); - ADLParser parser = new ADLParser(BuiltinReferenceModels.getMetaModels()); + ADLParser parser = new ADLParser(BuiltinReferenceModels.getMetaModelProvider()); Archetype result = parser.parse(serialized); assertTrue("roundtrip parsing should never cause errors: " + parser.getErrors().toString(), parser.getErrors().hasNoErrors()); @@ -166,11 +166,11 @@ private Archetype roundtrip(Archetype archetype, RMObjectMapperProvider rmObject } private Archetype load(String resourceName) throws IOException, ADLParseException { - return new ADLParser(BuiltinReferenceModels.getMetaModels()).parse(ADLArchetypeSerializerTest.class.getResourceAsStream(resourceName)); + return new ADLParser(BuiltinReferenceModels.getMetaModelProvider()).parse(ADLArchetypeSerializerTest.class.getResourceAsStream(resourceName)); } private Archetype loadRoot(String resourceName) throws IOException, ADLParseException { - return new ADLParser(BuiltinReferenceModels.getMetaModels()).parse(ADLArchetypeSerializerTest.class.getClassLoader().getResourceAsStream(resourceName)); + return new ADLParser(BuiltinReferenceModels.getMetaModelProvider()).parse(ADLArchetypeSerializerTest.class.getClassLoader().getResourceAsStream(resourceName)); } @Test @@ -245,7 +245,7 @@ public void operationalTemplate() throws Exception { repository.addArchetype(height); repository.addArchetype(heightTemplate); - Flattener flattener = new Flattener(repository, BuiltinReferenceModels.getMetaModels()).createOperationalTemplate(true); + Flattener flattener = new Flattener(repository, BuiltinReferenceModels.getMetaModelProvider()).createOperationalTemplate(true); Archetype operationalTemplate = flattener.flatten(bloodPressureComposition); Archetype parsed = roundtrip(operationalTemplate); TestUtil.assertCObjectEquals(operationalTemplate.getDefinition(), parsed.getDefinition()); diff --git a/tools/src/test/java/com/nedap/archie/serializer/adl/ADLArchetypeSerializerTest.java b/tools/src/test/java/com/nedap/archie/serializer/adl/ADLArchetypeSerializerTest.java index a176da12d..30f281725 100644 --- a/tools/src/test/java/com/nedap/archie/serializer/adl/ADLArchetypeSerializerTest.java +++ b/tools/src/test/java/com/nedap/archie/serializer/adl/ADLArchetypeSerializerTest.java @@ -119,7 +119,7 @@ public void rmOverlay() throws Exception { " >\n" + " >")); - Archetype parsed = new ADLParser(BuiltinReferenceModels.getMetaModels()).parse(serialized); + Archetype parsed = new ADLParser(BuiltinReferenceModels.getMetaModelProvider()).parse(serialized); assertEquals(VisibilityType.HIDE, parsed.getRmOverlay().getRmVisibility().get("/subject").getVisibility()); assertEquals("at12", parsed.getRmOverlay().getRmVisibility().get("/subject").getAlias().getCodeString()); } diff --git a/tools/src/test/java/com/nedap/archie/serializer/adl/DefaultValueSerializerTest.java b/tools/src/test/java/com/nedap/archie/serializer/adl/DefaultValueSerializerTest.java index 21ed50106..313227fda 100644 --- a/tools/src/test/java/com/nedap/archie/serializer/adl/DefaultValueSerializerTest.java +++ b/tools/src/test/java/com/nedap/archie/serializer/adl/DefaultValueSerializerTest.java @@ -22,7 +22,7 @@ public class DefaultValueSerializerTest { @Test public void serializeDvTextOdin() throws Exception { - ADLParser adlParser = new ADLParser(BuiltinReferenceModels.getMetaModels()); + ADLParser adlParser = new ADLParser(BuiltinReferenceModels.getMetaModelProvider()); try(InputStream stream = getClass().getResourceAsStream("openEHR-EHR-CLUSTER.simple.v1.adls")) { Archetype archetype = adlParser.parse(stream); CComplexObject cComplexObject = archetype.itemAtPath("/items[id2]/value[id21]"); @@ -46,7 +46,7 @@ public void serializeDvTextOdin() throws Exception { @Test public void serializeDvTextJson() throws Exception { - ADLParser adlParser = new ADLParser(BuiltinReferenceModels.getMetaModels()); + ADLParser adlParser = new ADLParser(BuiltinReferenceModels.getMetaModelProvider()); try(InputStream stream = getClass().getResourceAsStream("openEHR-EHR-CLUSTER.simple.v1.adls")) { Archetype archetype = adlParser.parse(stream); CComplexObject cComplexObject = archetype.itemAtPath("/items[id2]/value[id21]"); @@ -72,7 +72,7 @@ public void serializeDvTextJson() throws Exception { @Test public void serializeDvCodedTextJson() throws Exception { - ADLParser adlParser = new ADLParser(BuiltinReferenceModels.getMetaModels()); + ADLParser adlParser = new ADLParser(BuiltinReferenceModels.getMetaModelProvider()); try(InputStream stream = getClass().getResourceAsStream("openEHR-EHR-CLUSTER.simple.v1.adls")) { Archetype archetype = adlParser.parse(stream); CComplexObject cComplexObject = archetype.itemAtPath("/items[id2]/value[id21]"); @@ -99,7 +99,7 @@ public void serializeDvCodedTextJson() throws Exception { @Test public void serializeDvCodedTextOdin() throws Exception { - ADLParser adlParser = new ADLParser(BuiltinReferenceModels.getMetaModels()); + ADLParser adlParser = new ADLParser(BuiltinReferenceModels.getMetaModelProvider()); try(InputStream stream = getClass().getResourceAsStream("openEHR-EHR-CLUSTER.simple.v1.adls")) { Archetype archetype = adlParser.parse(stream); CComplexObject cComplexObject = archetype.itemAtPath("/items[id2]/value[id21]"); @@ -126,7 +126,7 @@ public void serializeDvCodedTextOdin() throws Exception { @Test public void serializeClusterJson() throws Exception { - ADLParser adlParser = new ADLParser(BuiltinReferenceModels.getMetaModels()); + ADLParser adlParser = new ADLParser(BuiltinReferenceModels.getMetaModelProvider()); try(InputStream stream = getClass().getResourceAsStream("openEHR-EHR-CLUSTER.simple.v1.adls")) { Archetype archetype = adlParser.parse(stream); CComplexObject cComplexObject = archetype.getDefinition(); @@ -155,7 +155,7 @@ public void serializeClusterJson() throws Exception { @Test public void serializeClusterOdin() throws Exception { - ADLParser adlParser = new ADLParser(BuiltinReferenceModels.getMetaModels()); + ADLParser adlParser = new ADLParser(BuiltinReferenceModels.getMetaModelProvider()); try(InputStream stream = getClass().getResourceAsStream("openEHR-EHR-CLUSTER.simple.v1.adls")) { Archetype archetype = adlParser.parse(stream); CComplexObject cComplexObject = archetype.getDefinition(); diff --git a/tools/src/test/java/com/nedap/archie/xml/JAXBRMRoundTripTest.java b/tools/src/test/java/com/nedap/archie/xml/JAXBRMRoundTripTest.java index 97c5fb38b..9ee8a65dd 100644 --- a/tools/src/test/java/com/nedap/archie/xml/JAXBRMRoundTripTest.java +++ b/tools/src/test/java/com/nedap/archie/xml/JAXBRMRoundTripTest.java @@ -40,7 +40,7 @@ public class JAXBRMRoundTripTest { @Before public void setup() { testUtil = new TestUtil(); - parser = new ADLParser(BuiltinReferenceModels.getMetaModels()); + parser = new ADLParser(BuiltinReferenceModels.getMetaModelProvider()); } @Test From 8160ea7d369e85205e0e04cbcf4ee163c8679aab Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 16 Jun 2025 14:29:59 +0200 Subject: [PATCH 02/25] Bump jacksonVersion from 2.19.0 to 2.19.1 (#691) Bumps `jacksonVersion` from 2.19.0 to 2.19.1. Updates `com.fasterxml.jackson.core:jackson-annotations` from 2.19.0 to 2.19.1 - [Commits](https://github.com/FasterXML/jackson/commits) Updates `com.fasterxml.jackson.core:jackson-databind` from 2.19.0 to 2.19.1 - [Commits](https://github.com/FasterXML/jackson/commits) Updates `com.fasterxml.jackson.datatype:jackson-datatype-jsr310` from 2.19.0 to 2.19.1 --- updated-dependencies: - dependency-name: com.fasterxml.jackson.core:jackson-annotations dependency-version: 2.19.1 dependency-type: direct:production update-type: version-update:semver-patch - dependency-name: com.fasterxml.jackson.core:jackson-databind dependency-version: 2.19.1 dependency-type: direct:production update-type: version-update:semver-patch - dependency-name: com.fasterxml.jackson.datatype:jackson-datatype-jsr310 dependency-version: 2.19.1 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index f0be9f514..42dd58613 100644 --- a/build.gradle +++ b/build.gradle @@ -46,7 +46,7 @@ subprojects { } ext.reflectionsVersion = '0.10.2' - ext.jacksonVersion = '2.19.0' + ext.jacksonVersion = '2.19.1' java { From f2e883fcc7ba53a13fac6d0e32abe121eeb132a7 Mon Sep 17 00:00:00 2001 From: Mattijs Kuhlmann <47526389+MattijsK@users.noreply.github.com> Date: Thu, 3 Jul 2025 16:06:50 +0200 Subject: [PATCH 03/25] Correctly flatten TemporalAmount (#692) --- .../archie/json/flat/FlatJsonGenerator.java | 4 ++-- .../json/flat/FlatJsonGeneratorTest.java | 19 +++++++++++++++++++ .../archie/datetime/DateTimeParserTest.java | 3 +++ .../DateTimeSerializerFormattersTest.java | 2 ++ 4 files changed, 26 insertions(+), 2 deletions(-) diff --git a/tools/src/main/java/com/nedap/archie/json/flat/FlatJsonGenerator.java b/tools/src/main/java/com/nedap/archie/json/flat/FlatJsonGenerator.java index 06a2242dc..ef0f30dc7 100644 --- a/tools/src/main/java/com/nedap/archie/json/flat/FlatJsonGenerator.java +++ b/tools/src/main/java/com/nedap/archie/json/flat/FlatJsonGenerator.java @@ -293,8 +293,8 @@ private void addAttribute(Map result, String pathSoFar, OpenEHRB storeValue(result, newPath, DateTimeSerializerFormatters.ISO_8601_TIME.format(t)); } } else if (child instanceof TemporalAmount) { - //duration or period. now just a toString, should this be a specific formatter? - storeValue(result, newPath, child); + // Serialize using DateTimeSerializerFormatters.serializeDuration to correctly handle negative durations + storeValue(result, newPath, DateTimeSerializerFormatters.serializeDuration((TemporalAmount) child)); } else if(child instanceof byte[]) { storeValue(result, newPath, Base64.getEncoder().encodeToString((byte[]) child)); } else { diff --git a/tools/src/test/java/com/nedap/archie/json/flat/FlatJsonGeneratorTest.java b/tools/src/test/java/com/nedap/archie/json/flat/FlatJsonGeneratorTest.java index bf1664362..ba6961ae0 100644 --- a/tools/src/test/java/com/nedap/archie/json/flat/FlatJsonGeneratorTest.java +++ b/tools/src/test/java/com/nedap/archie/json/flat/FlatJsonGeneratorTest.java @@ -18,15 +18,19 @@ import com.nedap.archie.rm.datavalues.DvText; import com.nedap.archie.rm.datavalues.encapsulated.DvMultimedia; import com.nedap.archie.rm.datavalues.quantity.DvCount; +import com.nedap.archie.rm.datavalues.quantity.datetime.DvDuration; import com.nedap.archie.rminfo.ArchieRMInfoLookup; import com.nedap.archie.rminfo.MetaModel; import com.nedap.archie.rminfo.MetaModelProvider; import org.junit.After; import org.junit.Test; import org.openehr.referencemodels.BuiltinReferenceModels; +import org.threeten.extra.PeriodDuration; import java.io.IOException; import java.io.InputStream; +import java.time.Duration; +import java.time.Period; import java.util.LinkedHashMap; import java.util.Map; @@ -132,6 +136,21 @@ public void testNedapInternalFormat() throws Exception { assertEquals("Systolic", stringObjectMap.get("/data[id2]/events[id7,2]/data[id4]/items[id5,1]/name/value")); } + @Test + public void testDurationFlattening() throws Exception { + FlatJsonGenerator flatJsonGenerator = new FlatJsonGenerator(ArchieRMInfoLookup.getInstance(), FlatJsonFormatConfiguration.nedapInternalFormat()); + + // Test a positive duration, make sure the value is a String and not a Duration object + DvDuration duration = new DvDuration(PeriodDuration.of(Period.of(1,0,0), Duration.ofHours(13))); + Map pathsAndValues = flatJsonGenerator.buildPathsAndValues(duration); + assertEquals("P1YT13H", pathsAndValues.get("/value")); + + // Also test a negative duration + DvDuration negativeDuration = new DvDuration(PeriodDuration.of(Period.of(-1,-2,-4), Duration.ofSeconds(-5736))); + Map secondPathsAndValues = flatJsonGenerator.buildPathsAndValues(negativeDuration); + assertEquals("-P1Y2M4DT1H35M36S", secondPathsAndValues.get("/value")); + } + @Test public void continuesIndices() throws Exception { Cluster cluster = new Cluster(); diff --git a/utils/src/test/java/com/nedap/archie/datetime/DateTimeParserTest.java b/utils/src/test/java/com/nedap/archie/datetime/DateTimeParserTest.java index ae5b55de0..b2ab9e3d0 100644 --- a/utils/src/test/java/com/nedap/archie/datetime/DateTimeParserTest.java +++ b/utils/src/test/java/com/nedap/archie/datetime/DateTimeParserTest.java @@ -82,6 +82,9 @@ public void negativeDurations() { TemporalAmount minusOneYear2Hours = DateTimeParsers.parseDurationValue("-P1YT2H"); assertEquals(PeriodDuration.of(Period.of(-1 ,0, 0), Duration.of(-2, ChronoUnit.HOURS)), minusOneYear2Hours); + + TemporalAmount minusMultiplePeriodDuration = DateTimeParsers.parseDurationValue("-P1Y2M4DT1H35M36S"); + assertEquals(PeriodDuration.of(Period.of(-1,-2,-4), Duration.ofSeconds(-5736)), minusMultiplePeriodDuration); } } diff --git a/utils/src/test/java/com/nedap/archie/datetime/DateTimeSerializerFormattersTest.java b/utils/src/test/java/com/nedap/archie/datetime/DateTimeSerializerFormattersTest.java index 6c7cef698..24b2483d1 100644 --- a/utils/src/test/java/com/nedap/archie/datetime/DateTimeSerializerFormattersTest.java +++ b/utils/src/test/java/com/nedap/archie/datetime/DateTimeSerializerFormattersTest.java @@ -57,6 +57,7 @@ public void serializeNegativeDurations() { TemporalAmount minusOneYearOneHour = PeriodDuration.of(Period.of(-1 ,0, 0), Duration.of(-2, ChronoUnit.HOURS)); TemporalAmount minusTwoHoursPeriodDuration = PeriodDuration.of(Period.ZERO, Duration.of(-2, ChronoUnit.HOURS)); TemporalAmount minusOneYearPeriodDuration = PeriodDuration.of(Period.of(-1 ,0, 0), Duration.ZERO); + TemporalAmount minusMultiplePeriodDuration = PeriodDuration.of(Period.of(-1,-2,-4), Duration.ofSeconds(-5736)); assertEquals("-PT2S", DateTimeSerializerFormatters.serializeDuration(minusTwoSeconds)); assertEquals("-P2Y", DateTimeSerializerFormatters.serializeDuration(minusTwoYears)); @@ -64,6 +65,7 @@ public void serializeNegativeDurations() { assertEquals("-P1YT2H", DateTimeSerializerFormatters.serializeDuration(minusOneYearOneHour)); assertEquals("-PT2H", DateTimeSerializerFormatters.serializeDuration(minusTwoHoursPeriodDuration)); assertEquals("-P1Y", DateTimeSerializerFormatters.serializeDuration(minusOneYearPeriodDuration)); + assertEquals("-P1Y2M4DT1H35M36S", DateTimeSerializerFormatters.serializeDuration(minusMultiplePeriodDuration)); } From 3011de22c62e3930ae5277787e9c5e78106b5d29 Mon Sep 17 00:00:00 2001 From: Mattijs Kuhlmann <47526389+MattijsK@users.noreply.github.com> Date: Thu, 3 Jul 2025 16:16:18 +0200 Subject: [PATCH 04/25] Update Archie to v3.15.0 (#693) --- README.md | 6 +++--- build.gradle | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 4ef89bb0f..890ebee27 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,7 @@ You can depend on parts of Archie, or the entire library at once. If you want th ```gradle dependencies { - compile 'com.nedap.healthcare.archie:archie-all:3.14.0' + compile 'com.nedap.healthcare.archie:archie-all:3.15.0' } ``` @@ -28,11 +28,11 @@ or if you use maven, in your pom.xml com.nedap.healthcare.archie archie-all - 3.14.0 + 3.15.0 ``` -If you want to depend on just the AOM and BMM, without any reference model implementation, depend on com.nedap.healthcare.archie:tools:3.14.0 and com.nedap.healthcare.archie:referencemodels:3.14.0 instead +If you want to depend on just the AOM and BMM, without any reference model implementation, depend on com.nedap.healthcare.archie:tools:3.15.0 and com.nedap.healthcare.archie:referencemodels:3.15.0 instead ## Build diff --git a/build.gradle b/build.gradle index 42dd58613..f457ccd47 100644 --- a/build.gradle +++ b/build.gradle @@ -8,7 +8,7 @@ wrapper { } allprojects { - version = '3.14.0' + version = '3.15.0' group = 'com.nedap.healthcare.archie' ext.gradleScriptDir = "${rootProject.projectDir}/gradle" //archivesBaseName = 'archie' From 29a0b0c214589a5f772b76e83a2a13386876ae4f Mon Sep 17 00:00:00 2001 From: Jelte Zeilstra Date: Mon, 21 Jul 2025 12:55:37 +0200 Subject: [PATCH 05/25] Fix NullPointerException in FlatJsonGenerator.buildPathsAndValuesInner (#699) --- .../com/nedap/archie/json/flat/FlatJsonGenerator.java | 2 +- .../nedap/archie/json/flat/FlatJsonGeneratorTest.java | 9 +++++++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/tools/src/main/java/com/nedap/archie/json/flat/FlatJsonGenerator.java b/tools/src/main/java/com/nedap/archie/json/flat/FlatJsonGenerator.java index ef0f30dc7..841f8293f 100644 --- a/tools/src/main/java/com/nedap/archie/json/flat/FlatJsonGenerator.java +++ b/tools/src/main/java/com/nedap/archie/json/flat/FlatJsonGenerator.java @@ -121,7 +121,7 @@ private void buildPathsAndValuesInner(Map result, RMTypeInfo rmA CAttribute cAttribute = cObject == null ? null : cObject.getAttribute(attributeName); RMAttributeInfo attributeInfo = typeInfo.getAttributes().get(attributeName); if(!attributeInfo.isComputed() && !isIgnored(typeInfo, attributeName) && attributeInfo.getGetMethod() != null) { - if(filterNames && cObject != null && isNameAttribute(typeInfo, attributeName)) { + if(filterNames && name != null && cObject != null && isNameAttribute(typeInfo, attributeName)) { ArchetypeTerm term = cObject.getTerm(); if(term != null && name.equals(term.getText())) { continue; diff --git a/tools/src/test/java/com/nedap/archie/json/flat/FlatJsonGeneratorTest.java b/tools/src/test/java/com/nedap/archie/json/flat/FlatJsonGeneratorTest.java index ba6961ae0..2f7d24dce 100644 --- a/tools/src/test/java/com/nedap/archie/json/flat/FlatJsonGeneratorTest.java +++ b/tools/src/test/java/com/nedap/archie/json/flat/FlatJsonGeneratorTest.java @@ -34,6 +34,7 @@ import java.util.LinkedHashMap; import java.util.Map; +import static junit.framework.Assert.assertTrue; import static junit.framework.TestCase.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNull; @@ -78,7 +79,15 @@ public void testBloodPressureExample() throws Exception { } + @Test + public void testBloodPressureEmpty() throws Exception { + OperationalTemplate bloodPressureOpt = parseBloodPressure(); + FlatJsonGenerator flatJsonGenerator = new FlatJsonGenerator(ArchieRMInfoLookup.getInstance(), FlatJsonFormatConfiguration.nedapInternalFormat()); + Map pathsAndValues = flatJsonGenerator.buildPathsAndValues(new Observation(), bloodPressureOpt, "en"); + + assertTrue(pathsAndValues.isEmpty()); + } @Test public void testBloodPressureExampleWithPipesForFinalFields() throws Exception { From 10fd6525b0c553a43d8e306e6ec1908318842b8e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 28 Jul 2025 13:14:44 +0200 Subject: [PATCH 06/25] Bump org.apache.commons:commons-lang3 from 3.17.0 to 3.18.0 (#695) Bumps org.apache.commons:commons-lang3 from 3.17.0 to 3.18.0. --- updated-dependencies: - dependency-name: org.apache.commons:commons-lang3 dependency-version: 3.18.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index f457ccd47..03c7e9dab 100644 --- a/build.gradle +++ b/build.gradle @@ -71,7 +71,7 @@ subprojects { exclude group: 'commons-logging', module: 'commons-logging' } implementation 'org.apache.commons:commons-text:1.13.1' - implementation 'org.apache.commons:commons-lang3:3.17.0' + implementation 'org.apache.commons:commons-lang3:3.18.0' //java 10 no longer has these included by default, so explicit dependency is needed. api 'javax.xml.bind:jaxb-api:2.3.1' From b3119e0547298a2d65af7b8c662a2dfe4431588b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 28 Jul 2025 13:14:53 +0200 Subject: [PATCH 07/25] Bump jacksonVersion from 2.19.1 to 2.19.2 (#700) Bumps `jacksonVersion` from 2.19.1 to 2.19.2. Updates `com.fasterxml.jackson.core:jackson-annotations` from 2.19.1 to 2.19.2 - [Commits](https://github.com/FasterXML/jackson/commits) Updates `com.fasterxml.jackson.core:jackson-databind` from 2.19.1 to 2.19.2 - [Commits](https://github.com/FasterXML/jackson/commits) Updates `com.fasterxml.jackson.datatype:jackson-datatype-jsr310` from 2.19.1 to 2.19.2 --- updated-dependencies: - dependency-name: com.fasterxml.jackson.core:jackson-annotations dependency-version: 2.19.2 dependency-type: direct:production update-type: version-update:semver-patch - dependency-name: com.fasterxml.jackson.core:jackson-databind dependency-version: 2.19.2 dependency-type: direct:production update-type: version-update:semver-patch - dependency-name: com.fasterxml.jackson.datatype:jackson-datatype-jsr310 dependency-version: 2.19.2 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 03c7e9dab..407b58c52 100644 --- a/build.gradle +++ b/build.gradle @@ -46,7 +46,7 @@ subprojects { } ext.reflectionsVersion = '0.10.2' - ext.jacksonVersion = '2.19.1' + ext.jacksonVersion = '2.19.2' java { From 07c01117e9a963f3470d179943903f0eb6b8b941 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 28 Jul 2025 13:15:01 +0200 Subject: [PATCH 08/25] Bump commons-io:commons-io from 2.19.0 to 2.20.0 (#701) Bumps [commons-io:commons-io](https://github.com/apache/commons-io) from 2.19.0 to 2.20.0. - [Changelog](https://github.com/apache/commons-io/blob/master/RELEASE-NOTES.txt) - [Commits](https://github.com/apache/commons-io/compare/rel/commons-io-2.19.0...rel/commons-io-2.20.0) --- updated-dependencies: - dependency-name: commons-io:commons-io dependency-version: 2.20.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 407b58c52..d885c2fc4 100644 --- a/build.gradle +++ b/build.gradle @@ -67,7 +67,7 @@ subprojects { implementation "org.reflections:reflections:${reflectionsVersion}" implementation 'com.esotericsoftware.kryo:kryo5:5.6.2' - implementation('commons-io:commons-io:2.19.0'){ + implementation('commons-io:commons-io:2.20.0'){ exclude group: 'commons-logging', module: 'commons-logging' } implementation 'org.apache.commons:commons-text:1.13.1' From 84717b19b5bee6349b20bfb399980ca8a2e071ab Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 28 Jul 2025 14:13:20 +0200 Subject: [PATCH 09/25] Bump org.apache.commons:commons-text from 1.13.1 to 1.14.0 (#703) Bumps [org.apache.commons:commons-text](https://github.com/apache/commons-text) from 1.13.1 to 1.14.0. - [Changelog](https://github.com/apache/commons-text/blob/master/RELEASE-NOTES.txt) - [Commits](https://github.com/apache/commons-text/compare/rel/commons-text-1.13.1...rel/commons-text-1.14.0) --- updated-dependencies: - dependency-name: org.apache.commons:commons-text dependency-version: 1.14.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index d885c2fc4..6ef0d897d 100644 --- a/build.gradle +++ b/build.gradle @@ -70,7 +70,7 @@ subprojects { implementation('commons-io:commons-io:2.20.0'){ exclude group: 'commons-logging', module: 'commons-logging' } - implementation 'org.apache.commons:commons-text:1.13.1' + implementation 'org.apache.commons:commons-text:1.14.0' implementation 'org.apache.commons:commons-lang3:3.18.0' //java 10 no longer has these included by default, so explicit dependency is needed. From 9cadbc533fcc864ce0f477289a0b12f179d8a667 Mon Sep 17 00:00:00 2001 From: Mattijs Kuhlmann <47526389+MattijsK@users.noreply.github.com> Date: Fri, 8 Aug 2025 10:54:20 +0200 Subject: [PATCH 10/25] Update release configuration for central.sonatype (#694) --- build.gradle | 4 ++++ gradle/publish-maven.gradle | 21 ++++++++------------- 2 files changed, 12 insertions(+), 13 deletions(-) diff --git a/build.gradle b/build.gradle index 6ef0d897d..882a3b156 100644 --- a/build.gradle +++ b/build.gradle @@ -1,3 +1,7 @@ +plugins { + id("io.github.gradle-nexus.publish-plugin") version "2.0.0" +} + repositories { mavenCentral() } diff --git a/gradle/publish-maven.gradle b/gradle/publish-maven.gradle index 33a94ffa0..1306fac7b 100644 --- a/gradle/publish-maven.gradle +++ b/gradle/publish-maven.gradle @@ -8,25 +8,20 @@ if(gradle.ext.shouldSign) { } } } -//define the repositories on global level, not per project, or you get many of them -publishing { + +nexusPublishing { repositories { - maven { - name = "ossrh" - // OSSRH URLS - def releasesRepoUrl = 'https://oss.sonatype.org/service/local/staging/deploy/maven2/' - def snapshotsRepoUrl = 'ttps://oss.sonatype.org/content/repositories/snapshots/' - url = version.endsWith('SNAPSHOT') ? snapshotsRepoUrl : releasesRepoUrl + // see https://central.sonatype.org/publish/publish-portal-ossrh-staging-api/#configuration + sonatype { + nexusUrl.set(uri("https://ossrh-staging-api.central.sonatype.com/service/local/")) + snapshotRepositoryUrl.set(uri("https://central.sonatype.com/repository/maven-snapshots/")) - credentials { - username = project.hasProperty('ossrhUsername') ? ossrhUsername : "Unknown user" - password = project.hasProperty('ossrhPassword') ? ossrhPassword : "Unknown password" - } + username = project.hasProperty("centralTokenUsername") ? centralTokenUsername : "Unknown username" + password = project.hasProperty("centralTokenPassword") ? centralTokenPassword : "Unknown password" } } } - //now uploading will have to be configured on a per subproject basis subprojects { From b554cb350f821f30676a77d9c1f6f80f7e134cd7 Mon Sep 17 00:00:00 2001 From: Jelte Zeilstra Date: Mon, 8 Sep 2025 11:16:07 +0200 Subject: [PATCH 11/25] Add GitHub Actions to Dependabot configuration (#713) --- .github/dependabot.yml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 25474490e..caf73180b 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -6,3 +6,9 @@ updates: interval: daily time: "11:00" open-pull-requests-limit: 10 +- package-ecosystem: github-actions + directory: "/" + schedule: + interval: daily + time: "11:00" + open-pull-requests-limit: 10 From 33f986837bed7c3d9e9710f02b56a26a21da1a17 Mon Sep 17 00:00:00 2001 From: Jelte Zeilstra Date: Mon, 15 Sep 2025 16:10:51 +0200 Subject: [PATCH 12/25] Update Gradle to version 8.14.3 and fix deprecated features (#715) * Remove Gradle wrapper version from build.gradle * Update Gradle to version 8.14.3 * Use Toolchains for JVM projects to set Java version * Assign properties using the 'propName = value' syntax Setting a property via the Gradle-generated 'propName value' or 'propName(value)' syntax in Groovy DSL has been deprecated. * Remove --add-opens arguments for tests The --add-opens arguments are not needed anymore since #443 and are causing issues with Toolchains on newer JVM versions. * Add Foojay Toolchains Plugin to automatically download JDK 8 if needed --- build.gradle | 26 ++++++----------------- gradle/jacoco.gradle | 2 +- gradle/wrapper/gradle-wrapper.jar | Bin 43453 -> 43764 bytes gradle/wrapper/gradle-wrapper.properties | 2 +- gradlew | 10 +++++---- gradlew.bat | 6 ++++-- settings.gradle | 4 ++++ 7 files changed, 22 insertions(+), 28 deletions(-) diff --git a/build.gradle b/build.gradle index 882a3b156..347493351 100644 --- a/build.gradle +++ b/build.gradle @@ -7,10 +7,6 @@ repositories { } -wrapper { - gradleVersion = '5.6.4' -} - allprojects { version = '3.15.0' group = 'com.nedap.healthcare.archie' @@ -38,15 +34,12 @@ subprojects { // id 'com.github.ben-manes.versions' version '0.13.0' // } - sourceCompatibility = '1.8' - targetCompatibility = '1.8' - compileJava.options.encoding = "UTF-8" compileTestJava.options.encoding = "UTF-8" repositories { mavenCentral() - maven { url 'https://jitpack.io' } + maven { url = 'https://jitpack.io' } } ext.reflectionsVersion = '0.10.2' @@ -54,6 +47,10 @@ subprojects { java { + toolchain { + languageVersion = JavaLanguageVersion.of(8) + } + withJavadocJar() withSourcesJar() } @@ -101,20 +98,9 @@ subprojects { test { - if(JavaVersion.current() != JavaVersion.VERSION_1_8) { - jvmArgs = ['--add-opens', 'java.base/java.lang=ALL-UNNAMED' - , '--add-opens', 'java.base/java.lang.invoke=ALL-UNNAMED' - , '--add-opens', 'java.base/java.net=ALL-UNNAMED' - , '--add-opens', 'java.base/java.nio=ALL-UNNAMED' - , '--add-opens', 'java.base/java.time=ALL-UNNAMED' - , '--add-opens', 'java.base/java.util=ALL-UNNAMED' - , '--add-opens', 'java.base/java.util.concurrent.atomic=ALL-UNNAMED' - , '--add-opens', 'java.base/sun.nio.ch=ALL-UNNAMED' - , '--add-opens', 'java.base/sun.util.calendar=ALL-UNNAMED'] - } testLogging { events "failed" - exceptionFormat "full" + exceptionFormat = "full" } } diff --git a/gradle/jacoco.gradle b/gradle/jacoco.gradle index 9c7a71049..9e7373cce 100644 --- a/gradle/jacoco.gradle +++ b/gradle/jacoco.gradle @@ -14,7 +14,7 @@ subprojects { test { testLogging { events "failed" - exceptionFormat "full" + exceptionFormat = "full" } } diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index e6441136f3d4ba8a0da8d277868979cfbc8ad796..1b33c55baabb587c669f562ae36f953de2481846 100644 GIT binary patch delta 35073 zcmXuKV_=ZQFLzI6K@ichI=8Z8x@UyRrTDzMk*@-Nmx&$7z}eRNg2`%LjH zsm3x@p*YfWOs<@Et_1QbQe5}9D(gyg^rtMJf~VPPyO5H5AxBlmJ*Cvj7wV%e-kfh& zT2}75JKKJ@$;I^pQr5Wg@nH>gmmWP)dY&)f5$AD~WZ~cuQ>?%K^?`tZNP+;*U=x5B zzDfX>R~L1df^gz^O3!~<57eol7aW%sf9oh-vBt|VOEqhTHzDqCz9RR$`r=FN{0%EB zF!0jyL!f(85W)x^4%wh-P5Y)FN2F?|(0BYG@v&vxt}2Gw?T|F1P^v>RnDl!D9Xe^N zNbA=^6yFXkN~5?V+B(uWHx5%4Je2*bpbi11=X1l9K{Rv?Qam)V;s(*XRT>knW2kdd zfs>p^F!cZm(BX^ebhc$-s%J3@>#+rR1eHLWavqmJFgzwa#)&pNxoY~`=LrgI4Bfe# z^ThVC*^6Zs&VqJo@gt#Cj{$!Aw1ra6G%<64evmq|j7sTGc*5SV6heCyuduJxg0XlD zge87Z|2rGVUg#}SFh80GP*)LC8SUdMR!S3{(rS$e^xG6s-Y%Jh#VrKgw(Z~ zI^v+pu!-0JM56TF4t<}Iq}v9#C`cOAzj{~?M>|QD)z6~`R7!|+@M|eBxuSNC96cwm z3h6y^*QK5Yz?$ucW=}C^k9lCXxeyqtIHN4hwM63Er(j+py3FhAL>BL=1Au3tk&s1m z!}(GJtl^6(W{!^GWoCL zCc`nu8X~EIs)ATLpU|wzh9`r0paG2m+`6<9dov$u)(~S}oRRWe;!ZPSc^pndBBMLL zx(qnL)=<<=abEw`S1?RlGOoYL#R!fZR`>4YU|4sz;Fnr87>_s@ zRx{j{F328%!6|x;zrvS-|EoSbvnqK9NC=2}CEhmM?oCkO^Eoz@LH}+^s+sNx54t_%Zn1-g9>4&?@jrLf> zKuc%8pmeo7%yzv@cRXX^Y>y=WeaY z)(;MUFoe44(S*1ZinhavgeFBj(7B=>(H1d$jgAvFLVmHBR!i}`@DA!hPE!4e)y%Kl z^rN{0?@1u_XEJH$HZ7KocOel%<4kyH7~Tu63_p#1J?^!X6#!@^rEQ4@o9|5`gyfKe zR6oxA)Sv8dmt;)2grB`-ay(Ue&^$Yxu$XJi9YaD61_-4X_aB9E2)n4w3&8bxR<#YG zdamrv(l|;uPo&)PA@>Eo!8OmpEQNY0?;a#JKxNY*XI(ohF50#-1$*3JX!mgk9~V_x zR(i|wGu7$ON&^WoTO=L4&F5ebqFLq2yl zm(H6=mA9Hx(2NV7hZ9%C+AkBp8RWDPGkJ@>p;bW4YIY5&O#pilOa7h!k&4_ zAn9U;zkG>i$05SFs;c$fBCf<9QNFg|gnNP2_>2t(g3VomJa!W%)i74K@jl(IW6}p5 zp%Tar`Bc{T;%U&SaWA6~8li3_=hreLfoZ{0lT*-{p$^Y2``1MI#+$7_6JJZGN78BR zF!unDky|XUhtc_9kAOqzx(e(r)QIl?6`pMcT$=8`!fOHtk`aQpzEgk;v&n&t>b8n= zMp*s^LWqsjIM@ET*tm9dnA1GJxc=yp{&tpOm1DnbORbz8oBjEl<%Lb|u3k_G6PxV% zW}=_i{D;0JwD2g-QpLH?=27Nt=9tgR-cd0VgoJbO&cf}HN1fsV=~8Nlz6zC^pR#;u zo2fbq_!VSoo1%(A?h#7ULS+T4@8y@ThW8sO*Usjx9hO%tn77fc_f%(t#2=8e5F_T7 z)#7^91=d=mlV8#5;pZ0CjDZ+JY?sXw8IhLA49Tay#-Ug?CTeNqGzPK^dles^?xq_f zf};0Q=FC%5(tgV<%R-x^a?I2ZO|_F z5k2q|JEr_da+7lxssRR{*0AoBqjIs+M<{DoOssmu(V)+mk|^0Tr`B9A7<((nAx3IM zv%e`M#;BrUrkJ8js9tRJ$df;I$9~wmv}aDf3fs75P>3cZ;YDbrLPbii*UwB3)1*EMN(*q{RYSle7gcHY;dtHAF)n zzmb1d@|~pErqsNb$GOi)?NEyzZJEbAfpV)8z*=P96XZ~}HFPG|ss_F-C}}98-LI^& zLtu%JfzpdT-4Gz~Rm18xmfUwLQ-UL0@8%i|SU=@K0OPsY-TIqkAQi5GHc$+7CkLp^0O&VXSW}Yc6?RDKJXX|}~ zVe9kxU_Z*(>isfqrT>x(4%g)wB%qNWm()5w4D9mJI zj8?IIxvBGpb7=3+jrk2iMWS-B&h-NmuJC*WmpCXos$W-X5K@nRlQDO+VO)U^JmoTH zer$7t%dWOnH5jBISULQYOz;f{$xGrO|JB@ z#qy>#?T-xCp(N7K(UMbYo;AD~jw&FHXi6nk8sV&M+461@eb($?r zwc$q;YY@YMD(`T*G9E%qlJngD zCd|!=kqvAWTL3{V?2}};2jF}r{ zq=SLqU#<;<(swQz%h=}Ru8Gcw&7^P_HjKsh6jm4ct=p-pdQgzZCJS5Xs`2rfDb@k~ z@>;^C&HeGYxhk6ufwXNl@uNZ$2UfbQVsuUKUW{Zocr7iC;kkp2k@)7$sspUJAVxRT zS+Fo677*uEj91@OTrEmQ1Jc}*JNFPi38na3b5Nq1;ZJ(wkjSXSk(%6DCu*D#?&#X@ z63+N()blX1HWUmh4~KSVrPFVO2O*2kP?q7h1ETMYNr z=XgU`%SEMY$ zpPT)1@y^Jvr&kyTMci^2nYv+fG~U?N2%Sr~Hf&AFQz%LqBc5|d*Ohf5S1rDL;d_wc zC_we#<|JxyOD`seGE8pV{sqs}mS(R-JQCh59Hf12f$x-l35&XNo09$_g5QoBj377e zmJ)3=)g%=K_=e8~+^4sf#dJmU1X~tLaMm(6PX`zuvl~V_sm`4*rG2*M$Omh}{RQto z0J7v?I73w7zN*O^pIFl?o~QMWUO{U#%YkQ!uz|{T*^*Q5JI)n^l6P!&{&2dwlruk( z?|0_8dD8kH0;TobPubg43K}gGx9RksOyd>v1+lY5PSv#jr2TA95d!xN?7*Z=cz2IY?DK(6D#l`CaTORcWRw&rNe^)b0^VX zVJV<*ob8$ke5Dg!6)I&ydy3Hr0dhot-^b3{4O5VQJcfc`aUD#$ zu}D#NNj~N7DDwAtqQ3d>u!ScYHt|0ihdSrKqsAYa&VQd$@#zq<_Q@Fi3*9(0q!n#g z3*D{k_ZDmZ1U0sT$X>V5AneoGUUt0bRq}%LzY%vCaFMwV?)q*ERJB)}Q^N9RghJF! z2vq3jY6$wtw6Q+l8ZbjW({C1p9-QFlv7uku&@8*gz#`!v-ra+mek}L4jd~@Ct0-$Z zO)qQ(_POBq%Rb7?cD##@Mi&HA}VMn&;GsW9A+F7MJCFXn+#JRa&f9ORQ4;*!ae*3qi?WfIU zIC|!25-?VdY5*2~GIaO-K1L1dP-axvVZZ(er5;A_KOnhhSE>zoW}n<8=!>TMOx(gH z5hUFniB#tU3dr_|r=u!jG@OOUAMO=>5YM0vsXOD!TI=;6j(wMU4!Wi7GE)Q2cG5}EJu&st5mD&Ff)?rj{%^$9-tM@=E0iOmFov>b-H z?PJV16OiYWRyh)&MbfNq@x6c*xgGaYd__GSbjIcSqMRG#U}vreJt#g*ZYAYJFGT(nn&}>ADjFKvb2@DV%efkM?kWwM9;FJC6mGkJb`S6%S+zkQgUB4=3R)ZUK0#718^!-jrD%Au%n}~>5!4}53#J>#A z6uufqRt2Y8UY1!7yD)*3oJotcP}jny)@p5?rXpS?R#tO3Z~;p2XdI4_DZxF?M?^TD zM0?>GBuOY5{E^f9yJ{T+NIi$NWM+YT+Mz#32xtxSqspAhW+R--u=K<%SEwcu_+SiT z#uF(K#}s95`U{2L5R&^HPnch%t28Ee;Bd%GI8>&3mKhYgJW3?EPZPx_VY6{NWzPAL zEgZqn;%v{Y90#}Wk&*X1gPQZvifA34D32|g=uYJ6K^Bw9KrmI(kIdY#A*ys0P4WjRR5wd| z;u2vae^Lxh^hfj&pe0iumU@J6 zq7>OD75dwFUt*6Ah)WGHE#V4jwsKA_vx^$2HrIxg-iD#<1q_h~Yc#H;5k~6pFl!2@ z8(&SzZ3;T0kB6|J@aArl`kf+AbkXS6-HJF|bx;Jov%4d{JK3P!hoM>^JDA~jG>O@E+#V2i`?GNma>m4mVkW%3%&2;#b?>H2w4IU& z)9b2Wiz|_Q!N^mAE-B@9y7i{Q4_<1o>r|#t6DR=oAe4srLlB1o!oGWpK5ZX)IUagh zTwHv9Km~lQV19D-d(Zd5?$^`HQwTa2LJqnY+Sew*_F!EyPN9 z9vg>U1432NSHX$nS#-b`K880paf%<&9i(5VzW-K>gy-Aep$siiEk%!+r>P}lPx&D2 zYQHwm$EV~*^q+z-ojyJ)ME9h|Wv_G2Qe{$4_vhAnKj3GCg)@+^fd(3(Gf8neCX;*X{+v4}L5Pfop zSlK*xdZw-nuE7%)X>-42+=N}wtD@#50k%9?ki*E|rcF@kE+rmap?ahDZ_E--=MSy~ zO%{Y=%A1ZdD6EYR*6}78zqoYWIIQ^@sop6*H^A<&uoEDQZoQs;Bd+B(PXuo~va2dhF(clC;@U``4;5e%r95 zhZe+8olTV8bksa8t{C#ZafHk3^!;r8HTx`hHW{*k`0Y^(>c4MY1S(Acl@Fnyprcse zkr)#|LuSuwPwF||O!hz&WyzT=irv9x*vK1ii8-HyFB%a!ZJ3x9a42&ijV*^O0o(jR z`(Bp2W+nx2#twDND(Pbu%x$;CatZ+!3TC=wip9yTzO>5Jdqu3D!rUw%jr)Ir#qxGcY6&A37s_{u_03%# z>O|Fg0u@>uv?z6i_{XjYWZx;jgzUmsy&(W88AX#Hu>8X4Sg5J4|MNk5(9Is`U%^Ur zCjXy=sYqm@XlP)(Pjl(MN++AcU{gc(e-SH`LH{1~|4TTwBSQ*48Fhz=o8p;wpO~e>E5NAPbm^oI}Yw_ zKTn}RqCtfUi!g7ZB`LaJ1;>BRw;0axAV^pkSd0th_0hx%P(!0Fj~(3S6W& zWUs=z!ztSSf}E9kbSxYpe4dEvRnnr+yLXHsej%JD?4@awcF97$2*f|SWkw>V-4+fN zF8wHXHVDMETvG8TB#~ZuYq{j@F>2lXs9qY`*z>@{K`xW%9&7&<&$VOWbLx=|v*l|O z){{9SDbby@nsZlh(tAl^E72{@Gtc6_8!$L%)B_U>YaQ|sEr}?*Rl-Bmq7Hk=D|y7~ zl>?8vGyVwotKGwQf@|j1^o7pYSWc60!pOWrm=oocjQ)?6QNg|wxboNsb#4?w2_V3M=o;r|2c;SsGHo%Ber zGwU09gZ~HC3ygMAiT{MLPBMt&lUqO4vw2udrm?v`e!RTzQ3ZI7v-%2fdn$jFXtp*| zLFyXLSK4=$=;j)_@)NZi8$IPRP&0;7d6HAN_L23iqAwb#J(Br312cRQs82bDuDm9k zuqEA%jVIH)WgF{!gSM)Ch+y&v9mZ#rp=0skNjCoE9(To~-{*O@x)rN&+SOJAPrsNB zSA@A+M+{X_0WQL3SqMk$6@R51rPJkJ-u|gVn{#C(BPlk7@ezJv)GDVr8LGYiHAMPP z+`f`exGfGKwE{g5P^FMe7~d^|q^GctS!?Csb^XqB``1}*`Y#o~MM3&t|Mb=o)8=c; zg4aO&mTOVigx8!}ww~wyBQ8KZO~t#4j9X$VlXz)~;LZ+Mg}3AwSF89TrY zqO96vSFZHahCy~Wya6<$v|HyOd2mVLw!fev;PoOlFC=}1Xi>m-PE0C zr>8hX*dZ1GfKYb~GuDxl(sg~I6I>COfJ~l#r)#wQL6X7lFY@aYdJgK3U~{wfL_?ic zx?ffYb(MN$P9e62x+gSxj{2I&ac1CyF!B`wlujlB|ODNHF5Wy=+ z@xPs|Tukt7f-q#zFo6FtLPHlB3b%hAUHNMgJ$HBXp2?a1RQ9px(|o=2);DbIEgiLHzl4gC~S)gFHpVpMDHP%h_4& zsJVL*(#weP802VI;gGw)Z2~5jEw_DdCzI>Z7mhN&C~ByiKHSh5h(R59nZwSywxLnq zSx6%B8^61Ex8*NJIJ>JpqK#9e1qbe~hxqUgiuWvRf>#tGS*)i%4lJUu^EJTW2p zV1^zS%H6Z_K^Ou^75p~ zsd0n})tb~DA%9;N?wpKC^FdJ25E~dQipc|7EWQFQ=xN%KxKVUIPCTg)>eXP>GP4Sx=U3z5x%WtU# z@(3h}x9Ub0#(W6N1^!OU^~yknf$QZCKZGasEJjDMGKSB}pFjJW&dEBFj#Uu^5RGEg z>qGapV0a1|>P$Z)_Mi)ToWUDJCy4nT?KgYi3|j0zk22h<5*YraQF-HJyj~l2=V?NpqHIjI8O%eNDd_QFe+jrX6D#dr+%7v&ph+JTF)) za?w0kOcw`>j_IjswyL#iGq|22w$-PXDf8;()3&)$Ei|cRe5N^^A?~myJ1zdC768@r zO>;Dgax~?Wwgf3s6l!{qY;^PFgeDBY_x<@Cmoj;C0hT?MWU@LSdPeVf`p;1YbEd^^ zzvPugX`j+%2|YKLDf%a`+uF+SYclL{`zA1&2Lg63N_H^Fs4&})E*%q@M?ZKSLRca) z$VnqA%kS5tjO7CQrD~T#%*)}iL+;%0J@62o2RQw5&0!1^e*@GcFIML37$PQek*iln zMvxnrf!tD`d2379<0^nV-QkE=18DPx3sD4E(P>hsz8nAJ908R5?m2cB7&XYO;l_H-dSh@%&b#ZWehjt7OWdaM=!-6%;B`G} zyg4f5=YLZ*mu&jA_Fq>sh5yeZ8=zr=zw@Gl(>bVsYqNOX5NkTn=?zjzcqL&Y;|jdz zW|Wh1ZAPtT&k$V!9T3ee8uowalj)fBx&l(W!tb|ugiPw@^~OJraxMkWFW30G-|zRP zAc~Axe|Wt;Ioy;xDJ(p+6owu3=?D-Y+5W6G`&DMStkGe0mihLTtM%07r6s@3**?tH z$D#EY2s*kgJGs$nQ47aeP+3RgadCB3UA?0>&N5>YFyxeXY2mZ+jWlRgXQrPd?4ynM z$l+sLAO*U(Sg_(QJ^MeMK>&g?YsX>-9RZY<@GA-=%1&w<`v?>47#?av2QOv%^kpg8 zdA=BL$U`0rejLVS8YH!8YX|96xp6zc^fC5;Ep&0L*(IY+r0P&9{C#rkY8zP%Iyy!G zdY<)zlxFQPk6zYwOy)40bHA$YAe5W1?0iPPP?v$-Xb`E~zdJ=(`Uw^0rbQU!I2uNZYYZ^*rcyF@T zLY}K6)t+oEV42Wuln3vY95vb9gQQG~KTmXN@QWrRA|A~vB1(g+(K*sxD6_IqVVzW+ zmNAiFoHCNiQe@m{nEQwL%H6&>VC7n?NJa7DBiqpj@D-3uIb^r}%*G$VS_g_tg!mR1 z!IZPo#7*|d?F~bSVvp8;6Z_xrJY= z-N8`ecJ*Q4&LJ~77e=<)wFP;g)(Qp0coI6@Ns@00(NDahGP?{C^8x#B7U%K>yThLD zkw`dr$5e_1bmkIh7wgWj*RPnm{xE>tDwG{g^(xXB?x9`CTl~W(7}Cj}a+&jXmAU+) z6yyBk2zK`@8(Bp~T4Pv|*t>ETp$7=J-(2k~iMKHrN}=?AQ*1n97W{nxF(qD0vUS$V zG2;Vc6*D3P`i^46>N%21!WJXoQ6w50QybvUy7RbhDiE{pqu9^7tSGg@m3(2^yXRGE zR^$1v-v8r(c89_(Kfr%^bb(3}GJQg5AB$zBjUNrC3!-21Opw)+RK(GGqCz8sww>G4 zifp;0SL6{%AB268P)VtuAOw=Q89Z-U#~RxH~5K3i)-aUAW$VRjo=150l0mA;BUr@;gx)5Gjv`8MEGTEn~opA*<&cmiV{ z)RR-;pROqw`%Vql3&X`DlWQmKM>_MD5}_~-~VgYs#dWo zs{epS1z7kWetMxs1^*EI3Kq&I1G=l~y3R>peQPV5AluFAmOShy? zi|}JHPY2%Ar7YD6;dppt#TyTQmH>rbS9f}tneDe;^8vB_%sYuT60;W`lh2bL51H?m z_hUc^`rjkW>#J?*z}*I~E2#oP%N2yS$xKW$X~D?W*t&)kGeY4OtlDiEV0`V6I>T|q zb^;#xsP@H;Rs>Hm@gl}%wK$KYkF~Xc7Poj;-3MbAU$`lxTHMm1HQg+;OlZ6^9!48u zL7ra7Qm1&e!CAQbQ7OWplC?P$ZaAGXJ-{Xn`CaKof&PtpL8R!%L%Z3Hqtiw^gV$u= zo&=+U6qGsW9rc;_(KH(b{FpiqBb|mF#4U^T5GQiYqU!fCDQZ1moNX;hUQx_NUEVZ- zrA3w~SWN8NG^3sv->lAy)B>oZ9wI zyT>LJ;ebCIk|#Yfy%K|m4zk9r>6#4o*4{kyw_34iURw)%5l*Y|CZC(G$FKaQd9iF> z`eOy&WHNj!AlBMZ;I>`6L5wN-%~KvST!hs9>YmWu?F^?=Y)^(jRnfWBigl5_!%?uY zEACyMyD_+ay@Ad8(OT{Ao6vC!BXhI|Tbk2^lSP=p$LgEs{?A1}gc!X?^E};{S*e`Y zoS7Eg0qi%W9i|1pGE=voo%#7{j(?&=efo%yq#gRJ)p^IV{FVea_yR-;yG zLsEta%}NqlSVk0evAK7!|KkKp9L!~3{_S&Q{mJE+;Zp zyk1;CA&hYFA-k)pyHTop#mZ<_lv{|)oLdOXeq>maA!V&mk4g5okcrM>f-z6XI7m3| z%@6zDYuSO>O?}#U<}Tk(M#)yz@JlvOE8P2l?|ZWV*f%i=D8`YZRSX_`Rf(hhA5$j2 zEw}!bfEX*H54|8XE8vuD@iCZ_+$p}DT_KAAH?omoSlfD+MYVQhA*pgV4resUVCoEH zS~&cwYHcpVC?slhuQzFKM^4vGepC<%5d|3)whBDml`=ARJ*x<&Xjp}x{&sAB!7KiogvvxpmI_~(lO61%$k&zi_ZR*h*)t=DeoYT5eJ(Jzb8 zcvQZ$$kY2L3qCN)41L!On*5VNuJypEgAAQ%5x5P@mkqYgS)f=mFpLYbd*;cx&nQ@2 zzv3I)h+%~v&c}Z(Yyy}S9QLn;LH!?-r59EJD*kU>k}Pzfjuw945_K^(Xrs!A9EGFH zNKTF!50Bk1Q^Bzrs=hvBWu*)7O!9%4EkhbnP5D8+M-RhcwMz~j;dhju9%5ro?V$T`*337})_~U1zQz#2@7X61j(?$Weh! zuzCmc@O9jBp5I36BpqE{_3eJR>do;kp&}L%#G`t(T*%DU&WlN$F6WZ5w%)pUmOnSF zAilCA3QPpCsPS1FLw6=d0(43v@|Ul=@=9t{#8q@z)60*8ceEuA3&$%HI`as8r%KM% z+9zXob9G^q6k8o-=yvyEYKAljP*pvK}! zTAn8QA*c%e2iphLl@EKt!lKr|cpT~NHm4f0YR#{tbr}6$$QAxA@9YM&Gz^{JbJy3G zr`7U&zajC3!eRXGybbk4Ew=XM3r4E7ySuvk#P}nzVfPpALH$tF)Kn(8%USdjq@R0t z>~z74Qie2mGGsoV|1+FC3egFX{6I?d`X?VZ@ryn2kYZSD63ngr_Zc z0`B)AMqXeb^+h+Z>u3vu6X)9P>CuuFVpND>=Cv&Q{~G|Co?pr&)SLNfa`yl?jd!R z^bi%Vl%_3G!zjw>Dk_;TLJwWSd~$zry(*Lry;5i%SZUHmEzWxNj-H;~W-Z@Rqy6-< zPDttX&@+TTdHE_1Cj#mhzdr3<3AGvd26g)Z4+!2wHnEPd{l`{q0^LSq_nW9j*AgFJ zMN+C^*Sc_=UiZ~!c4~1tfd)VdD9K1>yMK4E_dSq=z|hgYkC%jxKGyH16&u4tU1 zyxna&%Yd$RksIddZrnK(B6kh~sxqSP^56H~xenjMP~9{CR7AFS1;!avDSp`YPe_fF z?_dRUZX3`q@~Vk-8CbpHsItXN3J(oYvl94OPT?I|^V06Bu2|l@-YBuv(OmTRHjCK{ z_9R13tYv>sgh_G-COLtmZs;zB8EEFUL8gvqXSKww{MQ5evUdxe(@xpO-arJdcGhJD zl@6?fpjgB*@{?Zp6cmC1mMpiHVdk_<=U^8*0jv@$|R^m5_??R=Z;JZ$_asm)Fq}(@ML%}{^?i}AQ6F%>TSX3+J?njX5|0iZy2*E#Y6x6e z@}B`NEE$wQ+KkP<6McG%L)w!gYV)~vZjUHLF7?+Y>5 zy5QqKUlGSH;70q;SM2}iD;}k!fnmC`@S5oT_;^ZlBD!CCT+jna4FUqc82`Q6CYTk) zmjZhy21Sz*@4`Jr$EGM-5ahTG#<{HT>^2PGj)*4KKd$;z)=$a!zkj@-2nkx?Zl0er z3~X7QtuJHzl);~gMyb?f%e0$pXtCt|Nq$xUJy2K!?EyoNlrfFj+kk!MAlZ4B= zmXfivbqqE_9<2kXf_||u^q{$$@usBwFppS{-EYl|ueG)uY9h!!HAtE~+ZgFcMQ^gi zTX!{sP)D}U@XZ*q+Zh;j0dgSAUsRn%(5tIZO<^&L?yaK>T&8K*Wgki4+6>CA-3{XE z+|}t>CFiQ3R+cIKriK4)Adc49SRz3tDyiccweIdgkVczVWY6k$lH1zd_JKlrNO@XA zZg3DP8)1@fiKJG zK`B(md(`QRJ+bpWKWFa{-=SegP`Ei^h%K4Vd0$-bad!Za4hoF#?U zL!c65i*TT$x4_M%#-K2d?(nN1>NqC%K6lV4I!R) z1YwiehPo7s3$F=ylCLA8X+qQjka?sdlMxk}*+p6U`u9kAEEofn7(x{18vMkE2!C9I zlM%sVe(W5aVG(AdqlbyC`ORe5x?+70F4?VjbZ5hLIaJCuvkTlH5}h(C4?^Oz!=Fn@ zw>nl+X*hw5(ampTSudw-&29o{;rEFv>yuS$?RY_+mfZr$Gj*-1M#wHz#z`bSSAOKd z`MZo@mlf&g0wT+8U;MN{2L|-wJbiT{b^QO5zuk26=rA5!Esd<|XsHPSy&!A@XeXM! zL~U833Q~iGU69Gi{_Kr*hrKp0Li}~_fae!lz}xK-e~He>It*v6b`Fl|8&ajcfL;L7fF@sG zAs9`O9f;};_@*q^J71iLm1KZk%KRcluIzDAbkOGz_FxjWSc$J-kWjc}8mG0Ap|4y) zLTs@6ck`(KrH!47S{o~j`%lfUa6V*;?1JDYG}q(#T9t)c%p+fF`%nCgz1J2cfqtiv z*86OB9`2FmIB_o-&z0bJH55K9n{t+w*@GmLUqX76OVU!z^Ne=xm+`rAv``4y3&mdl zQqWaff8^f1^up)^nvMkCjd=4y5gPP60Wdzsxb{Y`gMxLWh#q^|7!nvt$@S~q_D>Za zACG2}bT@mO!PS1$@i z`*d04z_? z78{;kvRG+wPU}&x2_qI7QdrXAZrAeoVd<=8iAFBq!k4Gtt^6gnJ>wZyk7Evi(wLmqWQo-%x zbpy^;A1c6M*xgE*0S0j_NmAX`DzH~wUVDyVMXp%It$vO|vccI~W_an&LuKcknhR-_ za(_cb5LhHCmMq3DUro%2H@V0yUHD;I+z)^MBdg=K{_h|3Q2{;jH&R{g+=P9e-D<0# z>52Fv^45?oB}h!x`X@e1WtKcqjF0aYD6hZrF+Ri;12`}~fb++%;v`lUb)`%$p;0kV!t^Q_J4E4^3HHC1VgPKV?X{_oc(c_ z3zktO2g;J2gIlPBlT}-ybMqY#IgmY!+5Dh!74k?hPBMFWLCBo$^2Tg^xKb6j)G708 zfCN6<;Co!X*4N_|)yARkA6A@0DHU}b1$xxw6)}G|_#(SRil#F7oXVFLN z9f?HUA=T%&_&aN#Pok#k;Y-6yCC$2;*uSr9Q&*O)ljQe|#FQwnM=?FmL(UV9PL`rb zG1X=tZGy}_2@Njc&EZBQDWI8Zz(6$yU@2p;hX>5m9}Z!|_m9WFW83eN+hp3h@5JNV z`5$qONFQH6sVG@?sHWs4NaYzn)nMbE1ohw0E~d6;D4Rc{{|H`^{!sb*De^1)3s=6m zBCI0X0w%&YN0-;`lpe0s_Q#nUOf!;F!*0Iq8=&r$K=RaB9lfqyY%&ih-;%hx8d!2u2U!Vzbg$yF=tkAGGl zFU-Rl!6HS?Rt{2z&?k3rn=Hi+k|0KRb7{fyr`__wr|dEzaw@c*vEm=X6q~+63illq zMZe`wz2E!LA8F-fCNB&k*WLe7g`L7ZVG9HZ2wIH);>j^D95B8H4-f?)9o!FH_(v3_ zsE}NMV{T*ZeD;0xuLBCpjp!TBAao4n2Lv$by2&bfH<*ddb#mSHven~o?QzQRONFWQ z_Qr{I{e#4%jIB^$rQ@lFqTxd2bex_dr2_!qZ-sdq`6H3#+T3suv_NHxR_tHl_)vf| zS4PAGVj}A!JUDi+16F9C#qnq?_@DTc9cm*n; z*9%@1EpokzV0@q;wwpkNB5FZJQPis_zP(<>*Y$-8O7H)h*-f&^rqti9z;ySGH||=0_xhSXEp|vx$7{khvHqI+nwXIqN+dNiVWdMTBd%jT zqbGGOt7CIe%Z6fudhAd(m&(?J`?X|Nudf*z2&J^4P(sk?Yie2@TXPv;GwX`@{kdck z3)w*}v>LB^dLWV3^-Ll?fYrl#CX2JMzOLbthIOI1ez@k13Ne$~W8^Y_F@19)sWUA% zG6RhR87-dF8;@kPp&>ofxW#(iW50E2iL^{kruo-thqcC}mL6!_(RZC5Gi7o!IaAnY zS{U3HncVL&1rr-;uVR`vx!RW0vRRo_Cf|T=?#vh_h=9d*!=_OathH%m^;j;GFozqb z!))-9m*%KcL35dwo*hR@ELSvS<~ z^-?{BRH~x}*vjT4VKfSwjXO1S5JtS1$pMDoKfzKViZV@w2WxBS5|vidrA(DG_ho7V zOQvCadwpmlj7oiH~}6K}#Rz0^Xj zDm7D^t=64dMo*i6Ug{78nrX95v|CH*UfOD}!CvnD4cBRzn3AY}j{t7l}2!l*%;-aeJ~(tcQ9OD2tfBfaTEY2!$G$B=M%cn!lt zuAze-z+8*B0fqWtH=B4U2U?*)BL)A9Lu3U&_dR@SWD*g+6IMgzzK0Z8_OgL`l&4E3~!(}3O;Wv#<6vJOD3ZYBL@Ek+SRgx7p4^@ z+ARihq?Bb4yoqjB>CJS@OkG+|5TBw^ncf2BO;Xr@s$~Zuu1vQftJ_x1whr5@!ciin zkX_mkj(aP;O*qNF&LD(snf?s|SPFqlEecNMw#`T;?PLxjchWmlx`Y0m$sa5aWBcs8 zRJxtsEoxC@2G<3U_o#F$y_c!!wSr-JtKM&9>~QYM^%eGIx|?ZB@GMSiV{e!aF+;fp ze(q6!>3#Gc#iVH2uG7>rTAxU6|H-5z#G7ekgj7=%)LB@EdOk?^R?r9NLq#ej`!d~+ zY=-utTR&=A;f>H8p^sG1hv}oJ6KQL?w4M~a$4eil2L#+FnCf3sU-qNN)J$;xApA9@ z4fpAI&zL(39$q#XgPl*&!zw*QpJtLmA%#wVGKF6AxR!nhSja~*jfwy`SDini(ilAo zt%O4Ru4z6{r_g8clG02R*Q}Qw7u?j*DU^n6t}k0~@9JP@*=+q;dQw1t4w=_Tmq@$! z9817!ifR*_qF)^Q1v)KM_7u~ae;!|^FCv>2*cE=!l7WO52hV|*QZBwsez`Uge4=;oAI=%FDdQRx-8^V`6XH)051jv7(Nj1_fg*498 zTF!I+S#G~W&kJt9ivnSBE10!-eF52PIqHHa=WwU?L{`LK+)F>OOWY5UstXvQ0|Md4 z#s1LZr=^J5k;#aF`>9Gl6Q#2vW~5DjG@{w<`mmRNE*h#k=zo~bn=VRgE|H9j`uj^1 z9|XX!RC-agCT`Jxr%^*gWyPO`3?%(6{Z5ehU*r$dus6N*2hqs9NPmQ}&?6u%7S-#e zKhsBqW?r(i4mA!XbrZeAUv2aL4V)w~TbP4Z{(vE0p}z|&{R1)@>29OY7kKG^jL`5y z5Q64gbc*KaNXNY_iJsyic9gcHR_T=4Rp?wMnyTpqVRC1Kmt|H|cC$w)6pFt5T)bmO zHkfQL*o&&bbC_OtZa6Z}Lqdp5E69ZcdnYgO@O-W;HqNC0GFPcwEpjzCD}3H8IZ?z4 zV}Ph*3=pI+h6cw_ZhBi;NYk@_mi>}k&Py4i#T|^%qN;`1#!TVNCT`HZyao=2g-d4S-HFn)hA$Hkm>VvfQaaHP3}{I!;5&|g#`J=<)-f%% zSq-2N22#1CnShH2?AD_};jqfHjp+vJwUgUwT z=zAlEaVR$=GX{}G?H!w2dLz3JZrRn+9_cvP+tab@;MN^o9bRrhYsZ_ob)s=@5RG$# z)i`szJ!2N^GYr=}rxXBxrElgfA~v>y?DR7g-Ub_kte!sX<%kW4*=0fD{3#<1?_gRM zEFHsU89n$)3>dtNDOg4^lMW_GY(*F)k?450eFb1g|J0zraN3!*)BMoOSMeT|d--ZK zgJsT(7y|?1fW4yV?6vvZukt=VAZFg9h(NgDL6Pp78Iwy*84`tmYmbhjnEgcq#eML4 zk!Dtw)yMSgWS^<49Ai{IHypn|f$Cb4kER{fX2Ik#nw^k%kP{xDW0F~12B{r`Sklnq zGAGMBV>zlaqa&G%8U2WnIkY>G(hZSLxYNr+e7%PaMuT}Ccs&d$W?H2#IE$?1dVV%J zr*euhF|7%fliId_(S|a(owo9h3Uv7V`DKth(^(TEsm!l0onR&$PBRBZK~D8qj`qfx zE;Y@;tP|g)@{Npf>cCkUK8rERZkF&;IO!&p-@rGc1&Jp_YuT5xo5i`)Zi4t2zeSkk zRv4*K;oFf8Fu9tYc1Pvqx7p7@4>qCY*ri4+Yh`+5Zu=) zYSsPxVL@|$q*(3H-48alCI&jwrfww&%s%e8#ev8a7P*h}0|E!rjyu?Ck%7G)RQY54 zkm#PC6u%x8EfjLW{Hf+^)v~BrCq+ItI1gLw+_hs{N84_N$EHDA_f-6-4LJ_T8xlh{ z_G9+i4MnPed8ce00RxTt8)XMIa&4#uWzNqrk{3Y8f ztScPUkCKtKaIeG9@K;ol`KvH$Lo#+q;jh7(sY7v$@m_w;&ij}@DiY}OGw39Y4BC%x z+3Og8I?kV@xGR@7kte6L5#Pa#)Mn(8ajP|mWpsF4V92^_3&e}m0{uoNAk-cZ1_&sO zabq61Zt2S!$(*U%mVLpxROIig{JiKpl(d#ML{_#M>}_8D5&u}!=AXDo{F&Ff$wBaP#lCy%!jJZNKGs6)`Dbmesq{Tky{(=9f^6&XiOdI|mekwDjlLgkDLR-?v z>Q{>Ey5#U=cEIV@h8W$fcJ;6PHZZ`w7vG*6ljw~`hVXUxJ^ z2P-%ts8Ud)ADsO>DJaznbPOv?VX=lnOPthl>DVCJa=XJ9_EMyJVIg1^GSP~E*J#ZP zxk+k}8igJ(<@n0ngv-(z1*4wzJ)%oD2MtKNsSM?PGbm3zE2H;|JJCj)0uH@QYEr2} zT3d2sQ3@qX>yacA>BGh$B%t+WM$Fl-mP>{*X@hjRDupEsNv@cPMXz*)2#6|a6H~`z z>P(6+XS#JqZmTs=RC8ck%dS9wB3)dbS~>$OS7cW>VRft zuz+b;#UKpon6})a;EUfFu_^+IY#?WUTv4PearC5?Fscqh7Z}L{_9Y~LgzsTmb@ppT zgoAOUm;(_+y(lr#RZR7T>Kd3F^6UyF)H*rvS|bt;!g#f@4Y>|Wam^vc-a#f*eCO7oToXgT?htcP`bZXLbu7=pu5FY?W8U z94Yw6l1}7#3BM|cl!cY9Jk85fb)FXI>7r;PPb({H^VE1;exYuRE_;MFFhxeFa?dz5 zN4x6sv}u&u>m#e`itk(SZ(C)gvO7<^MyWSXSKEIh?N~B+d00)kUL@ z%2v6>aDdx|SLtQ-+5(aK=}R=)luy=jb&jnl2suydSlkA_ar z+w=6!QMzlCj*rv(qG4Ca?;NG~KSK90h24JlBlIz*<9yoh62Cvm^aMzUM${o;Xf^pvh3q=l$}*JUyMKuZCSCXCA=**R1^pu|K~# zPv2}3fYku~whdbCa$alw`h1?gCyH8K^Kp;6MLH)9O5^U$g^rO3J5rBVU0lP=2 zVw`>!9i{(16#^O{!wRJKD|!0GajFuu#P1?+^FsyNVUK`+@>oze`(5MoV$|#DIse!^Kuv^v_R1F@sd1Wv}feZbAC${zwD@1gfz1A z+JdRA?N9ri(U3TDWo1n0iRbP)!F6Jx;W+j9;egFyS7i+A(XiX%VYTxn;S=`DrOpr0 zdBW}R=E(C}FoUQWA$^?JM}53ulrKMJ|J*2kKFn=@dwkq6#+^9pG*yexf=Djl_}!47 zLO$L;#@(~*&a+lrpdvyu6cw*^KHfRXJ!2e&3}V6WDp}!u(Qe3Cc|D@3C>?$@jPf;k z){Z-#8s}IvT0hRqqN5xi<$)7?sB4^401wrl;4CaL#zzj0@(ttshG-WeZ=7!gNmtz{ zzd1C2%C`VM+I@m=6ZB~l820g7^ZfQ`lYEbG?74n-wXJhuJ0IUs+*2WwJVJB)Zb!9j zStb+(nK6E6p6?1PK7Q{QzdsuG`0?`tdA={t9~tM5!H=9xN}fMit$?Rb&0n79Ph0LK zKWMvISQhqEPVguQLA6#MQ2nlduxA8rf|WI-xU#3szqWe>;0a(DTJOZB~6i2Ttd)hMT_R4dE`*OI-!_ZH*C(*C9qrEZH}9s^Az@FNgU7e6loA-{=c59D zxBj4yzb8VEe^A8x;VJIsFv9GoRs6G*kAHqlTkGPm?3bUS-oola*Sqeat>gTQs1;u? z)`Npz<@tA(BmFtr{S+-lq=UvQ_`86fJ~k%t2&vosa`y-?M2hN$ea}3!eS|%J`80i} zE-yLZKG1^X0fu$_D^FnDw?(b5UQJ3>ES`u~C_l!wP^HN|`S~e!F#L1u@%1f)U zTM>;oe9|R7KIu}dufvLrl~p~Aw~c%9Qp=}=-mK;Ajyiy~ts0ZI2$juXp1V(f6?F{b z_@qwDI6u!z5uem8tn4XK`KnM+TN7x0^`KAMX{SY>v}+P}0>Cp1z;*%QlXkBfmG+#P z!f`z~juttdCdt0yx`hnPYfe!WI)=H5SGtxK({c(*ea;7+C*^0QxO2>T+Il|Y{H}Pq ztK5s-M~U34+^enUT6frbZgg*dww{~ao$f(ABkmp6bGQ2%>)GcXw4QHvACp`0Jm$XB zf`6y`F7cFGFQ|_^zz4CzdyiUGJJkiJWI(bk`_9a z(0PskEpn_NzoVAUcQnyrM;l$>*hxzqgS6CZA>>9dx-XMa{0mw9z$8SGe9wn_Lf4i@S;Gfd{H}O(sc zKrycgSqW!_6&EPWa&fCW$&p$cj~v_-Go8k@t6OP*Qwc94tvyya8J7_iSkRWok$f46`*Ts1hik&{O=T)GTNle}?3pp6i5yc>)u{ zrnAa_;Dbz`*5vHQtfxAT!Lb_VqefursK^e7bMCaH6$zPf1+^OLSiM5x+Ks3=-h%XU z66Qk#3u~lEa|~i30bk9b3lH6!QAHvaVKHkvj+}3>H>zk7P#rtHO2-MTpbkp}=H@-Y zF{CrInzJq(Is6Ei$m@>o^(9c=i;3GS^D56dlXcL#GK$B4?L(C+tYlF;^K* zuZ|UI?@kw}JbX$h_yk=@BN#Ljl#vT5C&M*I%%K10#Su2o%g`1E8j4*jKB?ghoGEbZ zQEpOj7FnBKc!nLN0G!PU*^X6XV4`D7!ZD)?R#W86INj^=gJ!QHD;=`cG@@j|8mujU zLI=*JJKkehk!0LFi{fB}DP>CYCCqsUu(tCFDe?$Zu%42xj|U=z2<7=wi4OTw=+bZj zE~H}&5db^nMR)obgOogUj4cr(ksuXgl2#6q2_|~@c7^i?E#GBUV39GosMgVIEN*J< zNJe#RWREt0ZmHH|Gbo!*uvcJq-gM1>LJWHmgUyH6M_!nlNp?a|QWCQ#NFMQDW8lf;sm1?$FR!6o=K>$^02 z8dA#gc-)ZU6?{g+<%|PvBNQ5U92pSeTlG17p4VMLIWX211y|B}SdK|yv?+;yD#lpb zni(fMuELj!@kLxs4jnqL;2KH_s;}+lW=F?Yu&fx@;yMDym>l>j=JLP|6vv1i4x6NC zdcHfKB0%?BN$ zjrZYx-uUBm(MaRxj3>Fn7BzOyNMv8`tY?PdsB2gh!K{5@(_8O)p}a8 zr^k$&q1C1#>(#?_PT9HESYI*&C)w#ovb8Q_aLy71kL5WiSxA1O;c+}6P`Gx@O5YL{ zPYTqIF3gc}*i!VghDWi7ap>T-v`LxypK92JpV1W|DWNv%{B%6WA=`zYliFa!PSD6N zxEa`mUy_S0b}|yGirG$oRS$zq72S#6DgqtK*%v73^JHo^F%@^5EXx-lFpeGx5+Vw!0ni$YBb1yq_^<4Mm6f4Y=ukX z6DKyQ{;Pm%ZO6fCl`}^>-^JgH@Hf0Swl+$+3jRq3Id+@fPt}6n0HX%w%E)Wb2l$tU z_wjFXuiuJ=?EZv`|4^i;A$ANaMqoWX*SD5lBi>H5cAM^eL6t!+EmN|1( z(8FNb=q?HrwRH2Y#TrQ269ka+@d2L0JYY&`u$+}#9;ioa)kV3e(8Lrm zm8uDumUGSM66bWYx%W>OUQx-LrjIFPBs6L`4m&?n6SHK0KRrJ&Kc))$^7P1Afu(uU zXx(9Reym{9TrK93Y%z}&EE$t0l;3o%6>%&9c;irPMAS;~YcauqK$lG{WVIyNG26|4+3SkM zvb_-0YFCbbYG0jeRI(4lg*B3(nK?tzL{C{Fhf%=4x1!2QkUdrO zoU=kzR4?RQgDU)49Wr1v(MT`I934x?KtayLvYgJa_3WI9Qwg?4ceG~XV}^3pP#0g& zLN9A-<{3`glhJN7zJ?=2xKv0@A4L|0lS}wL1`ySMGnC$9lF~~|QhK=oaMAiQOraO| z3gT*MzlZ3o+Q9nt-hv&dsM~>Q^*d1M+kqM0!X213ggN(t|4LAex#@j{+es%$cVAaK zg86~A+CfZ9VZjLM0<~R3sF&=*6pk-#rhh4%IE1Bxs7&G1t!S!Cp=B!?Xio+GDg!C3 z97bDz;H*KM6KLNJ&wzVk-Tmk!A?s2wQV4a{1_JA8HLaM|K8P9q0@~&;9K@`E-&3DL zZ|5MQe#PCadYX%TQo35MZiQCw^A@CVk+(1fXB&!#aj{<=Kr8c?1^nuhr0c*tUUdYQ z2mIO)KKpQUvAbC>*UO9Vz-+Htt}hPwCrG1zi@lnczP`|Tg)RmTyz15bs#kpgUlvGz zTraQ{$MM(K1RkM~_%*Ws8ypa?)>XQ72;0fcbSzT1Z5VfU4jg!z?DGs_AccE;US$~f zvSEYd#sFULEHCohj_16}lh{))R|Wiv6sK^2QyAjtK9H5T)31(5tzOlu`7%f0ORrpi zn6r}3fdVpuU4iwy(b*l4^9ccQqZiH7r8DBG#A|>{N?Jlk2|v|K))GM z*gZLkAT*v1_zU=eOaDBKzub?1r0`*X=|?FJwr2n@NS6zJWx_>%iS`ju5b*58`+0_LrGuhfloIplEMI9Kz-0PWvY=ys=%d0n zEb3FDk%B;+>SOBLjXB7y+ZC(6D1%EU>Tv!!_~rl-SA;yiIOweELIdJi?eOb79Rq>oY4$8-;#mGouolk_$0 zm-J0)ADDhfwU;Q>SWVIiRKA#hR*E^2R*MrQJz1=lG%EVUtKt-Kk+@3ItHrgFUN5#w zdb1do^dYfV(!Jt&u^$jGikBq6U%bWCb&cyr_XM$A(jw8~+U~kl@=Te(&2^{bnKD1% z8k9U!=7(GlN}eh6J6(@Ro+xt@?bQ|6y?y&`$0%Oo?}wxGR{Klz0Nn(+NB`ppt-B;7kJGPPnlS1@z=Eq<5wVR}u){02Ox; zsD1=ZEJrbctS-WsAflM)T82rkHJI$W041&M%LYJ zOKqvn8>I&WVJ`e@>#4mHnuhz zUW>Zd%6?zt$4SI~lcxhlC4TO|$3j~w-G4Q7M%K!ZiRsf{m&+`_EmNcWDpuKn zz~ahZga7dAl|W%-^~!;R$uf$lI4EIk3?ryIC}TXYW(0;0`IS)TrpP}tglbN4Rm~aB zg2TZCuXEfjpuhoC)~>H#Ftz@S>Dn`9pMU{c7+4fO0Z>Z^2t=Mc0&4*P0OtV!08mQ< z1d~V*7L%EKFMkPm8^?8iLjVN0f)0|RWazNhlxTrCNF5O=L$(|qvP}`96jDcE$(EPE zf?NsMWp)>mXxB>G$Z3wYX%eT2l*V%1)^uAZjamt$qeSWzyLHo~Y15=<+Qx3$rdOKY zhok&&0FWRF%4wrdA7*Ff&CHwk{`bE(eC0czzD`8jMSo7v#dGI|cRk)Zs-;iqW~MdK zn$EVyTGLj3!pLc^VVUu~mC-S7>p5L>bWDzGPCPxXr%ySBywjSH8!T(g4QQ%tWV0x-GTxc>x`MRw2YvQwFLXi(-2*!pH1fqj&WM* z)ss%^jy-O~~=Jod&rs3`p^lQh*xx z>$V^%w2Z&j!JV31wR!8-t%AmCUa;)Y-AU<8!|LS2%021Y5tmW3yZsi6H<#N!hAI1Y zOn-O#a+>1^Y7Vzo?Ij0y2kCaYgRP(n3RWNMr&c&bKWjLyBMtUYkTz4BLYwF=K`m0W z;2OEkJ}Z|4-hg4pPhmj~dVa#4Ok$m&rpk#@lE-jhgrW+yQw*XxjPPMNp)uTkZ2rB2 z)Iptm9_-aTw@Z(0YjS%(ZC7XqyKkA{^nV*Rl(6i{Anhz^*#)h&3?SVSPA&|N-F%x} zbT_Y02wE{;M?c*o$Zt4%`65BuLv73GUb;`vqYp@vs~HH{#%O^rt!`;^wx}6PcU04I z)wE^0nqjJ%ISH|nPKNGusC&;&prdD0*HW{FnNjt#TH4J`s@rDeCOZPuGcS}&{(tsU zA6${O?7Rk>-W^^Hh+{QwxL7Jkd+C0K`so2dTfRpG`DsAVrtljgQiju@Li;Ew$mLtxrwweRuSZebVg~sWWptaT74S$#u1s7ZB zTHa52W{3I8m+)pOWYR>19WXa<84{8gUtj=V_*gGP(WQby4xL6c6(%y83!VL#8W`a1 z&e9}n@)*R^Im^+5^aGq99C`xc8L2Ne1WWY>>Fx9mmi@ts)>Sv|Ef~2BXN7kvbe@6I zI43cH)FLy+yI?xkdQd-GT7R<$v9kgDZhDVGKTPlCRF1mA9S_ov&;gF&AH@(u#l-zK zg!>k+E-Qjf-cLWyx_m%Td}$9YvGPN_@+qVd*Q)5cI$TrLpP-Mh>_<6kysd!BC`cEX zVf*Q0Y(UgdE^PYo5;;FDXeF@IGwN8mf~#|e4$?Ec!zTJEQCEM2VSjC;Wf`Vg*;)ah zW;Gxob7z~`W~NXn)s)F=lj^v3T31JP-BevIkI)8>oH5+-jyAK;GP8!ASKV>V#gDFT zsa`xXt|1Uc3i&PSgl%D=JEwjW^F5vD1UeDg2OE5$hxnCFVvbUDpIEl_O19mVOmP_8bVz-kCsYEtX_1Ovbj+KS444hDH zKJfNHwq&hQ29#QGU>;3PSjf!&)Yr_T8HS#)Y zF@1v9`RQjDr1yF0XiA~y=y{YGCGep{s6iwTA*ge*SZSH9K;{Gc1^NWT@{>XOdHMwf z#oVVr5e4%x1I%+r&CEE*Qu8V$tmu5mm?%|OR}{L++~wCzm$RIp(7a-4uUW|Jw)8G^ zn5G$)e{tS^RevIWx`v3t^JKqe>w9y09=jp{Kg*@dXXrZU#?;Tc<%xwMJewbXg?^RA ze+_wMk=A>m=A@r~0~#Z6hmh`q^b!Z`=jde+%aR2&hxQ>`<7bXmDk+!%e+$*7qh)2_ z^In4P`ktr>O8z!|UZGd$clcz~c=h>Hr~z=--z_oAmw!Nq6({r-vRRJz0|mD#FZ{ls z+p66(fA$X)`U?9cH0RlBfikrIP@yl=AE9!T32=5+P-i$<+jN!7%+FG|&!5nrvTOeg zUa57UpZ*+hJA>p2ga0MxsK21E^Uo8!3b{#gdjViLwDj?{%qL2b= zfc}>G8GrHM04YZSz|%^HpkOH)4w1W41*h(bOQ8mmEBsPEo@ObLg93$OR0O5mp zOMj_muJWzicd5+~DdKi<2U`M<%O>D6UC5#6I_&6n&lq+LidLWk)0^OY9*xW4fM}}_ z(4tNKVhgr%baxmv1}d_H<;08!&5{N0g2W)&MMM!{5rt{6{~60ZbqGntDu5ToKv2X* zM+0=~M6SR&<)ddMykRaD#Wt~>_t=3wq<=D6rYsQ@J4;ibrnTWEV_xiHnY-c4F?oiI zdnZc;p4g2750m%IdkG@6bOz!c03W3^!@e}MkjzV?@Z_6Ck0S09y;xv4TzT4dVFJ}b zQ1pW-F|*f4{BIQzPD0Kdvk|QP{?*Mzf6Q4J5u5wBBE`9VlR!DpSj`QxGz*C1KwY`uOsHURS@Wb04YUIC8;j5AVHYM92El2AI3|7!eaOO$$wm{yCc6}sue43iB z(dyLTG_^#o(%R@%3dOF{`pXhN4YYwamKKQzu%sUCvS_48cOEU$mW!m!P=9=IitdXR zXsou|$KQ-uyjWqQ}X6V7eYqT$w6p?A#KSdvb6cFIOR4q2LNNghFd6ACR zq1M@i@lB~zGSZZqriY;H1%C=h<@t9;uhDT<@L}{HO(kEVmC@_oXQ(0S**-;H@pAPM zql=DME;|u{PV`eSkr1cw8-cy+VdH~Tho_^5PQzI5hn1hk=oGB~D*W}B#^ZpzM3Zs;1Bsf0H=O>b*lMV|>Id?7De>`bbw{(os|iidojmii(+ zJ_T#jhg$0EF0t9a77uxgbgoE0g!SjKewv>2bop9*@$1i0N4&+iqmgc&o1yom5?K6W zxbL!%ch%M+eefu@$Iyq5p7+5aUyAWQ7g9q-`pFAWDVi$MB{=)pq@RtFI-c-)A|u}D zh%Yu$A0KJ@nUJ?+p?~L6u+PukkXqb;1zKnw?ZnMCAU$*2j^CZL_F4f6AMEu3*y|O1 zH*on~MrSW(JZQTj(qC~jzsPRd?74SC6t~&Ho{dB|Y=>iK=<-GKd0seQ2i;$T8Bdj+ z^cwz8-F(Mj1Sh?ABUYrpy39W}5TOdE+ z*bM#6<z)Ddox>o2N5DqtOG!qxx|%NBqc+6Fj^Fz(uu%!QGdXaA8r=)rLCl^E*&i&6g$x@ z0yt?#tSE}ciVo|C*xX<);bC`*gjXbdQe-WHg1wsXvs(d>ud+wQMn*g0ivOoLF2tQh zvAJ2?b)qO@SH#w$c$56?E{a6L*BFNL_ZP*zUEYT7Kts0@^2Hfeo@y3{rp4hK(U3pni(e5(n#Egj{R-^BgMlcU zDgtvJJ9-)Hy>pP4vE5+TX7MmA3PKQ#&Ef<;Z3EAhC`=6xC zvd=B|IeNLzE%#rd&&xiy-2Xa#L-x7l{_7|Jxz8>7!Xp~FFI(=%M7Qj7%l))?O6pmP ziz6nW|1H4kBUC4nix*$<2{av@xW8pXsPUVs;6 zJVT3+(1xAt?9Q3@Iqyu)%%8u%egjy8DR6vr^rrerZ%S*Q{Fc6`FJH6}@8{p6nQo%F$e3uUKnOSQ}Q)_}#>H zIS{p_QQ;x^w&N3pj&F1Hkiv+)I9^?SyjnF{bf|wGg%C(Lf+V!)h2xUId=T2E9mcN1L$QF^ z5g2*u_)h#xV5qoL+7?I^OWPS_a6JtT*$mPcAHy(mJmUtoz)Z1zp0^RJebf|pVGWIs zQB0nO8D@fneP+6d6PT}AA2UVLt7UKlb7PprygKtn-5>!^V1XRwIrG!}4+mn=`W zBk<_rS~lAZls_hOj;GnnAs;L$9u zaRbuj_dhXN_<^afP)`ndO!qW}o+exVj;Uj$zv1Tc32vVWmrHP`CoJ`Zxvp@$E4=rv z{Dp%8tK5(97c5fP{T{ZAA#Omvi%lqOVetgT%V6phEDiQ6oM7cL#+QIm<(v8kP)i30 z>q=X}6rk(Ww~N);x^ ziv)>V)F>R%WhPu8Gn7lW${nB1g?2dLWg6t73{<@%o=iq^d`ejx{msu;S`%=Y2!BRo z(WJ^CT4hqAYqXBuA|4G-hEb5 zmu9WW%-NT3U(UDppMSsn9l$6&h9?gmEM$I+<+-sY>_TijW)x$|nBi1h)8fAA*r|$B z5Pu|>!V=sQq%3nUWt4@n=2a_RY`n-VPb6b*DOKTa%2XKnv9S?j^a|O^%)WoIYFQ-k z$~-kfM`4#tTL@{|C6cZS=}|0_XNE5iXHo^R9{V{2#-J}cRcVM@rX?8Sjx421k{2wI z-jLjNg-qX(4!wL+c*$)WrJ}VISa*F}M;|US1T2Ra7|u70n*8gwmk?87`Wa3dmg9*C-c^D7 zFhJOiT&KBLrcyM-bquPcf@@-PQTVOpl8DM3LQ;XI7}^i1G^D9jrY|J-9m#O+knhZ% zoB&2J8piv$%+PsMui*-VMr@rE_kaBeK16#MW5`goHVLT3`>0J6An!!!qN!5A#Eh8;<}j}mcj#PFH!u)CTJEtOSbxBxx|St! zBoZ)Wj&b~-P8eeez$}_PZ;AQ|KROTh@U@zUZx}8#z!$2vZ&t+A zeM7ivvNU|RPyVLP+^CvXL2ZKX8TzNBbYyg+EbORaI;o@X!Bjf6RAnERF=+$>eOC%OUDW-w7m}IbH1s5 zhd4b+YnHm4rL8(wt>lGVQtp9EI7tLmKVlO?^f3HDr`HIQ2KX&e!|5l`o}>HOHhOZo z>=xeKMqh4rD49!aAzH&bHN3Zt!QAaFkn!*fe84c9e1VS`9%Gz7u75G)=4$w~bFzk+ z$2+f6^xYAzVKz4&sNsuWcm7KB28KxbB`IpiEkE7)Bk>&HKFdBuC`stAwy~1i2G1o{ zI*lz9YgnyeZDgR{}rT%7+Bt3;T+QP(koWLXc zCK8kM1ls-qP)i30T?r=oZ}tNK0QLrx(G?t%tCCTFTcB1zlqZ!0#k7KfkdSS=y&hce zn!76`8u=i82484mW8w=xfFH^@+q=`!9=6HN?9Tr;yF0V{>-UeJ0FZ%A0-r7~^SKXV zk(SPwS{9eZQbn8-OIociE7X)VHCfZj4Ci&GFlsOiR;iIJRaxoGXw(dGxk43#&53m> zS)=uTq|9>^v)ObhvxHhb=kS$=qTqy4rO7l7nJURDW4f$LID5`?1J}a&-2B3PE?H*h z;zu740{(*5&`a#OtS|ymO_x%VPRj~QUFfu4XL{-O9v0OB=uyFEst^tz2VT!z4g<2#lRmMJ`j5ZM7xZ*AM>%2rvSpe(=Ig+{%mm`qu9D$$nuwfAVtg)wU1D1@Oa-0qBDX0)tL} zsrdd3AKVr|u!4652w2`d0fsD36d(v8?%fw448z=eKw!vV=GK+cg<@B0$2aAJ0j^IF z7?!T;tpbe1;%>zpHr&Lcv2JbrpgXly(as#!?0ARvZ(9Tyw9dPLBI6nnUO(iIoc8&R z_JI|#ma!w&AcT?E9qq-QVS__Pcf=Ea+u?_rKX*`?w+8~YR z^5P4}7sOkF9^v<)Wd+*~+BRU@A=_f}TNYc7Hi#bHH2iMhXaTblw9&-j;qmcz7z^KO zLL_{r36tEL;@)&98f?OhrwP%oz<(i#LEKIdh93L_^e1MUFzdwUAZf=#X!!zWeTi=n z`C^CXA?1cg9Q>gxKI!0TcYM;pGp_iegD<(`iw>T3#itznkvl%+;5k=(+QA>Y9v3?#|5p?&G^NcjljeZ~g^f18y^%J9)Cd^>|=N zijQzL5oimxJIZx~e9?Ss^Ty`Z zaDtBpPPoAsJW(yH$N4T<;S2#yPeoF?lu&qNOqVhlu1EGea_2aYXH89ap^|@L(Gh7> ziYStriu4X0;c?T2YBH74HPSR?ZZItAvUReitVH^z=C?2`C}=rO7dV=-77=68sE%uD zQcf{6cFi77hpm&o07Yne+0~cxtd5_*)sP&)@ zHC}ize=e%9#0xj(imzo}crbrYe63*c7RTYjDhiU1%Z6##t_Qui5BGbp8h+wH(WFEn zJTC%R=pic)GR)Vxl-NNqUE8ZG40R2ST?P81rl{~1FV5^e_8Pg(x$FW_6(mpMLKFJ(* zW5>({#DW*QoCKbj>CJyx?{us_MShE|Mu(*hn_8mTv>ROv%chy0TJ@sGvER$E`JN~l zoQ0D;f|Gu7Wz6bozzKCPos?s8CQ8kPJJs7yy@Vnhlrv7zVopqhG;I`3KjYvJ7U3Q8 z4o~47P9z6EG=+Dj6AqqAR72W5+#J*NkpVf)wXA6$(M~T?7#4pzGDBrUr>GEi zFyui0#Il7feTyMnkzrLN9=k=`_CN6Ie zzr4J@x_~MF!ZH07B1P5dwMerC-8)peeldTHiFmtYw~FezE_um2lAh)(G@j}3 z0!Pn8|GYWq|D%=5GOF(N?!wRmr@znXHvHk+@}b(3#@WpG zkVVaQ!w2@M`A`6i61n>$ zUwnAGnIh+VCyDh%ctls6YsySKbLgXY z#MN4E^`xoW>mPP~4KZ=8)o)S%7?r`a{9VlAD@+;3Q}=Z8eYv%XpFOvdLwQ?B!I^2t z3r|g3{xaS}Ahgj&lS5EdRAu_zLo*}FgEcG~%bmsSwiUdSI$2!qkuR5doylzDmjfpi ze+Twjszf(k-*~6|-l6dFhrGYeZT33#ZB@q{v9NdRgdQH>rBze^eDTzSE8fpmJC(>J z{!U=hL;qjjCrp+46_?|^>sax(zdKLdIkGFah%3t-0*m7j%9?wb?G zIW3d#O*QbWwJDRo&T*1uI>d5c3D^-U0AfQ1;ISxh@QsgQa-x9rP&s<7O2XC?~wuq z;5nd5BNSEBv>{INS*RtAeB+NjimEk}CoYU;1>c)7`Qt)S=4l2XU5db)fcU||2R;TL z=-r3x=)u3llwq=fl_KzR4Twtkaqd9Z=%CnPYXwqi1~w0Vo;A=+R9}6zW|(YXF9kdR z-dGxOt}<{s5yh;y$$g7sSs};sepoEZ9P7w1S>MrPvcd{MY4`!L3=H}xnx;5UZd@ih zxzbq``QegS8RR1ZO;8Nd@&p@{ztl&00 z;INSaoeOgl7%rQDv80Ql*fI>LSbDO>GF@rJ76;%7K`4sKCO0f|llFrzcw%5sLXrP7 z`Qb7<8RX?SsFqk&fn5}^+*k%N0?ELjfMN(|4Or2JYB5kCv4TgHCf{E!$`siRmRR2< z3X+h4kDmbjgPI{<_ktBV^vZx0#=^T$3=DcGR^{}A6k?9LfNhomH$#B|6#&eSsQx%U o8Ek>-N@E#tp#oHJl!t*q1I2Ku>0m{jE48=;c!3#XE~r=m0855eHUIzs delta 34912 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

Gn4F+B~IivciU9^t0j-Mgao3 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 dDuazZG^u*-) zCV{{p$D*4m=Z;!QJ0C3EBfaUv#@3CmRgS-#a4+Uk9LtR(mzdSt-?*B-Q{Jgs!F;+_ zT&Jc~{N951OskjVtnWOLnfUacmSEkQ#fQojqa=HN?aN#ubFA){K&TrfoSnBphJ<43S zS5?OUrqPYpEqf;(zc;IIty0d`-n-Ke%PlArJt^DN>ZYW)ZS5z$Rnx=cxbM1#zPRNS1N0u>c z*gpBeTvyKAjdr#Uz%$J3C+p2~l9`-P6`=_1Y83#nAp`Kd5jfb*H#u;=%w#=&g~|Q% z1!N9S7n+#|tj#t98*^$X3S9)i3I*n?N+YghXJ9Z!QN%wvV7|W$;;Lx|1{)Ol%c4L- zlz|txtAK4ozLL`xMPZR7Sm6grRj@+Db&BXF9#sG|gMywm=IO1O01imHv3 zFjX9ri>su;HX}wK85k5$R0A&?fdtA5_Q_vX$jc(elo%M~QB>A-K~#2igOjH$d^80Z zC8#NjzZarXrcVZJJEF73z+ix4=7c`5N>TJt7>~rfl$^E}UAMlP2$P)vS26{cE?ONf_&Vd@-E2?PMU+S~pB diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index a4413138c..d4081da47 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.8-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.14.3-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME diff --git a/gradlew b/gradlew index b740cf133..23d15a936 100755 --- a/gradlew +++ b/gradlew @@ -15,6 +15,8 @@ # See the License for the specific language governing permissions and # limitations under the License. # +# SPDX-License-Identifier: Apache-2.0 +# ############################################################################## # @@ -84,7 +86,7 @@ done # shellcheck disable=SC2034 APP_BASE_NAME=${0##*/} # Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) -APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit +APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD=maximum @@ -112,7 +114,7 @@ case "$( uname )" in #( NONSTOP* ) nonstop=true ;; esac -CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar +CLASSPATH="\\\"\\\"" # Determine the Java command to use to start the JVM. @@ -203,7 +205,7 @@ fi DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' # Collect all arguments for the java command: -# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, # and any embedded shellness will be escaped. # * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be # treated as '${Hostname}' itself on the command line. @@ -211,7 +213,7 @@ DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' set -- \ "-Dorg.gradle.appname=$APP_BASE_NAME" \ -classpath "$CLASSPATH" \ - org.gradle.wrapper.GradleWrapperMain \ + -jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \ "$@" # Stop when "xargs" is not available. diff --git a/gradlew.bat b/gradlew.bat index 7101f8e46..5eed7ee84 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -13,6 +13,8 @@ @rem See the License for the specific language governing permissions and @rem limitations under the License. @rem +@rem SPDX-License-Identifier: Apache-2.0 +@rem @if "%DEBUG%"=="" @echo off @rem ########################################################################## @@ -68,11 +70,11 @@ goto fail :execute @rem Setup the command line -set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar +set CLASSPATH= @rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %* :end @rem End local scope for the variables with windows NT shell diff --git a/settings.gradle b/settings.gradle index 806003fdf..ba34972aa 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1,3 +1,7 @@ +plugins { + id 'org.gradle.toolchains.foojay-resolver-convention' version '0.10.0' +} + rootProject.name = 'archie' include 'base', 'aom', 'grammars', 'tools', 'odin', 'openehr-rm', 'archie-utils' From c8f059b8d940a289c72292ebeea600aec66ce897 Mon Sep 17 00:00:00 2001 From: Jelte Zeilstra Date: Tue, 16 Sep 2025 11:27:37 +0200 Subject: [PATCH 13/25] Use Gradle Version Catalog (#716) * Use Version Catalog for main build.gradle file * Use Version Catalog for grammars build.gradle file * Use Version Catalog for tools build.gradle file * Remove non-working exclusion of commons-logging commons-logging is not a dependency of commons-io, so this exclude does nothing. --- build.gradle | 48 +++++++++++++---------------------- gradle/libs.versions.toml | 53 +++++++++++++++++++++++++++++++++++++++ grammars/build.gradle | 6 ++--- tools/build.gradle | 4 +-- 4 files changed, 74 insertions(+), 37 deletions(-) create mode 100644 gradle/libs.versions.toml diff --git a/build.gradle b/build.gradle index 347493351..7c3b9e39c 100644 --- a/build.gradle +++ b/build.gradle @@ -1,5 +1,5 @@ plugins { - id("io.github.gradle-nexus.publish-plugin") version "2.0.0" + alias(libs.plugins.nexus.publish) } repositories { @@ -30,10 +30,6 @@ apply from: "${gradleScriptDir}/publish-maven.gradle" subprojects { apply plugin: 'java-library' - // plugins { - // id 'com.github.ben-manes.versions' version '0.13.0' - // } - compileJava.options.encoding = "UTF-8" compileTestJava.options.encoding = "UTF-8" @@ -42,10 +38,6 @@ subprojects { maven { url = 'https://jitpack.io' } } - ext.reflectionsVersion = '0.10.2' - ext.jacksonVersion = '2.19.2' - - java { toolchain { languageVersion = JavaLanguageVersion.of(8) @@ -57,37 +49,31 @@ subprojects { dependencies { - api 'org.slf4j:slf4j-api:1.7.36' + api(libs.slf4j.api) - api "com.fasterxml.jackson.core:jackson-annotations:${jacksonVersion}" - api "com.fasterxml.jackson.core:jackson-databind:${jacksonVersion}" - api "com.fasterxml.jackson.datatype:jackson-datatype-jsr310:${jacksonVersion}" + api(libs.bundles.jackson) - implementation 'com.google.guava:guava:33.4.8-jre' + implementation(libs.guava) - implementation "org.reflections:reflections:${reflectionsVersion}" - implementation 'com.esotericsoftware.kryo:kryo5:5.6.2' + implementation(libs.reflections) + implementation(libs.kryo) - implementation('commons-io:commons-io:2.20.0'){ - exclude group: 'commons-logging', module: 'commons-logging' - } - implementation 'org.apache.commons:commons-text:1.14.0' - implementation 'org.apache.commons:commons-lang3:3.18.0' + implementation(libs.commons.io) + implementation(libs.commons.text) + implementation(libs.commons.lang3) //java 10 no longer has these included by default, so explicit dependency is needed. - api 'javax.xml.bind:jaxb-api:2.3.1' - api 'com.sun.xml.bind:jaxb-core:2.3.0.1' - runtimeOnly 'com.sun.xml.bind:jaxb-impl:2.3.9' - api 'javax.activation:activation:1.1.1' - - api 'org.threeten:threeten-extra:1.8.0' - - testImplementation 'junit:junit:4.+' - testImplementation 'org.slf4j:slf4j-simple:1.7.36' + api(libs.jaxb.api) + api(libs.jaxb.core) + runtimeOnly(libs.jaxb.impl) + api(libs.activation) - api 'com.github.zafarkhaja:java-semver:0.10.2' + api(libs.threeten.extra) + testImplementation(libs.junit4) + testImplementation(libs.slf4j.simple) + api(libs.zafarkhaja.semver) } diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml new file mode 100644 index 000000000..e958d1d6f --- /dev/null +++ b/gradle/libs.versions.toml @@ -0,0 +1,53 @@ +[versions] +antlr = "4.13.2" + +jackson = "2.19.2" + +slf4j = "1.7.36" + +[plugins] +nexus-publish = { id = "io.github.gradle-nexus.publish-plugin", version = "2.0.0" } + +[bundles] +jackson = ["jackson-annotations", "jackson-databind", "jackson-datatype-jsr310"] + +[libraries] +activation = { module = "javax.activation:activation", version = "1.1.1" } + +antlr4 = { module = "org.antlr:antlr4", version.ref = "antlr" } +antlr4-runtime = { module = "org.antlr:antlr4-runtime", version.ref = "antlr" } + +commons-io = { module = "commons-io:commons-io", version = "2.20.0" } + +commons-lang3 = { module = "org.apache.commons:commons-lang3", version = "3.18.0" } + +commons-text = { module = "org.apache.commons:commons-text", version = "1.14.0" } + +guava = { module = "com.google.guava:guava", version = "33.4.8-jre" } + +jackson-annotations = { module = "com.fasterxml.jackson.core:jackson-annotations", version.ref = "jackson" } +jackson-databind = { module = "com.fasterxml.jackson.core:jackson-databind", version.ref = "jackson" } +jackson-datatype-jsr310 = { module = "com.fasterxml.jackson.datatype:jackson-datatype-jsr310", version.ref = "jackson" } + +jakarta-json = { module = "org.glassfish:jakarta.json", version = "2.0.1" } + +jaxb-api = { module = "javax.xml.bind:jaxb-api", version = "2.3.1" } + +jaxb-core = { module = "com.sun.xml.bind:jaxb-core", version = "2.3.0.1" } + +jaxb-impl = { module = "com.sun.xml.bind:jaxb-impl", version = "2.3.9" } + +junit4 = { module = "junit:junit", version = "4.+" } + +kryo = { module = "com.esotericsoftware.kryo:kryo5", version = "5.6.2" } + +leadpony-justify = { module = "org.leadpony.justify:justify", version = "3.1.0" } + +reflections = { module = "org.reflections:reflections", version = "0.10.2" } + +slf4j-api = { module = "org.slf4j:slf4j-api", version.ref = "slf4j" } +slf4j-simple = { module = "org.slf4j:slf4j-simple", version.ref = "slf4j" } + +threeten-extra = { module = "org.threeten:threeten-extra", version = "1.8.0" } + +zafarkhaja-semver = { module = "com.github.zafarkhaja:java-semver", version = "0.10.2" } diff --git a/grammars/build.gradle b/grammars/build.gradle index dd44333be..fbe1f5185 100644 --- a/grammars/build.gradle +++ b/grammars/build.gradle @@ -1,8 +1,6 @@ description = "grammars for parsing ADL, ODIN and xpath" apply plugin: 'antlr' -ext.antlrVersion = '4.13.2' - generateGrammarSource { //antlr4 outputDirectory = new File("${project.buildDir}/generated-src/antlr/main/com/nedap/archie/adlparser/antlr".toString()) arguments = ['-visitor', '-package', 'com.nedap.archie.adlparser.antlr', '-encoding', 'utf-8'] + arguments @@ -18,6 +16,6 @@ classes { dependencies { - antlr "org.antlr:antlr4:${antlrVersion}" - api "org.antlr:antlr4-runtime:${antlrVersion}" + antlr(libs.antlr4) + api(libs.antlr4.runtime) } diff --git a/tools/build.gradle b/tools/build.gradle index 615f06c8a..69b9f1c73 100644 --- a/tools/build.gradle +++ b/tools/build.gradle @@ -14,6 +14,6 @@ dependencies { testImplementation project(':test-rm') testImplementation project(':referencemodels') - api 'org.leadpony.justify:justify:3.1.0' - api 'org.glassfish:jakarta.json:2.0.1:module' + api(libs.leadpony.justify) + api(variantOf(libs.jakarta.json) {classifier("module") }) } From 8566fd37c30006c2475ca20164f8ba6ac249cba2 Mon Sep 17 00:00:00 2001 From: Jelte Zeilstra Date: Thu, 18 Sep 2025 10:22:23 +0200 Subject: [PATCH 14/25] Don't include exception information in validation errors (#719) * Improve exception handling in ArchetypeValidator * Improve exception handling in RMObjectValidator --- i18n/po/i18n_en.po | 125 +++++++++--------- i18n/po/i18n_nl.po | 125 +++++++++--------- i18n/po/keys.pot | 125 +++++++++--------- .../ArchetypeValidator.java | 14 +- .../rmobjectvalidator/RMObjectValidator.java | 11 +- 5 files changed, 198 insertions(+), 202 deletions(-) diff --git a/i18n/po/i18n_en.po b/i18n/po/i18n_en.po index 40eb0a4b1..8e0c8d573 100644 --- a/i18n/po/i18n_en.po +++ b/i18n/po/i18n_en.po @@ -2,7 +2,7 @@ msgid "" msgstr "" "Project-Id-Version: \n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-12-11 10:35+0100\n" +"POT-Creation-Date: 2025-09-17 15:14+0200\n" "PO-Revision-Date: \n" "Last-Translator: Pieter Bos \n" "Language-Team: \n" @@ -65,12 +65,12 @@ msgstr "" msgid "An object with the new node id {0} cannot be prohibited" msgstr "" -#: ../tools/src/main/java/com/nedap/archie/archetypevalidator/validations/VariousStructureValidation.java:65 +#: ../tools/src/main/java/com/nedap/archie/archetypevalidator/validations/VariousStructureValidation.java:60 #, java-format msgid "Archetype referenced in use_archetype points to class {0}, which does not exist in this reference model" msgstr "" -#: ../tools/src/main/java/com/nedap/archie/archetypevalidator/validations/VariousStructureValidation.java:75 +#: ../tools/src/main/java/com/nedap/archie/archetypevalidator/validations/VariousStructureValidation.java:70 msgid "Archetype root must have an archetype reference or be prohibited (occurrences matches 0)" msgstr "" @@ -86,7 +86,7 @@ msgstr "" msgid "Archetype terminology not defined" msgstr "" -#: ../tools/src/main/java/com/nedap/archie/archetypevalidator/validations/VariousStructureValidation.java:54 +#: ../tools/src/main/java/com/nedap/archie/archetypevalidator/validations/VariousStructureValidation.java:49 #, java-format msgid "Archetype with id {0} used in use_archetype, but it was not found" msgstr "" @@ -136,13 +136,13 @@ msgstr "" msgid "Attribute {0} of class {1} does not match existence {2}" msgstr "" -#: ../tools/src/main/java/com/nedap/archie/archetypevalidator/validations/ValidateAgainstReferenceModel.java:70 -#: ../tools/src/main/java/com/nedap/archie/archetypevalidator/validations/ValidateAgainstReferenceModel.java:82 +#: ../tools/src/main/java/com/nedap/archie/archetypevalidator/validations/ValidateAgainstReferenceModel.java:63 +#: ../tools/src/main/java/com/nedap/archie/archetypevalidator/validations/ValidateAgainstReferenceModel.java:75 #, java-format msgid "Attribute {0}.{1} cannot be constrained by a {2}" msgstr "" -#: ../tools/src/main/java/com/nedap/archie/archetypevalidator/validations/ValidateAgainstReferenceModel.java:48 +#: ../tools/src/main/java/com/nedap/archie/archetypevalidator/validations/ValidateAgainstReferenceModel.java:41 #, java-format msgid "Attribute {0}.{1} cannot contain type {2}" msgstr "" @@ -190,7 +190,7 @@ msgstr "" msgid "Code {0} from the C_TERMINOLOGY_CODE constraint is not defined in the terminology" msgstr "" -#: ../tools/src/main/java/com/nedap/archie/archetypevalidator/validations/BasicTerminologyValidation.java:161 +#: ../tools/src/main/java/com/nedap/archie/archetypevalidator/validations/BasicTerminologyValidation.java:164 #, java-format msgid "Code {0} is in the terminology, but not used in the archetype" msgstr "" @@ -242,30 +242,23 @@ msgstr "" msgid "Error" msgstr "" -#: ../tools/src/main/java/com/nedap/archie/archetypevalidator/ArchetypeValidator.java:153 +#: ../tools/src/main/java/com/nedap/archie/archetypevalidator/ArchetypeValidator.java:156 #, java-format msgid "Error in parent archetype. Fix those errors before continuing with this archetype: {0}" msgstr "" -#: ../tools/src/main/java/com/nedap/archie/rmobjectvalidator/RMObjectValidator.java:130 -#, java-format -msgid "" -"Exception {0} invoking invariant {1} on {2}: {3}\n" -"{4}" -msgstr "" - -#: ../tools/src/main/java/com/nedap/archie/archetypevalidator/validations/BasicTerminologyValidation.java:39 +#: ../tools/src/main/java/com/nedap/archie/archetypevalidator/validations/BasicTerminologyValidation.java:42 #, java-format msgid "Id code {0} in terminology is not a valid term code, should be id, ac or at, followed by digits" msgstr "" -#: ../tools/src/main/java/com/nedap/archie/archetypevalidator/validations/BasicTerminologyValidation.java:43 -#: ../tools/src/main/java/com/nedap/archie/archetypevalidator/validations/BasicTerminologyValidation.java:47 +#: ../tools/src/main/java/com/nedap/archie/archetypevalidator/validations/BasicTerminologyValidation.java:46 +#: ../tools/src/main/java/com/nedap/archie/archetypevalidator/validations/BasicTerminologyValidation.java:50 #, java-format msgid "Id code {0} in terminology is of a different specialization depth than the archetype" msgstr "" -#: ../tools/src/main/java/com/nedap/archie/archetypevalidator/validations/AttributeTupleValidation.java:38 +#: ../tools/src/main/java/com/nedap/archie/archetypevalidator/validations/AttributeTupleValidation.java:36 #, java-format msgid "In the attribute tuple {0} members were specified, but the primitive tuple has {1} members instead" msgstr "" @@ -275,7 +268,7 @@ msgstr "" msgid "Incorrect root node id {0}: it must match the specialization depth of the archetype, which is {1}" msgstr "" -#: ../tools/src/main/java/com/nedap/archie/rmobjectvalidator/RMObjectValidator.java:125 +#: ../tools/src/main/java/com/nedap/archie/rmobjectvalidator/RMObjectValidator.java:168 #, java-format msgid "Invariant {0} failed on type " msgstr "" @@ -314,7 +307,7 @@ msgstr "" msgid "No Reference Model schema found for package ''{0}''" msgstr "" -#: ../aom/src/main/java/com/nedap/archie/aom/primitives/CString.java:112 +#: ../aom/src/main/java/com/nedap/archie/aom/primitives/CString.java:114 #, java-format msgid "No matching constraint found in parent for contraint {0}" msgstr "" @@ -328,7 +321,7 @@ msgstr "" msgid "Node id numbers should be unique without their ac, at or id-prefix, to ensure the possibility of converting the archetype to ADL 1.4" msgstr "" -#: ../tools/src/main/java/com/nedap/archie/archetypevalidator/validations/BasicTerminologyValidation.java:175 +#: ../tools/src/main/java/com/nedap/archie/archetypevalidator/validations/BasicTerminologyValidation.java:178 #, java-format msgid "Node id {0} already used in archetype as {1} with a different at, id or ac prefix. The archetype will not be convertible to ADL 1.4" msgstr "" @@ -338,7 +331,7 @@ msgstr "" msgid "Node id {0} already used in path {1}" msgstr "" -#: ../aom/src/main/java/com/nedap/archie/aom/CObject.java:281 +#: ../aom/src/main/java/com/nedap/archie/aom/CObject.java:282 #, java-format msgid "Node id {0} does not conform to {1}" msgstr "" @@ -373,7 +366,7 @@ msgstr "" msgid "Object with node id {0} should be specialized before excluding the parent node" msgstr "" -#: ../aom/src/main/java/com/nedap/archie/aom/CPrimitiveObject.java:127 +#: ../aom/src/main/java/com/nedap/archie/aom/CPrimitiveObject.java:129 #, java-format msgid "Occurrences {0} does not conform to {1}" msgstr "" @@ -694,7 +687,7 @@ msgstr "" msgid "Sibling order {0} refers to missing node id" msgstr "" -#: ../tools/src/main/java/com/nedap/archie/archetypevalidator/validations/ValidateAgainstReferenceModel.java:151 +#: ../tools/src/main/java/com/nedap/archie/archetypevalidator/validations/ValidateAgainstReferenceModel.java:144 msgid "Single valued attributes can not have a cardinality" msgstr "" @@ -715,27 +708,27 @@ msgstr "" msgid "Syntax error: terminology not specified" msgstr "" -#: ../tools/src/main/java/com/nedap/archie/archetypevalidator/ArchetypeValidator.java:199 +#: ../tools/src/main/java/com/nedap/archie/archetypevalidator/ArchetypeValidator.java:202 #, java-format msgid "Template overlay {0} had validation errors" msgstr "" -#: ../tools/src/main/java/com/nedap/archie/archetypevalidator/validations/BasicTerminologyValidation.java:83 +#: ../tools/src/main/java/com/nedap/archie/archetypevalidator/validations/BasicTerminologyValidation.java:86 #, java-format msgid "Term binding key {0} in path format is not present in archetype" msgstr "" -#: ../tools/src/main/java/com/nedap/archie/archetypevalidator/validations/BasicTerminologyValidation.java:88 +#: ../tools/src/main/java/com/nedap/archie/archetypevalidator/validations/BasicTerminologyValidation.java:91 #, java-format msgid "Term binding key {0} is not present in terminology" msgstr "" -#: ../tools/src/main/java/com/nedap/archie/archetypevalidator/validations/FlatFormValidation.java:88 +#: ../tools/src/main/java/com/nedap/archie/archetypevalidator/validations/FlatFormValidation.java:91 #, java-format msgid "Term binding key {0} is not present in the terminology" msgstr "" -#: ../tools/src/main/java/com/nedap/archie/archetypevalidator/validations/FlatFormValidation.java:81 +#: ../tools/src/main/java/com/nedap/archie/archetypevalidator/validations/FlatFormValidation.java:84 #, java-format msgid "Term binding key {0} points to a path that cannot be found in the archetype" msgstr "" @@ -758,7 +751,7 @@ msgstr "" msgid "The attribute cardinality interval has lower > upper, this is not allowed" msgstr "" -#: ../tools/src/main/java/com/nedap/archie/archetypevalidator/validations/FlatFormValidation.java:55 +#: ../tools/src/main/java/com/nedap/archie/archetypevalidator/validations/FlatFormValidation.java:58 #, java-format msgid "The attribute contains {0} objects that are required, but only has an upper cardinality of {1}" msgstr "" @@ -768,12 +761,12 @@ msgstr "" msgid "The attribute {0} of type {1} can only have a single value, but the occurrences of the C_OBJECTS below has an upper limit of more than 1" msgstr "" -#: ../tools/src/main/java/com/nedap/archie/archetypevalidator/validations/ValidateAgainstReferenceModel.java:135 +#: ../tools/src/main/java/com/nedap/archie/archetypevalidator/validations/ValidateAgainstReferenceModel.java:128 #, java-format msgid "The cardinality of Attribute {0}.{1} is the same as in the reference model - this is not allowed due to strict multiplicities validation being enabled" msgstr "" -#: ../tools/src/main/java/com/nedap/archie/archetypevalidator/validations/ValidateAgainstReferenceModel.java:143 +#: ../tools/src/main/java/com/nedap/archie/archetypevalidator/validations/ValidateAgainstReferenceModel.java:136 #, java-format msgid "The cardinality {0} of attribute {2}.{3} does not match cardinality {1} of the reference model" msgstr "" @@ -793,12 +786,12 @@ msgstr "" msgid "The constraint interval for this {0} has lower > upper, this is not allowed" msgstr "" -#: ../tools/src/main/java/com/nedap/archie/archetypevalidator/validations/ValidateAgainstReferenceModel.java:116 +#: ../tools/src/main/java/com/nedap/archie/archetypevalidator/validations/ValidateAgainstReferenceModel.java:109 #, java-format msgid "The existence of attribute {0}.{1} is the same as in the reference model - this is not allowed due to strict existence validation being enabled" msgstr "" -#: ../tools/src/main/java/com/nedap/archie/archetypevalidator/validations/ValidateAgainstReferenceModel.java:124 +#: ../tools/src/main/java/com/nedap/archie/archetypevalidator/validations/ValidateAgainstReferenceModel.java:117 #, java-format msgid "The existence {0} of attribute {2}.{3} does not match existence {1} of the reference model" msgstr "" @@ -816,7 +809,7 @@ msgstr "" msgid "The occurrences interval has lower > upper, this is not allowed" msgstr "" -#: ../tools/src/main/java/com/nedap/archie/archetypevalidator/validations/FlatFormValidation.java:52 +#: ../tools/src/main/java/com/nedap/archie/archetypevalidator/validations/FlatFormValidation.java:55 #, java-format msgid "The occurrences of all C_OBJECTS under this attributes is at least {0}, which does not fit in the upper limit of the cardinality of the attribute, {1}" msgstr "" @@ -836,12 +829,12 @@ msgstr "" msgid "The path {0} referenced in the rm visibility does not exist in the flat archetype" msgstr "" -#: ../aom/src/main/java/com/nedap/archie/aom/CPrimitiveObject.java:134 +#: ../aom/src/main/java/com/nedap/archie/aom/CPrimitiveObject.java:136 #, java-format msgid "The primitive object of type {0} does not conform null" msgstr "" -#: ../aom/src/main/java/com/nedap/archie/aom/CPrimitiveObject.java:136 +#: ../aom/src/main/java/com/nedap/archie/aom/CPrimitiveObject.java:138 #, java-format msgid "The primitive object of type {0} does not conform to non-primitive object with type {1}" msgstr "" @@ -887,16 +880,21 @@ msgstr "" msgid "Translation details language {0} has an incorrect key: {1}" msgstr "" -#: ../tools/src/main/java/com/nedap/archie/archetypevalidator/validations/AttributeTupleValidation.java:32 +#: ../tools/src/main/java/com/nedap/archie/archetypevalidator/validations/AttributeTupleValidation.java:30 #, java-format msgid "Tuple member attribute {0} is not an attribute of type {1}" msgstr "" -#: ../tools/src/main/java/com/nedap/archie/archetypevalidator/validations/ValidateAgainstReferenceModel.java:35 +#: ../tools/src/main/java/com/nedap/archie/archetypevalidator/validations/ValidateAgainstReferenceModel.java:28 #, java-format msgid "Type name {0} does not exist" msgstr "" +#: ../tools/src/main/java/com/nedap/archie/rmobjectvalidator/RMObjectValidator.java:173 +#, java-format +msgid "Unexpected error validating invariant {0} on {1}" +msgstr "" + #: ../bmm/src/main/java/org/openehr/bmm/persistence/validation/BmmMessageIds.java:54 #, java-format msgid "Unknown Reference Model ''{0}'' mentioned in ''rm_schemas_load_list'' config setting (ignored)" @@ -910,7 +908,7 @@ msgstr "" msgid "Unknown exception processing RM schemas" msgstr "" -#: ../tools/src/main/java/com/nedap/archie/archetypevalidator/validations/VariousStructureValidation.java:68 +#: ../tools/src/main/java/com/nedap/archie/archetypevalidator/validations/VariousStructureValidation.java:63 #, java-format msgid "Use_archetype points to type {0}, which is not conformant for type {1} of the archetype root used" msgstr "" @@ -931,21 +929,21 @@ msgstr "" msgid "Use_archetype {0} does not match the expression of the archetype slot it specialized in the parent" msgstr "" -#: ../tools/src/main/java/com/nedap/archie/archetypevalidator/validations/FlatFormValidation.java:42 +#: ../tools/src/main/java/com/nedap/archie/archetypevalidator/validations/FlatFormValidation.java:45 #, java-format msgid "Use_node (C_COMPLEX_OBJECT_PROXY) must point to a C_COMPLEX_OBJECT, but points to a {0}" msgstr "" -#: ../tools/src/main/java/com/nedap/archie/archetypevalidator/validations/FlatFormValidation.java:24 +#: ../tools/src/main/java/com/nedap/archie/archetypevalidator/validations/FlatFormValidation.java:27 #, java-format msgid "Use_node (C_COMPLEX_OBJECT_PROXY) points to a path that cannot be found: {0}" msgstr "" -#: ../tools/src/main/java/com/nedap/archie/archetypevalidator/validations/FlatFormValidation.java:26 +#: ../tools/src/main/java/com/nedap/archie/archetypevalidator/validations/FlatFormValidation.java:29 msgid "Use_node (C_COMPLEX_OBJECT_PROXY) points to a path that resolves to more than one object" msgstr "" -#: ../tools/src/main/java/com/nedap/archie/archetypevalidator/validations/FlatFormValidation.java:36 +#: ../tools/src/main/java/com/nedap/archie/archetypevalidator/validations/FlatFormValidation.java:39 #, java-format msgid "Use_node (C_COMPLEX_OBJECT_PROXY) points to type {0}, which does not conform to type {1}" msgstr "" @@ -1041,22 +1039,22 @@ msgstr "" msgid "cardinality/occurrences upper bound validity: where a cardinality with a finite upper bound is stated on an attribute, for all immediate child objects for which an occurrences constraint is stated, the occurrences must either have an open upper bound (i.e. n..*) which is interpreted as the maximum value allowed within the cardinality, or else a finite upper bound which is ⇐ the cardinality upper bound." msgstr "" -#: ../aom/src/main/java/com/nedap/archie/aom/primitives/CTerminologyCode.java:234 +#: ../aom/src/main/java/com/nedap/archie/aom/primitives/CTerminologyCode.java:235 #, java-format msgid "child CTerminology code contains more than one constraint, that is not valid. Constraints are: {0}" msgstr "" -#: ../aom/src/main/java/com/nedap/archie/aom/primitives/CTerminologyCode.java:279 +#: ../aom/src/main/java/com/nedap/archie/aom/primitives/CTerminologyCode.java:280 #, java-format msgid "child terminology constraint value code {0} does not conform to parent constraint with value code {1}" msgstr "" -#: ../aom/src/main/java/com/nedap/archie/aom/primitives/CTerminologyCode.java:263 +#: ../aom/src/main/java/com/nedap/archie/aom/primitives/CTerminologyCode.java:264 #, java-format msgid "child terminology constraint value code {0} is not contained in {1}, or a direct specialization of one of its values" msgstr "" -#: ../aom/src/main/java/com/nedap/archie/aom/primitives/CTerminologyCode.java:259 +#: ../aom/src/main/java/com/nedap/archie/aom/primitives/CTerminologyCode.java:260 #, java-format msgid "child terminology constraint value set code {0} does not conform to parent constraint with value set code {1}" msgstr "" @@ -1069,7 +1067,8 @@ msgstr "" msgid "constraint code validity. Each value set code (ac-code) used in a term constraint in the archetype definition must be defined in the term_definitions part of the terminology of the current archetype." msgstr "" -#: ../tools/src/main/java/com/nedap/archie/rmobjectvalidator/validations/RMPrimitiveObjectValidation.java:59 +#: ../tools/src/main/java/com/nedap/archie/rmobjectvalidator/RmPrimitiveObjectValidator.java:60 +#: ../tools/src/main/java/com/nedap/archie/rmobjectvalidator/validations/RMPrimitiveObjectValidation.java:71 msgid "empty" msgstr "" @@ -1136,7 +1135,7 @@ msgstr "" msgid "original language specified. An original_language section containing the meta-data of the original authoring language must exist." msgstr "" -#: ../aom/src/main/java/com/nedap/archie/aom/primitives/CTerminologyCode.java:237 +#: ../aom/src/main/java/com/nedap/archie/aom/primitives/CTerminologyCode.java:238 #, java-format msgid "parent CTerminology code contains more than one constraint, that is not valid. Constraints are: {0}" msgstr "" @@ -1217,7 +1216,7 @@ msgstr "" msgid "specialised object node occurrences validity: the sum of the lower occurrences and the sum of the upper occurrences of all objects redefining a node in a specialised archetype, must be contained in the occurrences interval of the corresponding node in the flat parent archetype." msgstr "" -#: ../aom/src/main/java/com/nedap/archie/aom/primitives/CTerminologyCode.java:243 +#: ../aom/src/main/java/com/nedap/archie/aom/primitives/CTerminologyCode.java:244 #, java-format msgid "specialized CTerminology code constraint status {0} is wider more than parent contraint status {1}" msgstr "" @@ -1238,8 +1237,8 @@ msgstr "" msgid "translations key does not match translations item language" msgstr "" -#: ../aom/src/main/java/com/nedap/archie/aom/CPrimitiveObject.java:130 -#: ../aom/src/main/java/com/nedap/archie/aom/CObject.java:284 +#: ../aom/src/main/java/com/nedap/archie/aom/CPrimitiveObject.java:132 +#: ../aom/src/main/java/com/nedap/archie/aom/CObject.java:285 #, java-format msgid "type name {0} does not conform to {1}" msgstr "" @@ -1260,13 +1259,13 @@ msgstr "" msgid "value code validity. Each value code (at-code) used in a term constraint in the archetype definition must be defined in the term_definitions part of the terminology of the flattened form of the current archetype." msgstr "" -#: ../tools/src/main/java/com/nedap/archie/archetypevalidator/validations/BasicTerminologyValidation.java:140 +#: ../tools/src/main/java/com/nedap/archie/archetypevalidator/validations/BasicTerminologyValidation.java:143 #, java-format msgid "value code {0} is used in redefined value set {1}, but not present in its parent value set with members {2}" msgstr "" -#: ../tools/src/main/java/com/nedap/archie/archetypevalidator/validations/BasicTerminologyValidation.java:118 -#: ../tools/src/main/java/com/nedap/archie/archetypevalidator/validations/BasicTerminologyValidation.java:122 +#: ../tools/src/main/java/com/nedap/archie/archetypevalidator/validations/BasicTerminologyValidation.java:121 +#: ../tools/src/main/java/com/nedap/archie/archetypevalidator/validations/BasicTerminologyValidation.java:125 #, java-format msgid "value code {0} is used in value set {1}, but not present in terminology" msgstr "" @@ -1275,18 +1274,18 @@ msgstr "" msgid "value set assumed value code validity. Each value code (at-code) used as an assumed_value for a value set in a term constraint in the archetype definition must exist in the value set definition in the terminology for the identified value set." msgstr "" -#: ../tools/src/main/java/com/nedap/archie/archetypevalidator/validations/BasicTerminologyValidation.java:103 +#: ../tools/src/main/java/com/nedap/archie/archetypevalidator/validations/BasicTerminologyValidation.java:106 #, java-format msgid "value set code {0} is not present in terminology" msgstr "" -#: ../tools/src/main/java/com/nedap/archie/archetypevalidator/validations/BasicTerminologyValidation.java:109 -#: ../tools/src/main/java/com/nedap/archie/archetypevalidator/validations/BasicTerminologyValidation.java:113 +#: ../tools/src/main/java/com/nedap/archie/archetypevalidator/validations/BasicTerminologyValidation.java:112 +#: ../tools/src/main/java/com/nedap/archie/archetypevalidator/validations/BasicTerminologyValidation.java:116 #, java-format msgid "value set code {0} is used in value set {1}, but not present in terminology" msgstr "" -#: ../tools/src/main/java/com/nedap/archie/archetypevalidator/validations/BasicTerminologyValidation.java:135 +#: ../tools/src/main/java/com/nedap/archie/archetypevalidator/validations/BasicTerminologyValidation.java:138 #, java-format msgid "value set {0} has a specialized code, but the valueset it specialized cannot be found in the flat parent" msgstr "" @@ -1308,7 +1307,7 @@ msgstr "" msgid "{0} and {1}" msgstr "" -#: ../tools/src/main/java/com/nedap/archie/archetypevalidator/validations/ValidateAgainstReferenceModel.java:106 +#: ../tools/src/main/java/com/nedap/archie/archetypevalidator/validations/ValidateAgainstReferenceModel.java:99 #, java-format msgid "{0} is not a known attribute of {1}" msgstr "" diff --git a/i18n/po/i18n_nl.po b/i18n/po/i18n_nl.po index ddaffbefa..c1308e77b 100644 --- a/i18n/po/i18n_nl.po +++ b/i18n/po/i18n_nl.po @@ -2,7 +2,7 @@ msgid "" msgstr "" "Project-Id-Version: \n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-12-11 10:35+0100\n" +"POT-Creation-Date: 2025-09-17 15:14+0200\n" "PO-Revision-Date: \n" "Last-Translator: Pieter Bos \n" "Language-Team: \n" @@ -65,12 +65,12 @@ msgstr "Een archetype slot is gebruikt in het archetype, maar er is geen archety msgid "An object with the new node id {0} cannot be prohibited" msgstr "Een object met een nieuw node id {0} mag geen occurrences van maximaal 0 hebben" -#: ../tools/src/main/java/com/nedap/archie/archetypevalidator/validations/VariousStructureValidation.java:65 +#: ../tools/src/main/java/com/nedap/archie/archetypevalidator/validations/VariousStructureValidation.java:60 #, java-format msgid "Archetype referenced in use_archetype points to class {0}, which does not exist in this reference model" msgstr "Het archetype waarnaar use_archetype verwijst, verwijst naar klasse {0}. Deze klasse bestaat niet in het referentiemodel" -#: ../tools/src/main/java/com/nedap/archie/archetypevalidator/validations/VariousStructureValidation.java:75 +#: ../tools/src/main/java/com/nedap/archie/archetypevalidator/validations/VariousStructureValidation.java:70 msgid "Archetype root must have an archetype reference or be prohibited (occurrences matches 0)" msgstr "Use_archetype moet verwijzen naar een archetype, of beperkt zijn tot occurrences 0" @@ -86,7 +86,7 @@ msgstr "De terminologie van dit archetype bevat geen termdefinities" msgid "Archetype terminology not defined" msgstr "Archetype terminology ontbreekt" -#: ../tools/src/main/java/com/nedap/archie/archetypevalidator/validations/VariousStructureValidation.java:54 +#: ../tools/src/main/java/com/nedap/archie/archetypevalidator/validations/VariousStructureValidation.java:49 #, java-format msgid "Archetype with id {0} used in use_archetype, but it was not found" msgstr "Archetype met id {0} is gebruikt met use_archetype, maar het archetype kon niet worden gevonden" @@ -136,13 +136,13 @@ msgstr "Attribuut {0} is geen tuple in het archetype dat gespecializeerd wordt, msgid "Attribute {0} of class {1} does not match existence {2}" msgstr "Attribuut {0} van class {1} komt niet overeen met existence {2}" -#: ../tools/src/main/java/com/nedap/archie/archetypevalidator/validations/ValidateAgainstReferenceModel.java:70 -#: ../tools/src/main/java/com/nedap/archie/archetypevalidator/validations/ValidateAgainstReferenceModel.java:82 +#: ../tools/src/main/java/com/nedap/archie/archetypevalidator/validations/ValidateAgainstReferenceModel.java:63 +#: ../tools/src/main/java/com/nedap/archie/archetypevalidator/validations/ValidateAgainstReferenceModel.java:75 #, java-format msgid "Attribute {0}.{1} cannot be constrained by a {2}" msgstr "Attribuut {0}.{1} kan niet worden beperkt met een {2}" -#: ../tools/src/main/java/com/nedap/archie/archetypevalidator/validations/ValidateAgainstReferenceModel.java:48 +#: ../tools/src/main/java/com/nedap/archie/archetypevalidator/validations/ValidateAgainstReferenceModel.java:41 #, java-format msgid "Attribute {0}.{1} cannot contain type {2}" msgstr "Attribuut {0}.{1} mag geen type {2} bevatten" @@ -190,7 +190,7 @@ msgstr "Code {0} van de C_TERMINOLOGY_CODE heeft specialization depth {1}, maar msgid "Code {0} from the C_TERMINOLOGY_CODE constraint is not defined in the terminology" msgstr "Code {0} van deze C_TERMINOLOGY_CODE bestaat niet in de terminology" -#: ../tools/src/main/java/com/nedap/archie/archetypevalidator/validations/BasicTerminologyValidation.java:161 +#: ../tools/src/main/java/com/nedap/archie/archetypevalidator/validations/BasicTerminologyValidation.java:164 #, java-format msgid "Code {0} is in the terminology, but not used in the archetype" msgstr "Code {0} uit de terminologie is niet gebruikt in de definitie van het archetype" @@ -242,30 +242,23 @@ msgstr "" msgid "Error" msgstr "Fout" -#: ../tools/src/main/java/com/nedap/archie/archetypevalidator/ArchetypeValidator.java:153 +#: ../tools/src/main/java/com/nedap/archie/archetypevalidator/ArchetypeValidator.java:156 #, java-format msgid "Error in parent archetype. Fix those errors before continuing with this archetype: {0}" msgstr "Fout in het gespecialiseerde archetype. Los deze fout in het bovenliggende archetype eerst op, alvorens verder te gaan met dit archetype. De gevonden fouten: {0}" -#: ../tools/src/main/java/com/nedap/archie/rmobjectvalidator/RMObjectValidator.java:130 -#, java-format -msgid "" -"Exception {0} invoking invariant {1} on {2}: {3}\n" -"{4}" -msgstr "" - -#: ../tools/src/main/java/com/nedap/archie/archetypevalidator/validations/BasicTerminologyValidation.java:39 +#: ../tools/src/main/java/com/nedap/archie/archetypevalidator/validations/BasicTerminologyValidation.java:42 #, java-format msgid "Id code {0} in terminology is not a valid term code, should be id, ac or at, followed by digits" msgstr "Id code {0} in de terminology is geen geldige term-code. De code zou moeten beginnen met id, ac of at, gevolgd door getallen" -#: ../tools/src/main/java/com/nedap/archie/archetypevalidator/validations/BasicTerminologyValidation.java:43 -#: ../tools/src/main/java/com/nedap/archie/archetypevalidator/validations/BasicTerminologyValidation.java:47 +#: ../tools/src/main/java/com/nedap/archie/archetypevalidator/validations/BasicTerminologyValidation.java:46 +#: ../tools/src/main/java/com/nedap/archie/archetypevalidator/validations/BasicTerminologyValidation.java:50 #, java-format msgid "Id code {0} in terminology is of a different specialization depth than the archetype" msgstr "Id code {0} uit de terminologie heeft een andere specialization depth dan het archetype" -#: ../tools/src/main/java/com/nedap/archie/archetypevalidator/validations/AttributeTupleValidation.java:38 +#: ../tools/src/main/java/com/nedap/archie/archetypevalidator/validations/AttributeTupleValidation.java:36 #, java-format msgid "In the attribute tuple {0} members were specified, but the primitive tuple has {1} members instead" msgstr "In het attribuut tupel zijn {0} members opgenomen, maar het primitive tuple heeft {1} members. Dit moet gelijk zijn" @@ -275,7 +268,7 @@ msgstr "In het attribuut tupel zijn {0} members opgenomen, maar het primitive tu msgid "Incorrect root node id {0}: it must match the specialization depth of the archetype, which is {1}" msgstr "Fout in root node id {0}: Dit moet kloppen met de specialization depth van het archetype, {1}" -#: ../tools/src/main/java/com/nedap/archie/rmobjectvalidator/RMObjectValidator.java:125 +#: ../tools/src/main/java/com/nedap/archie/rmobjectvalidator/RMObjectValidator.java:168 #, java-format msgid "Invariant {0} failed on type " msgstr "" @@ -314,7 +307,7 @@ msgstr "" msgid "No Reference Model schema found for package ''{0}''" msgstr "Geen referentiemodel-schema gevonden voor package “{0}”" -#: ../aom/src/main/java/com/nedap/archie/aom/primitives/CString.java:112 +#: ../aom/src/main/java/com/nedap/archie/aom/primitives/CString.java:114 #, java-format msgid "No matching constraint found in parent for contraint {0}" msgstr "" @@ -328,7 +321,7 @@ msgstr "De specialization depth van node id {0} klopt niet bij de specialization msgid "Node id numbers should be unique without their ac, at or id-prefix, to ensure the possibility of converting the archetype to ADL 1.4" msgstr "Node id nummers moeten uniek zijn zonder hun ac, at of id-prefix, om conversie van het archetype naar ADL 1.4 mogelijk te maken" -#: ../tools/src/main/java/com/nedap/archie/archetypevalidator/validations/BasicTerminologyValidation.java:175 +#: ../tools/src/main/java/com/nedap/archie/archetypevalidator/validations/BasicTerminologyValidation.java:178 #, java-format msgid "Node id {0} already used in archetype as {1} with a different at, id or ac prefix. The archetype will not be convertible to ADL 1.4" msgstr "Node id {0} wordt al gebruikt in het archetype als {1} met een andere at, id of ac prefix. Het archetype kan niet naar ADL 1.4 geconverteerd worden" @@ -338,7 +331,7 @@ msgstr "Node id {0} wordt al gebruikt in het archetype als {1} met een andere at msgid "Node id {0} already used in path {1}" msgstr "Node id {0} is al gebruikt in pad {1}" -#: ../aom/src/main/java/com/nedap/archie/aom/CObject.java:281 +#: ../aom/src/main/java/com/nedap/archie/aom/CObject.java:282 #, java-format msgid "Node id {0} does not conform to {1}" msgstr "Node id {0} komt niet overeen met {1}" @@ -373,7 +366,7 @@ msgstr "Object moet van type {0} zijn, maar is van type {1}" msgid "Object with node id {0} should be specialized before excluding the parent node" msgstr "Object met node id {0} moet gespecialiseerd worden voordat de parent node excluded wordt" -#: ../aom/src/main/java/com/nedap/archie/aom/CPrimitiveObject.java:127 +#: ../aom/src/main/java/com/nedap/archie/aom/CPrimitiveObject.java:129 #, java-format msgid "Occurrences {0} does not conform to {1}" msgstr "Occurrences {0} komt niet overeen met {1}" @@ -694,7 +687,7 @@ msgstr "" msgid "Sibling order {0} refers to missing node id" msgstr "Sibling order {0} verwijst naar een ontbrekende node id" -#: ../tools/src/main/java/com/nedap/archie/archetypevalidator/validations/ValidateAgainstReferenceModel.java:151 +#: ../tools/src/main/java/com/nedap/archie/archetypevalidator/validations/ValidateAgainstReferenceModel.java:144 msgid "Single valued attributes can not have a cardinality" msgstr "Attributen die maar één waarde kunnen bevatten mogen geen cardinaliteit hebben" @@ -715,27 +708,27 @@ msgstr "Syntaxfout: existence moet een van 0..0, 0..1 of 1..1 zijn, maar was {0} msgid "Syntax error: terminology not specified" msgstr "Syntaxfout: terminologie ontbreekt" -#: ../tools/src/main/java/com/nedap/archie/archetypevalidator/ArchetypeValidator.java:199 +#: ../tools/src/main/java/com/nedap/archie/archetypevalidator/ArchetypeValidator.java:202 #, java-format msgid "Template overlay {0} had validation errors" msgstr "Template overlay {0} heeft validatiefouten" -#: ../tools/src/main/java/com/nedap/archie/archetypevalidator/validations/BasicTerminologyValidation.java:83 +#: ../tools/src/main/java/com/nedap/archie/archetypevalidator/validations/BasicTerminologyValidation.java:86 #, java-format msgid "Term binding key {0} in path format is not present in archetype" msgstr "Het pad {0} uit een term binding kan niet worden gevonden in het archetype" -#: ../tools/src/main/java/com/nedap/archie/archetypevalidator/validations/BasicTerminologyValidation.java:88 +#: ../tools/src/main/java/com/nedap/archie/archetypevalidator/validations/BasicTerminologyValidation.java:91 #, java-format msgid "Term binding key {0} is not present in terminology" msgstr "De code {0} van een term binding bestaat niet in de terminologie" -#: ../tools/src/main/java/com/nedap/archie/archetypevalidator/validations/FlatFormValidation.java:88 +#: ../tools/src/main/java/com/nedap/archie/archetypevalidator/validations/FlatFormValidation.java:91 #, java-format msgid "Term binding key {0} is not present in the terminology" msgstr "De code {0} van een term binding bestaat niet in de terminologie" -#: ../tools/src/main/java/com/nedap/archie/archetypevalidator/validations/FlatFormValidation.java:81 +#: ../tools/src/main/java/com/nedap/archie/archetypevalidator/validations/FlatFormValidation.java:84 #, java-format msgid "Term binding key {0} points to a path that cannot be found in the archetype" msgstr "Het pad {0} uit een term binding kan niet worden gevonden in het archetype" @@ -758,7 +751,7 @@ msgstr "Het archetype id {0} komt niet overeen met de mogelijke archetype ids" msgid "The attribute cardinality interval has lower > upper, this is not allowed" msgstr "" -#: ../tools/src/main/java/com/nedap/archie/archetypevalidator/validations/FlatFormValidation.java:55 +#: ../tools/src/main/java/com/nedap/archie/archetypevalidator/validations/FlatFormValidation.java:58 #, java-format msgid "The attribute contains {0} objects that are required, but only has an upper cardinality of {1}" msgstr "Het attribuut bevat {0} waarden die verplicht zijn, maar heeft een maximale cardinaliteit van {1}" @@ -768,12 +761,12 @@ msgstr "Het attribuut bevat {0} waarden die verplicht zijn, maar heeft een maxim msgid "The attribute {0} of type {1} can only have a single value, but the occurrences of the C_OBJECTS below has an upper limit of more than 1" msgstr "Het attribuut {0} van type {1} kan maar één waarde hebben, maar de occurrences van de C_OBJECTS in dit attibuut heeft een maximale limiet van meer dan 1" -#: ../tools/src/main/java/com/nedap/archie/archetypevalidator/validations/ValidateAgainstReferenceModel.java:135 +#: ../tools/src/main/java/com/nedap/archie/archetypevalidator/validations/ValidateAgainstReferenceModel.java:128 #, java-format msgid "The cardinality of Attribute {0}.{1} is the same as in the reference model - this is not allowed due to strict multiplicities validation being enabled" msgstr "De cardinaliteit van attribuut {0}.{1} is hetzelfde als in het referentiemodel. Dit is niet toegestaan als strikte validatie is ingeschakeld" -#: ../tools/src/main/java/com/nedap/archie/archetypevalidator/validations/ValidateAgainstReferenceModel.java:143 +#: ../tools/src/main/java/com/nedap/archie/archetypevalidator/validations/ValidateAgainstReferenceModel.java:136 #, java-format msgid "The cardinality {0} of attribute {2}.{3} does not match cardinality {1} of the reference model" msgstr "De cardinaliteit {0} van attribuut {2}.{3} klopt niet met de cardinaliteit {1} uit het referentiemodel" @@ -793,12 +786,12 @@ msgstr "" msgid "The constraint interval for this {0} has lower > upper, this is not allowed" msgstr "" -#: ../tools/src/main/java/com/nedap/archie/archetypevalidator/validations/ValidateAgainstReferenceModel.java:116 +#: ../tools/src/main/java/com/nedap/archie/archetypevalidator/validations/ValidateAgainstReferenceModel.java:109 #, java-format msgid "The existence of attribute {0}.{1} is the same as in the reference model - this is not allowed due to strict existence validation being enabled" msgstr "De existence van attribuut {0}.{1} is hetzelfde als in het referentiemodel. Dit is niet toegestaan als strikte validatie ingeschakeld is" -#: ../tools/src/main/java/com/nedap/archie/archetypevalidator/validations/ValidateAgainstReferenceModel.java:124 +#: ../tools/src/main/java/com/nedap/archie/archetypevalidator/validations/ValidateAgainstReferenceModel.java:117 #, java-format msgid "The existence {0} of attribute {2}.{3} does not match existence {1} of the reference model" msgstr "De existence {0} van attribuut {2}.{3} klopt niet bij existence {1} van het referentiemodel" @@ -816,7 +809,7 @@ msgstr "De node id van het bovenste object van het archetype moet van de form id msgid "The occurrences interval has lower > upper, this is not allowed" msgstr "" -#: ../tools/src/main/java/com/nedap/archie/archetypevalidator/validations/FlatFormValidation.java:52 +#: ../tools/src/main/java/com/nedap/archie/archetypevalidator/validations/FlatFormValidation.java:55 #, java-format msgid "The occurrences of all C_OBJECTS under this attributes is at least {0}, which does not fit in the upper limit of the cardinality of the attribute, {1}" msgstr "De occurrences van alle C_OBJECTS onder dit attribuut is ten minste {0}. Dat past niet in de maximale cardinaliteit van het attibruut {1}" @@ -836,12 +829,12 @@ msgstr "Het pad {0} gebruikt in de annotations bestaat niet in het flattened arc msgid "The path {0} referenced in the rm visibility does not exist in the flat archetype" msgstr "Het pad {0} gebruikt in de rm zichtbaarheid bestaat niet in het flattened archetype" -#: ../aom/src/main/java/com/nedap/archie/aom/CPrimitiveObject.java:134 +#: ../aom/src/main/java/com/nedap/archie/aom/CPrimitiveObject.java:136 #, java-format msgid "The primitive object of type {0} does not conform null" msgstr "" -#: ../aom/src/main/java/com/nedap/archie/aom/CPrimitiveObject.java:136 +#: ../aom/src/main/java/com/nedap/archie/aom/CPrimitiveObject.java:138 #, java-format msgid "The primitive object of type {0} does not conform to non-primitive object with type {1}" msgstr "Het primitieve object van type {0} komt niet overeen met het niet-primitieve object met type {1}" @@ -887,16 +880,21 @@ msgstr "De waarde {0} moet {1} zijn" msgid "Translation details language {0} has an incorrect key: {1}" msgstr "De beschrijving van de vertaling {0} zou een gelijke sleutelwaarde als de taal moeten hebben, maar heeft de waarde {1}" -#: ../tools/src/main/java/com/nedap/archie/archetypevalidator/validations/AttributeTupleValidation.java:32 +#: ../tools/src/main/java/com/nedap/archie/archetypevalidator/validations/AttributeTupleValidation.java:30 #, java-format msgid "Tuple member attribute {0} is not an attribute of type {1}" msgstr "Onderdeel van tupel {0} is geen attribuut van type {1}" -#: ../tools/src/main/java/com/nedap/archie/archetypevalidator/validations/ValidateAgainstReferenceModel.java:35 +#: ../tools/src/main/java/com/nedap/archie/archetypevalidator/validations/ValidateAgainstReferenceModel.java:28 #, java-format msgid "Type name {0} does not exist" msgstr "Type met naam {0} bestaat niet" +#: ../tools/src/main/java/com/nedap/archie/rmobjectvalidator/RMObjectValidator.java:173 +#, fuzzy, java-format +msgid "Unexpected error validating invariant {0} on {1}" +msgstr "Onverwachte fout bij het valideren van invariant {0} van {1}" + #: ../bmm/src/main/java/org/openehr/bmm/persistence/validation/BmmMessageIds.java:54 #, java-format msgid "Unknown Reference Model ''{0}'' mentioned in ''rm_schemas_load_list'' config setting (ignored)" @@ -910,7 +908,7 @@ msgstr "" msgid "Unknown exception processing RM schemas" msgstr "" -#: ../tools/src/main/java/com/nedap/archie/archetypevalidator/validations/VariousStructureValidation.java:68 +#: ../tools/src/main/java/com/nedap/archie/archetypevalidator/validations/VariousStructureValidation.java:63 #, java-format msgid "Use_archetype points to type {0}, which is not conformant for type {1} of the archetype root used" msgstr "Use_archetype verwijst naar een pad met type {0}. Dit komt niet overeen met type {1} zoals opgegeven in use_archetype" @@ -931,21 +929,21 @@ msgstr "Use_archetype {1} specialiseert een andere use_archetype die verwijst na msgid "Use_archetype {0} does not match the expression of the archetype slot it specialized in the parent" msgstr "Use_archetype {0} komt niet overeen met de restricties van het archetype slot dat het specialiseert" -#: ../tools/src/main/java/com/nedap/archie/archetypevalidator/validations/FlatFormValidation.java:42 +#: ../tools/src/main/java/com/nedap/archie/archetypevalidator/validations/FlatFormValidation.java:45 #, java-format msgid "Use_node (C_COMPLEX_OBJECT_PROXY) must point to a C_COMPLEX_OBJECT, but points to a {0}" msgstr "Use_node, hergebruik van een deel van het archetype, moet naar een C_COMPLEX_OBJECT verwijzen, maar verwijst naar een {0}" -#: ../tools/src/main/java/com/nedap/archie/archetypevalidator/validations/FlatFormValidation.java:24 +#: ../tools/src/main/java/com/nedap/archie/archetypevalidator/validations/FlatFormValidation.java:27 #, java-format msgid "Use_node (C_COMPLEX_OBJECT_PROXY) points to a path that cannot be found: {0}" msgstr "Use_node, hergebruik van een deel van het archetype, verwijst naar een pad dat niet kan worden gevonden: {0}" -#: ../tools/src/main/java/com/nedap/archie/archetypevalidator/validations/FlatFormValidation.java:26 +#: ../tools/src/main/java/com/nedap/archie/archetypevalidator/validations/FlatFormValidation.java:29 msgid "Use_node (C_COMPLEX_OBJECT_PROXY) points to a path that resolves to more than one object" msgstr "Use_node, hergebruik van een deel van het archetype, verwijst naar een pad dat verwijst naar meer dan één object" -#: ../tools/src/main/java/com/nedap/archie/archetypevalidator/validations/FlatFormValidation.java:36 +#: ../tools/src/main/java/com/nedap/archie/archetypevalidator/validations/FlatFormValidation.java:39 #, java-format msgid "Use_node (C_COMPLEX_OBJECT_PROXY) points to type {0}, which does not conform to type {1}" msgstr "Use_node, hergebruik van een deel van het archetype, verwijst naar type {0}, maar dat klopt niet met type {1} zoals gevonden uit het pad" @@ -1041,22 +1039,22 @@ msgstr "" msgid "cardinality/occurrences upper bound validity: where a cardinality with a finite upper bound is stated on an attribute, for all immediate child objects for which an occurrences constraint is stated, the occurrences must either have an open upper bound (i.e. n..*) which is interpreted as the maximum value allowed within the cardinality, or else a finite upper bound which is ⇐ the cardinality upper bound." msgstr "" -#: ../aom/src/main/java/com/nedap/archie/aom/primitives/CTerminologyCode.java:234 +#: ../aom/src/main/java/com/nedap/archie/aom/primitives/CTerminologyCode.java:235 #, java-format msgid "child CTerminology code contains more than one constraint, that is not valid. Constraints are: {0}" msgstr "" -#: ../aom/src/main/java/com/nedap/archie/aom/primitives/CTerminologyCode.java:279 +#: ../aom/src/main/java/com/nedap/archie/aom/primitives/CTerminologyCode.java:280 #, java-format msgid "child terminology constraint value code {0} does not conform to parent constraint with value code {1}" msgstr "child terminology constraint value code {0} komt niet overeen met dat van de parent constraint met value code {1}" -#: ../aom/src/main/java/com/nedap/archie/aom/primitives/CTerminologyCode.java:263 +#: ../aom/src/main/java/com/nedap/archie/aom/primitives/CTerminologyCode.java:264 #, java-format msgid "child terminology constraint value code {0} is not contained in {1}, or a direct specialization of one of its values" msgstr "" -#: ../aom/src/main/java/com/nedap/archie/aom/primitives/CTerminologyCode.java:259 +#: ../aom/src/main/java/com/nedap/archie/aom/primitives/CTerminologyCode.java:260 #, java-format msgid "child terminology constraint value set code {0} does not conform to parent constraint with value set code {1}" msgstr "child terminology constraint value set code {0} komt niet overeen de parent constraint met value set code {1}" @@ -1069,7 +1067,8 @@ msgstr "code uit terminologie is niet gebruikt in de definitie van het archetype msgid "constraint code validity. Each value set code (ac-code) used in a term constraint in the archetype definition must be defined in the term_definitions part of the terminology of the current archetype." msgstr "" -#: ../tools/src/main/java/com/nedap/archie/rmobjectvalidator/validations/RMPrimitiveObjectValidation.java:59 +#: ../tools/src/main/java/com/nedap/archie/rmobjectvalidator/RmPrimitiveObjectValidator.java:60 +#: ../tools/src/main/java/com/nedap/archie/rmobjectvalidator/validations/RMPrimitiveObjectValidation.java:71 msgid "empty" msgstr "leeg" @@ -1136,7 +1135,7 @@ msgstr "" msgid "original language specified. An original_language section containing the meta-data of the original authoring language must exist." msgstr "" -#: ../aom/src/main/java/com/nedap/archie/aom/primitives/CTerminologyCode.java:237 +#: ../aom/src/main/java/com/nedap/archie/aom/primitives/CTerminologyCode.java:238 #, java-format msgid "parent CTerminology code contains more than one constraint, that is not valid. Constraints are: {0}" msgstr "" @@ -1217,7 +1216,7 @@ msgstr "" msgid "specialised object node occurrences validity: the sum of the lower occurrences and the sum of the upper occurrences of all objects redefining a node in a specialised archetype, must be contained in the occurrences interval of the corresponding node in the flat parent archetype." msgstr "" -#: ../aom/src/main/java/com/nedap/archie/aom/primitives/CTerminologyCode.java:243 +#: ../aom/src/main/java/com/nedap/archie/aom/primitives/CTerminologyCode.java:244 #, java-format msgid "specialized CTerminology code constraint status {0} is wider more than parent contraint status {1}" msgstr "" @@ -1238,8 +1237,8 @@ msgstr "de gegeven id code is niet geldig" msgid "translations key does not match translations item language" msgstr "" -#: ../aom/src/main/java/com/nedap/archie/aom/CPrimitiveObject.java:130 -#: ../aom/src/main/java/com/nedap/archie/aom/CObject.java:284 +#: ../aom/src/main/java/com/nedap/archie/aom/CPrimitiveObject.java:132 +#: ../aom/src/main/java/com/nedap/archie/aom/CObject.java:285 #, java-format msgid "type name {0} does not conform to {1}" msgstr "Naam type {0} komt niet overeen met {1}" @@ -1260,13 +1259,13 @@ msgstr "" msgid "value code validity. Each value code (at-code) used in a term constraint in the archetype definition must be defined in the term_definitions part of the terminology of the flattened form of the current archetype." msgstr "Geldigheid van een value code. Elke value code (at-code) gebruikt in een term constraint in de definitie van het archetype moet in de term definities van de flat form van dit archetype opgenomen zijn." -#: ../tools/src/main/java/com/nedap/archie/archetypevalidator/validations/BasicTerminologyValidation.java:140 +#: ../tools/src/main/java/com/nedap/archie/archetypevalidator/validations/BasicTerminologyValidation.java:143 #, java-format msgid "value code {0} is used in redefined value set {1}, but not present in its parent value set with members {2}" msgstr "" -#: ../tools/src/main/java/com/nedap/archie/archetypevalidator/validations/BasicTerminologyValidation.java:118 -#: ../tools/src/main/java/com/nedap/archie/archetypevalidator/validations/BasicTerminologyValidation.java:122 +#: ../tools/src/main/java/com/nedap/archie/archetypevalidator/validations/BasicTerminologyValidation.java:121 +#: ../tools/src/main/java/com/nedap/archie/archetypevalidator/validations/BasicTerminologyValidation.java:125 #, java-format msgid "value code {0} is used in value set {1}, but not present in terminology" msgstr "de code {0} is gebruikt in value set {1}, maar bestaat niet in de terminologie" @@ -1275,18 +1274,18 @@ msgstr "de code {0} is gebruikt in value set {1}, maar bestaat niet in de termin msgid "value set assumed value code validity. Each value code (at-code) used as an assumed_value for a value set in a term constraint in the archetype definition must exist in the value set definition in the terminology for the identified value set." msgstr "" -#: ../tools/src/main/java/com/nedap/archie/archetypevalidator/validations/BasicTerminologyValidation.java:103 +#: ../tools/src/main/java/com/nedap/archie/archetypevalidator/validations/BasicTerminologyValidation.java:106 #, java-format msgid "value set code {0} is not present in terminology" msgstr "de code {0} van een value set bestaat niet in de terminologie" -#: ../tools/src/main/java/com/nedap/archie/archetypevalidator/validations/BasicTerminologyValidation.java:109 -#: ../tools/src/main/java/com/nedap/archie/archetypevalidator/validations/BasicTerminologyValidation.java:113 +#: ../tools/src/main/java/com/nedap/archie/archetypevalidator/validations/BasicTerminologyValidation.java:112 +#: ../tools/src/main/java/com/nedap/archie/archetypevalidator/validations/BasicTerminologyValidation.java:116 #, java-format msgid "value set code {0} is used in value set {1}, but not present in terminology" msgstr "de value set code {0} is gebruikt in value set {1}, maar bestaat niet in de terminologie" -#: ../tools/src/main/java/com/nedap/archie/archetypevalidator/validations/BasicTerminologyValidation.java:135 +#: ../tools/src/main/java/com/nedap/archie/archetypevalidator/validations/BasicTerminologyValidation.java:138 #, java-format msgid "value set {0} has a specialized code, but the valueset it specialized cannot be found in the flat parent" msgstr "" @@ -1308,7 +1307,7 @@ msgstr "value-set waardes uniek. Elke waarde mag maar één keer gebruikt worden msgid "{0} and {1}" msgstr "{0} en {1}" -#: ../tools/src/main/java/com/nedap/archie/archetypevalidator/validations/ValidateAgainstReferenceModel.java:106 +#: ../tools/src/main/java/com/nedap/archie/archetypevalidator/validations/ValidateAgainstReferenceModel.java:99 #, java-format msgid "{0} is not a known attribute of {1}" msgstr "{0} is niet een bekend attribuut van {1}" diff --git a/i18n/po/keys.pot b/i18n/po/keys.pot index 82b49724b..5ca873152 100644 --- a/i18n/po/keys.pot +++ b/i18n/po/keys.pot @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-12-14 13:44+0100\n" +"POT-Creation-Date: 2025-09-17 15:14+0200\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -70,12 +70,12 @@ msgstr "" msgid "An object with the new node id {0} cannot be prohibited" msgstr "" -#: ../tools/src/main/java/com/nedap/archie/archetypevalidator/validations/VariousStructureValidation.java:65 +#: ../tools/src/main/java/com/nedap/archie/archetypevalidator/validations/VariousStructureValidation.java:60 #, java-format msgid "Archetype referenced in use_archetype points to class {0}, which does not exist in this reference model" msgstr "" -#: ../tools/src/main/java/com/nedap/archie/archetypevalidator/validations/VariousStructureValidation.java:75 +#: ../tools/src/main/java/com/nedap/archie/archetypevalidator/validations/VariousStructureValidation.java:70 msgid "Archetype root must have an archetype reference or be prohibited (occurrences matches 0)" msgstr "" @@ -91,7 +91,7 @@ msgstr "" msgid "Archetype terminology not defined" msgstr "" -#: ../tools/src/main/java/com/nedap/archie/archetypevalidator/validations/VariousStructureValidation.java:54 +#: ../tools/src/main/java/com/nedap/archie/archetypevalidator/validations/VariousStructureValidation.java:49 #, java-format msgid "Archetype with id {0} used in use_archetype, but it was not found" msgstr "" @@ -141,13 +141,13 @@ msgstr "" msgid "Attribute {0} of class {1} does not match existence {2}" msgstr "" -#: ../tools/src/main/java/com/nedap/archie/archetypevalidator/validations/ValidateAgainstReferenceModel.java:70 -#: ../tools/src/main/java/com/nedap/archie/archetypevalidator/validations/ValidateAgainstReferenceModel.java:82 +#: ../tools/src/main/java/com/nedap/archie/archetypevalidator/validations/ValidateAgainstReferenceModel.java:63 +#: ../tools/src/main/java/com/nedap/archie/archetypevalidator/validations/ValidateAgainstReferenceModel.java:75 #, java-format msgid "Attribute {0}.{1} cannot be constrained by a {2}" msgstr "" -#: ../tools/src/main/java/com/nedap/archie/archetypevalidator/validations/ValidateAgainstReferenceModel.java:48 +#: ../tools/src/main/java/com/nedap/archie/archetypevalidator/validations/ValidateAgainstReferenceModel.java:41 #, java-format msgid "Attribute {0}.{1} cannot contain type {2}" msgstr "" @@ -195,7 +195,7 @@ msgstr "" msgid "Code {0} from the C_TERMINOLOGY_CODE constraint is not defined in the terminology" msgstr "" -#: ../tools/src/main/java/com/nedap/archie/archetypevalidator/validations/BasicTerminologyValidation.java:161 +#: ../tools/src/main/java/com/nedap/archie/archetypevalidator/validations/BasicTerminologyValidation.java:164 #, java-format msgid "Code {0} is in the terminology, but not used in the archetype" msgstr "" @@ -247,30 +247,23 @@ msgstr "" msgid "Error" msgstr "" -#: ../tools/src/main/java/com/nedap/archie/archetypevalidator/ArchetypeValidator.java:153 +#: ../tools/src/main/java/com/nedap/archie/archetypevalidator/ArchetypeValidator.java:156 #, java-format msgid "Error in parent archetype. Fix those errors before continuing with this archetype: {0}" msgstr "" -#: ../tools/src/main/java/com/nedap/archie/rmobjectvalidator/RMObjectValidator.java:130 -#, java-format -msgid "" -"Exception {0} invoking invariant {1} on {2}: {3}\n" -"{4}" -msgstr "" - -#: ../tools/src/main/java/com/nedap/archie/archetypevalidator/validations/BasicTerminologyValidation.java:39 +#: ../tools/src/main/java/com/nedap/archie/archetypevalidator/validations/BasicTerminologyValidation.java:42 #, java-format msgid "Id code {0} in terminology is not a valid term code, should be id, ac or at, followed by digits" msgstr "" -#: ../tools/src/main/java/com/nedap/archie/archetypevalidator/validations/BasicTerminologyValidation.java:43 -#: ../tools/src/main/java/com/nedap/archie/archetypevalidator/validations/BasicTerminologyValidation.java:47 +#: ../tools/src/main/java/com/nedap/archie/archetypevalidator/validations/BasicTerminologyValidation.java:46 +#: ../tools/src/main/java/com/nedap/archie/archetypevalidator/validations/BasicTerminologyValidation.java:50 #, java-format msgid "Id code {0} in terminology is of a different specialization depth than the archetype" msgstr "" -#: ../tools/src/main/java/com/nedap/archie/archetypevalidator/validations/AttributeTupleValidation.java:38 +#: ../tools/src/main/java/com/nedap/archie/archetypevalidator/validations/AttributeTupleValidation.java:36 #, java-format msgid "In the attribute tuple {0} members were specified, but the primitive tuple has {1} members instead" msgstr "" @@ -280,7 +273,7 @@ msgstr "" msgid "Incorrect root node id {0}: it must match the specialization depth of the archetype, which is {1}" msgstr "" -#: ../tools/src/main/java/com/nedap/archie/rmobjectvalidator/RMObjectValidator.java:125 +#: ../tools/src/main/java/com/nedap/archie/rmobjectvalidator/RMObjectValidator.java:168 #, java-format msgid "Invariant {0} failed on type " msgstr "" @@ -319,7 +312,7 @@ msgstr "" msgid "No Reference Model schema found for package ''{0}''" msgstr "" -#: ../aom/src/main/java/com/nedap/archie/aom/primitives/CString.java:112 +#: ../aom/src/main/java/com/nedap/archie/aom/primitives/CString.java:114 #, java-format msgid "No matching constraint found in parent for contraint {0}" msgstr "" @@ -333,7 +326,7 @@ msgstr "" msgid "Node id numbers should be unique without their ac, at or id-prefix, to ensure the possibility of converting the archetype to ADL 1.4" msgstr "" -#: ../tools/src/main/java/com/nedap/archie/archetypevalidator/validations/BasicTerminologyValidation.java:175 +#: ../tools/src/main/java/com/nedap/archie/archetypevalidator/validations/BasicTerminologyValidation.java:178 #, java-format msgid "Node id {0} already used in archetype as {1} with a different at, id or ac prefix. The archetype will not be convertible to ADL 1.4" msgstr "" @@ -343,7 +336,7 @@ msgstr "" msgid "Node id {0} already used in path {1}" msgstr "" -#: ../aom/src/main/java/com/nedap/archie/aom/CObject.java:281 +#: ../aom/src/main/java/com/nedap/archie/aom/CObject.java:282 #, java-format msgid "Node id {0} does not conform to {1}" msgstr "" @@ -378,7 +371,7 @@ msgstr "" msgid "Object with node id {0} should be specialized before excluding the parent node" msgstr "" -#: ../aom/src/main/java/com/nedap/archie/aom/CPrimitiveObject.java:127 +#: ../aom/src/main/java/com/nedap/archie/aom/CPrimitiveObject.java:129 #, java-format msgid "Occurrences {0} does not conform to {1}" msgstr "" @@ -699,7 +692,7 @@ msgstr "" msgid "Sibling order {0} refers to missing node id" msgstr "" -#: ../tools/src/main/java/com/nedap/archie/archetypevalidator/validations/ValidateAgainstReferenceModel.java:151 +#: ../tools/src/main/java/com/nedap/archie/archetypevalidator/validations/ValidateAgainstReferenceModel.java:144 msgid "Single valued attributes can not have a cardinality" msgstr "" @@ -720,27 +713,27 @@ msgstr "" msgid "Syntax error: terminology not specified" msgstr "" -#: ../tools/src/main/java/com/nedap/archie/archetypevalidator/ArchetypeValidator.java:199 +#: ../tools/src/main/java/com/nedap/archie/archetypevalidator/ArchetypeValidator.java:202 #, java-format msgid "Template overlay {0} had validation errors" msgstr "" -#: ../tools/src/main/java/com/nedap/archie/archetypevalidator/validations/BasicTerminologyValidation.java:83 +#: ../tools/src/main/java/com/nedap/archie/archetypevalidator/validations/BasicTerminologyValidation.java:86 #, java-format msgid "Term binding key {0} in path format is not present in archetype" msgstr "" -#: ../tools/src/main/java/com/nedap/archie/archetypevalidator/validations/BasicTerminologyValidation.java:88 +#: ../tools/src/main/java/com/nedap/archie/archetypevalidator/validations/BasicTerminologyValidation.java:91 #, java-format msgid "Term binding key {0} is not present in terminology" msgstr "" -#: ../tools/src/main/java/com/nedap/archie/archetypevalidator/validations/FlatFormValidation.java:88 +#: ../tools/src/main/java/com/nedap/archie/archetypevalidator/validations/FlatFormValidation.java:91 #, java-format msgid "Term binding key {0} is not present in the terminology" msgstr "" -#: ../tools/src/main/java/com/nedap/archie/archetypevalidator/validations/FlatFormValidation.java:81 +#: ../tools/src/main/java/com/nedap/archie/archetypevalidator/validations/FlatFormValidation.java:84 #, java-format msgid "Term binding key {0} points to a path that cannot be found in the archetype" msgstr "" @@ -763,7 +756,7 @@ msgstr "" msgid "The attribute cardinality interval has lower > upper, this is not allowed" msgstr "" -#: ../tools/src/main/java/com/nedap/archie/archetypevalidator/validations/FlatFormValidation.java:55 +#: ../tools/src/main/java/com/nedap/archie/archetypevalidator/validations/FlatFormValidation.java:58 #, java-format msgid "The attribute contains {0} objects that are required, but only has an upper cardinality of {1}" msgstr "" @@ -773,12 +766,12 @@ msgstr "" msgid "The attribute {0} of type {1} can only have a single value, but the occurrences of the C_OBJECTS below has an upper limit of more than 1" msgstr "" -#: ../tools/src/main/java/com/nedap/archie/archetypevalidator/validations/ValidateAgainstReferenceModel.java:135 +#: ../tools/src/main/java/com/nedap/archie/archetypevalidator/validations/ValidateAgainstReferenceModel.java:128 #, java-format msgid "The cardinality of Attribute {0}.{1} is the same as in the reference model - this is not allowed due to strict multiplicities validation being enabled" msgstr "" -#: ../tools/src/main/java/com/nedap/archie/archetypevalidator/validations/ValidateAgainstReferenceModel.java:143 +#: ../tools/src/main/java/com/nedap/archie/archetypevalidator/validations/ValidateAgainstReferenceModel.java:136 #, java-format msgid "The cardinality {0} of attribute {2}.{3} does not match cardinality {1} of the reference model" msgstr "" @@ -798,12 +791,12 @@ msgstr "" msgid "The constraint interval for this {0} has lower > upper, this is not allowed" msgstr "" -#: ../tools/src/main/java/com/nedap/archie/archetypevalidator/validations/ValidateAgainstReferenceModel.java:116 +#: ../tools/src/main/java/com/nedap/archie/archetypevalidator/validations/ValidateAgainstReferenceModel.java:109 #, java-format msgid "The existence of attribute {0}.{1} is the same as in the reference model - this is not allowed due to strict existence validation being enabled" msgstr "" -#: ../tools/src/main/java/com/nedap/archie/archetypevalidator/validations/ValidateAgainstReferenceModel.java:124 +#: ../tools/src/main/java/com/nedap/archie/archetypevalidator/validations/ValidateAgainstReferenceModel.java:117 #, java-format msgid "The existence {0} of attribute {2}.{3} does not match existence {1} of the reference model" msgstr "" @@ -821,7 +814,7 @@ msgstr "" msgid "The occurrences interval has lower > upper, this is not allowed" msgstr "" -#: ../tools/src/main/java/com/nedap/archie/archetypevalidator/validations/FlatFormValidation.java:52 +#: ../tools/src/main/java/com/nedap/archie/archetypevalidator/validations/FlatFormValidation.java:55 #, java-format msgid "The occurrences of all C_OBJECTS under this attributes is at least {0}, which does not fit in the upper limit of the cardinality of the attribute, {1}" msgstr "" @@ -841,12 +834,12 @@ msgstr "" msgid "The path {0} referenced in the rm visibility does not exist in the flat archetype" msgstr "" -#: ../aom/src/main/java/com/nedap/archie/aom/CPrimitiveObject.java:134 +#: ../aom/src/main/java/com/nedap/archie/aom/CPrimitiveObject.java:136 #, java-format msgid "The primitive object of type {0} does not conform null" msgstr "" -#: ../aom/src/main/java/com/nedap/archie/aom/CPrimitiveObject.java:136 +#: ../aom/src/main/java/com/nedap/archie/aom/CPrimitiveObject.java:138 #, java-format msgid "The primitive object of type {0} does not conform to non-primitive object with type {1}" msgstr "" @@ -892,16 +885,21 @@ msgstr "" msgid "Translation details language {0} has an incorrect key: {1}" msgstr "" -#: ../tools/src/main/java/com/nedap/archie/archetypevalidator/validations/AttributeTupleValidation.java:32 +#: ../tools/src/main/java/com/nedap/archie/archetypevalidator/validations/AttributeTupleValidation.java:30 #, java-format msgid "Tuple member attribute {0} is not an attribute of type {1}" msgstr "" -#: ../tools/src/main/java/com/nedap/archie/archetypevalidator/validations/ValidateAgainstReferenceModel.java:35 +#: ../tools/src/main/java/com/nedap/archie/archetypevalidator/validations/ValidateAgainstReferenceModel.java:28 #, java-format msgid "Type name {0} does not exist" msgstr "" +#: ../tools/src/main/java/com/nedap/archie/rmobjectvalidator/RMObjectValidator.java:173 +#, java-format +msgid "Unexpected error validating invariant {0} on {1}" +msgstr "" + #: ../bmm/src/main/java/org/openehr/bmm/persistence/validation/BmmMessageIds.java:54 #, java-format msgid "Unknown Reference Model ''{0}'' mentioned in ''rm_schemas_load_list'' config setting (ignored)" @@ -915,7 +913,7 @@ msgstr "" msgid "Unknown exception processing RM schemas" msgstr "" -#: ../tools/src/main/java/com/nedap/archie/archetypevalidator/validations/VariousStructureValidation.java:68 +#: ../tools/src/main/java/com/nedap/archie/archetypevalidator/validations/VariousStructureValidation.java:63 #, java-format msgid "Use_archetype points to type {0}, which is not conformant for type {1} of the archetype root used" msgstr "" @@ -936,21 +934,21 @@ msgstr "" msgid "Use_archetype {0} does not match the expression of the archetype slot it specialized in the parent" msgstr "" -#: ../tools/src/main/java/com/nedap/archie/archetypevalidator/validations/FlatFormValidation.java:42 +#: ../tools/src/main/java/com/nedap/archie/archetypevalidator/validations/FlatFormValidation.java:45 #, java-format msgid "Use_node (C_COMPLEX_OBJECT_PROXY) must point to a C_COMPLEX_OBJECT, but points to a {0}" msgstr "" -#: ../tools/src/main/java/com/nedap/archie/archetypevalidator/validations/FlatFormValidation.java:24 +#: ../tools/src/main/java/com/nedap/archie/archetypevalidator/validations/FlatFormValidation.java:27 #, java-format msgid "Use_node (C_COMPLEX_OBJECT_PROXY) points to a path that cannot be found: {0}" msgstr "" -#: ../tools/src/main/java/com/nedap/archie/archetypevalidator/validations/FlatFormValidation.java:26 +#: ../tools/src/main/java/com/nedap/archie/archetypevalidator/validations/FlatFormValidation.java:29 msgid "Use_node (C_COMPLEX_OBJECT_PROXY) points to a path that resolves to more than one object" msgstr "" -#: ../tools/src/main/java/com/nedap/archie/archetypevalidator/validations/FlatFormValidation.java:36 +#: ../tools/src/main/java/com/nedap/archie/archetypevalidator/validations/FlatFormValidation.java:39 #, java-format msgid "Use_node (C_COMPLEX_OBJECT_PROXY) points to type {0}, which does not conform to type {1}" msgstr "" @@ -1046,22 +1044,22 @@ msgstr "" msgid "cardinality/occurrences upper bound validity: where a cardinality with a finite upper bound is stated on an attribute, for all immediate child objects for which an occurrences constraint is stated, the occurrences must either have an open upper bound (i.e. n..*) which is interpreted as the maximum value allowed within the cardinality, or else a finite upper bound which is ⇐ the cardinality upper bound." msgstr "" -#: ../aom/src/main/java/com/nedap/archie/aom/primitives/CTerminologyCode.java:234 +#: ../aom/src/main/java/com/nedap/archie/aom/primitives/CTerminologyCode.java:235 #, java-format msgid "child CTerminology code contains more than one constraint, that is not valid. Constraints are: {0}" msgstr "" -#: ../aom/src/main/java/com/nedap/archie/aom/primitives/CTerminologyCode.java:279 +#: ../aom/src/main/java/com/nedap/archie/aom/primitives/CTerminologyCode.java:280 #, java-format msgid "child terminology constraint value code {0} does not conform to parent constraint with value code {1}" msgstr "" -#: ../aom/src/main/java/com/nedap/archie/aom/primitives/CTerminologyCode.java:263 +#: ../aom/src/main/java/com/nedap/archie/aom/primitives/CTerminologyCode.java:264 #, java-format msgid "child terminology constraint value code {0} is not contained in {1}, or a direct specialization of one of its values" msgstr "" -#: ../aom/src/main/java/com/nedap/archie/aom/primitives/CTerminologyCode.java:259 +#: ../aom/src/main/java/com/nedap/archie/aom/primitives/CTerminologyCode.java:260 #, java-format msgid "child terminology constraint value set code {0} does not conform to parent constraint with value set code {1}" msgstr "" @@ -1074,7 +1072,8 @@ msgstr "" msgid "constraint code validity. Each value set code (ac-code) used in a term constraint in the archetype definition must be defined in the term_definitions part of the terminology of the current archetype." msgstr "" -#: ../tools/src/main/java/com/nedap/archie/rmobjectvalidator/validations/RMPrimitiveObjectValidation.java:59 +#: ../tools/src/main/java/com/nedap/archie/rmobjectvalidator/RmPrimitiveObjectValidator.java:60 +#: ../tools/src/main/java/com/nedap/archie/rmobjectvalidator/validations/RMPrimitiveObjectValidation.java:71 msgid "empty" msgstr "" @@ -1141,7 +1140,7 @@ msgstr "" msgid "original language specified. An original_language section containing the meta-data of the original authoring language must exist." msgstr "" -#: ../aom/src/main/java/com/nedap/archie/aom/primitives/CTerminologyCode.java:237 +#: ../aom/src/main/java/com/nedap/archie/aom/primitives/CTerminologyCode.java:238 #, java-format msgid "parent CTerminology code contains more than one constraint, that is not valid. Constraints are: {0}" msgstr "" @@ -1222,7 +1221,7 @@ msgstr "" msgid "specialised object node occurrences validity: the sum of the lower occurrences and the sum of the upper occurrences of all objects redefining a node in a specialised archetype, must be contained in the occurrences interval of the corresponding node in the flat parent archetype." msgstr "" -#: ../aom/src/main/java/com/nedap/archie/aom/primitives/CTerminologyCode.java:243 +#: ../aom/src/main/java/com/nedap/archie/aom/primitives/CTerminologyCode.java:244 #, java-format msgid "specialized CTerminology code constraint status {0} is wider more than parent contraint status {1}" msgstr "" @@ -1243,8 +1242,8 @@ msgstr "" msgid "translations key does not match translations item language" msgstr "" -#: ../aom/src/main/java/com/nedap/archie/aom/CPrimitiveObject.java:130 -#: ../aom/src/main/java/com/nedap/archie/aom/CObject.java:284 +#: ../aom/src/main/java/com/nedap/archie/aom/CPrimitiveObject.java:132 +#: ../aom/src/main/java/com/nedap/archie/aom/CObject.java:285 #, java-format msgid "type name {0} does not conform to {1}" msgstr "" @@ -1265,13 +1264,13 @@ msgstr "" msgid "value code validity. Each value code (at-code) used in a term constraint in the archetype definition must be defined in the term_definitions part of the terminology of the flattened form of the current archetype." msgstr "" -#: ../tools/src/main/java/com/nedap/archie/archetypevalidator/validations/BasicTerminologyValidation.java:140 +#: ../tools/src/main/java/com/nedap/archie/archetypevalidator/validations/BasicTerminologyValidation.java:143 #, java-format msgid "value code {0} is used in redefined value set {1}, but not present in its parent value set with members {2}" msgstr "" -#: ../tools/src/main/java/com/nedap/archie/archetypevalidator/validations/BasicTerminologyValidation.java:118 -#: ../tools/src/main/java/com/nedap/archie/archetypevalidator/validations/BasicTerminologyValidation.java:122 +#: ../tools/src/main/java/com/nedap/archie/archetypevalidator/validations/BasicTerminologyValidation.java:121 +#: ../tools/src/main/java/com/nedap/archie/archetypevalidator/validations/BasicTerminologyValidation.java:125 #, java-format msgid "value code {0} is used in value set {1}, but not present in terminology" msgstr "" @@ -1280,18 +1279,18 @@ msgstr "" msgid "value set assumed value code validity. Each value code (at-code) used as an assumed_value for a value set in a term constraint in the archetype definition must exist in the value set definition in the terminology for the identified value set." msgstr "" -#: ../tools/src/main/java/com/nedap/archie/archetypevalidator/validations/BasicTerminologyValidation.java:103 +#: ../tools/src/main/java/com/nedap/archie/archetypevalidator/validations/BasicTerminologyValidation.java:106 #, java-format msgid "value set code {0} is not present in terminology" msgstr "" -#: ../tools/src/main/java/com/nedap/archie/archetypevalidator/validations/BasicTerminologyValidation.java:109 -#: ../tools/src/main/java/com/nedap/archie/archetypevalidator/validations/BasicTerminologyValidation.java:113 +#: ../tools/src/main/java/com/nedap/archie/archetypevalidator/validations/BasicTerminologyValidation.java:112 +#: ../tools/src/main/java/com/nedap/archie/archetypevalidator/validations/BasicTerminologyValidation.java:116 #, java-format msgid "value set code {0} is used in value set {1}, but not present in terminology" msgstr "" -#: ../tools/src/main/java/com/nedap/archie/archetypevalidator/validations/BasicTerminologyValidation.java:135 +#: ../tools/src/main/java/com/nedap/archie/archetypevalidator/validations/BasicTerminologyValidation.java:138 #, java-format msgid "value set {0} has a specialized code, but the valueset it specialized cannot be found in the flat parent" msgstr "" @@ -1313,7 +1312,7 @@ msgstr "" msgid "{0} and {1}" msgstr "" -#: ../tools/src/main/java/com/nedap/archie/archetypevalidator/validations/ValidateAgainstReferenceModel.java:106 +#: ../tools/src/main/java/com/nedap/archie/archetypevalidator/validations/ValidateAgainstReferenceModel.java:99 #, java-format msgid "{0} is not a known attribute of {1}" msgstr "" diff --git a/tools/src/main/java/com/nedap/archie/archetypevalidator/ArchetypeValidator.java b/tools/src/main/java/com/nedap/archie/archetypevalidator/ArchetypeValidator.java index 0336d9321..cd6f1997a 100644 --- a/tools/src/main/java/com/nedap/archie/archetypevalidator/ArchetypeValidator.java +++ b/tools/src/main/java/com/nedap/archie/archetypevalidator/ArchetypeValidator.java @@ -1,6 +1,5 @@ package com.nedap.archie.archetypevalidator; -import com.google.common.base.Joiner; import com.nedap.archie.adlparser.modelconstraints.ReflectionConstraintImposer; import com.nedap.archie.aom.Archetype; import com.nedap.archie.aom.OperationalTemplate; @@ -215,17 +214,18 @@ public ValidationResult validate(Archetype archetype, FullArchetypeRepository re } catch (Exception e) { //this is probably an error in an included archetype, so ignore it here //the other archetype will not validate - ValidationMessage message = new ValidationMessage(ErrorType.OTHER, null, "Error during Operational template creation. This does not necessarily mean the current archetype has a problem, but perhaps one that is included with use_archetype: " + e); + ValidationMessage message = new ValidationMessage(ErrorType.OTHER, null, "Error during operational template creation. This does not necessarily mean the current archetype has a problem, but perhaps one that is included with use_archetype."); message.setWarning(true); messages.add(message); + logger.debug("Error during operational template creation", e); } result.setFlattened(flattened); if(result.passes()) { messages.addAll(runValidations(metaModel, flattened, repository, settings, flatParent, validationsPhase3)); } } catch (Exception e) { - messages.add(new ValidationMessage(ErrorType.OTHER, null, "flattening failed with exception " + e)); - logger.error("error during validation", e); + messages.add(new ValidationMessage(ErrorType.OTHER, null, "Unexpected error during flattening")); + logger.error("Unexpected error during flattening", e); } } @@ -246,10 +246,8 @@ private List runValidations(MetaModel metaModel, Archetype ar try { messages.addAll(validation.validate(metaModel, archetype, flatParent, repository, settings)); } catch (Exception e) { - logger.error("error running validation processor", e); - e.printStackTrace(); - messages.add(new ValidationMessage(ErrorType.OTHER, null, "error running validator : " + e.getClass().getSimpleName() + - Joiner.on("\n").join(e.getStackTrace()))); + logger.error("Unexpected error running validation processor", e); + messages.add(new ValidationMessage(ErrorType.OTHER, null, "Unexpected error running validation processor")); } } return messages; diff --git a/tools/src/main/java/com/nedap/archie/rmobjectvalidator/RMObjectValidator.java b/tools/src/main/java/com/nedap/archie/rmobjectvalidator/RMObjectValidator.java index 230501039..e34e4737f 100644 --- a/tools/src/main/java/com/nedap/archie/rmobjectvalidator/RMObjectValidator.java +++ b/tools/src/main/java/com/nedap/archie/rmobjectvalidator/RMObjectValidator.java @@ -13,6 +13,8 @@ import com.nedap.archie.rminfo.ModelInfoLookup; import com.nedap.archie.rminfo.RMTypeInfo; import org.openehr.utils.message.I18n; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import java.lang.reflect.InvocationTargetException; import java.util.ArrayList; @@ -26,6 +28,7 @@ * Created by pieter.bos on 15/02/16. */ public class RMObjectValidator extends RMObjectValidatingProcessor { + private static final Logger logger = LoggerFactory.getLogger(RMObjectValidator.class); private final MetaModel metaModel; private final OperationalTemplateProvider operationalTemplateProvider; @@ -167,13 +170,11 @@ private List validateInvariants(RMObjectWithPath obje } } catch (IllegalAccessException | InvocationTargetException e) { result.add(new RMObjectValidationMessage(null, joinPaths(pathSoFar, objectWithPath.getPath()), - I18n.t("Exception {0} invoking invariant {1} on {2}: {3}\n{4}", - e.getCause() == null ? e.getClass().getSimpleName() : e.getCause().getClass().getSimpleName(), + I18n.t("Unexpected error validating invariant {0} on {1}", invariantMethod.getAnnotation().value(), - typeInfo.getRmName(), - e.getCause() == null ? e.getMessage() : e.getCause().getMessage(), - Joiner.on("\n\t").join(e.getStackTrace())), + typeInfo.getRmName()), RMObjectValidationMessageType.EXCEPTION)); + logger.error("Unexpected error validating invariant {} on {}", invariantMethod.getAnnotation().value(), typeInfo.getRmName(), e); } } } From 828713d0cbafa959435bccbcd3278237d4989324 Mon Sep 17 00:00:00 2001 From: Jelte Zeilstra Date: Mon, 22 Sep 2025 13:02:19 +0200 Subject: [PATCH 15/25] Reformat Gradle files (#721) * Reformat Gradle files * Fix missing imports * Fix comments * Have a single newline at the end of each Gradle file --- adlchecker/build.gradle | 2 +- aom/build.gradle | 14 ++-- archie-utils/build.gradle | 8 +-- base/build.gradle | 6 +- bmm/build.gradle | 12 ++-- build.gradle | 102 ++++++++++++++--------------- gradle/jacoco.gradle | 57 ++++++++-------- gradle/publish-maven.gradle | 122 +++++++++++++++++------------------ grammars/build.gradle | 10 +-- json-schema/build.gradle | 28 ++++---- odin/build.gradle | 6 +- openehr-rm/build.gradle | 13 ++-- path-queries/build.gradle | 12 ++-- referencemodels/build.gradle | 14 ++-- test-rm/build.gradle | 15 +++-- tools/build.gradle | 28 ++++---- utils/build.gradle | 4 +- 17 files changed, 225 insertions(+), 228 deletions(-) diff --git a/adlchecker/build.gradle b/adlchecker/build.gradle index ef07c4738..d6f0e1815 100644 --- a/adlchecker/build.gradle +++ b/adlchecker/build.gradle @@ -15,4 +15,4 @@ run { args = ['archetypes', '--lint']//, '--outputFlat'] } -mainClassName='com.nedap.archie.adlchecker.AdlChecker' +mainClassName = 'com.nedap.archie.adlchecker.AdlChecker' diff --git a/aom/build.gradle b/aom/build.gradle index 2de9ebe81..675fb909f 100644 --- a/aom/build.gradle +++ b/aom/build.gradle @@ -1,10 +1,10 @@ description = "An OpenEHR archetype object model implementation, plus parser" dependencies { - api project(':grammars') - api project(':base') - api project(':odin') - api project(':utils') - api project(':bmm') - api project(':openehr-terminology') -} \ No newline at end of file + api project(':grammars') + api project(':base') + api project(':odin') + api project(':utils') + api project(':bmm') + api project(':openehr-terminology') +} diff --git a/archie-utils/build.gradle b/archie-utils/build.gradle index 64817f40d..99f013084 100644 --- a/archie-utils/build.gradle +++ b/archie-utils/build.gradle @@ -1,7 +1,7 @@ description = "Utils for the Archie OpenEHR library" dependencies { - api project(':base') - api project(':aom') - api project(':openehr-rm') -} \ No newline at end of file + api project(':base') + api project(':aom') + api project(':openehr-rm') +} diff --git a/base/build.gradle b/base/build.gradle index db69568f7..4c72910bb 100644 --- a/base/build.gradle +++ b/base/build.gradle @@ -1,6 +1,6 @@ description = "Base classes for an OpenEHR implementation" dependencies { - //only for the xpath grammar. perhaps include it here? - api project(':grammars') -} \ No newline at end of file + //only for the xpath grammar. perhaps include it here? + api project(':grammars') +} diff --git a/bmm/build.gradle b/bmm/build.gradle index 91063ab94..991adac95 100644 --- a/bmm/build.gradle +++ b/bmm/build.gradle @@ -1,8 +1,8 @@ - description = "A basic metadata model implementation" +description = "A basic metadata model implementation" dependencies { - api project(':base') - api project(':utils') - api project(':odin') - testImplementation project(':i18n') -} \ No newline at end of file + api project(':base') + api project(':utils') + api project(':odin') + testImplementation project(':i18n') +} diff --git a/build.gradle b/build.gradle index 7c3b9e39c..c02ab8097 100644 --- a/build.gradle +++ b/build.gradle @@ -1,21 +1,21 @@ plugins { - alias(libs.plugins.nexus.publish) + alias(libs.plugins.nexus.publish) } repositories { - mavenCentral() + mavenCentral() } allprojects { - version = '3.15.0' - group = 'com.nedap.healthcare.archie' - ext.gradleScriptDir = "${rootProject.projectDir}/gradle" - //archivesBaseName = 'archie' - - tasks.withType(Javadoc) { - options.addStringOption('Xdoclint:all', '-quiet') - } + version = '3.15.0' + group = 'com.nedap.healthcare.archie' + ext.gradleScriptDir = "${rootProject.projectDir}/gradle" + //archivesBaseName = 'archie' + + tasks.withType(Javadoc) { + options.addStringOption('Xdoclint:all', '-quiet') + } } gradle.ext.ossrhUsernameSafe = hasProperty('ossrhUsername') ? ossrhUsername : "" @@ -26,69 +26,67 @@ gradle.ext.isParallel = hasProperty('org.gradle.parallel') ? project.property('o apply from: "${gradleScriptDir}/publish-maven.gradle" - subprojects { - apply plugin: 'java-library' - - compileJava.options.encoding = "UTF-8" - compileTestJava.options.encoding = "UTF-8" + apply plugin: 'java-library' - repositories { - mavenCentral() - maven { url = 'https://jitpack.io' } - } + compileJava.options.encoding = "UTF-8" + compileTestJava.options.encoding = "UTF-8" - java { - toolchain { - languageVersion = JavaLanguageVersion.of(8) + repositories { + mavenCentral() + maven { url = 'https://jitpack.io' } } - withJavadocJar() - withSourcesJar() - } + java { + toolchain { + languageVersion = JavaLanguageVersion.of(8) + } + withJavadocJar() + withSourcesJar() + } - dependencies { - api(libs.slf4j.api) - api(libs.bundles.jackson) + dependencies { + api(libs.slf4j.api) - implementation(libs.guava) + api(libs.bundles.jackson) - implementation(libs.reflections) - implementation(libs.kryo) + implementation(libs.guava) - implementation(libs.commons.io) - implementation(libs.commons.text) - implementation(libs.commons.lang3) + implementation(libs.reflections) + implementation(libs.kryo) - //java 10 no longer has these included by default, so explicit dependency is needed. - api(libs.jaxb.api) - api(libs.jaxb.core) - runtimeOnly(libs.jaxb.impl) - api(libs.activation) + implementation(libs.commons.io) + implementation(libs.commons.text) + implementation(libs.commons.lang3) - api(libs.threeten.extra) + //java 10 no longer has these included by default, so explicit dependency is needed. + api(libs.jaxb.api) + api(libs.jaxb.core) + runtimeOnly(libs.jaxb.impl) + api(libs.activation) - testImplementation(libs.junit4) - testImplementation(libs.slf4j.simple) + api(libs.threeten.extra) - api(libs.zafarkhaja.semver) - } + testImplementation(libs.junit4) + testImplementation(libs.slf4j.simple) + api(libs.zafarkhaja.semver) + } - javadoc { - options.encoding = 'UTF-8' - } + javadoc { + options.encoding = 'UTF-8' + } - test { - testLogging { - events "failed" - exceptionFormat = "full" + test { + testLogging { + events "failed" + exceptionFormat = "full" + } } - } } diff --git a/gradle/jacoco.gradle b/gradle/jacoco.gradle index 9e7373cce..e89d29674 100644 --- a/gradle/jacoco.gradle +++ b/gradle/jacoco.gradle @@ -1,47 +1,46 @@ - //the generated ANTLR sources plus the OpenEHR Test RM implementation do not need coverage def excludedPaths = ["**/nedap/archie/adlparser/antlr**", "**/nedap/archie/openehrtestrm/**"] allprojects { - apply plugin: 'jacoco' + apply plugin: 'jacoco' } subprojects { - jacoco { - toolVersion = "0.8.7" - } + jacoco { + toolVersion = "0.8.7" + } - test { - testLogging { - events "failed" - exceptionFormat = "full" + test { + testLogging { + events "failed" + exceptionFormat = "full" + } } - } - jacocoTestReport { - reports { - xml.required = true - html.required = true - } - additionalSourceDirs.from = sourceSets.main.allSource.srcDirs - sourceDirectories.from = sourceSets.main.allSource.srcDirs - classDirectories.from = sourceSets.main.output - afterEvaluate { - classDirectories.from = classDirectories.files.collect { - fileTree(dir: it, excludes: excludedPaths) + jacocoTestReport { + reports { + xml.required = true + html.required = true } - } - } + additionalSourceDirs.from = sourceSets.main.allSource.srcDirs + sourceDirectories.from = sourceSets.main.allSource.srcDirs + classDirectories.from = sourceSets.main.output + afterEvaluate { + classDirectories.from = classDirectories.files.collect { + fileTree(dir: it, excludes: excludedPaths) + } + } + } - check.dependsOn jacocoTestReport + check.dependsOn jacocoTestReport } task jacocoRootReport(type: org.gradle.testing.jacoco.tasks.JacocoReport) { dependsOn = subprojects.test additionalSourceDirs.from = subprojects.sourceSets.main.allSource.srcDirs sourceDirectories.from = subprojects.sourceSets.main.allSource.srcDirs - classDirectories.from = subprojects.sourceSets.main.output - executionData.from = subprojects.findAll {!it.sourceSets.test.java.isEmpty()}.jacocoTestReport.executionData + classDirectories.from = subprojects.sourceSets.main.output + executionData.from = subprojects.findAll { !it.sourceSets.test.java.isEmpty() }.jacocoTestReport.executionData reports { html.required = true xml.required = true @@ -49,8 +48,8 @@ task jacocoRootReport(type: org.gradle.testing.jacoco.tasks.JacocoReport) { } afterEvaluate { - classDirectories.from = files(classDirectories.files.collect { - fileTree(dir: it, excludes: excludedPaths) - }) + classDirectories.from = files(classDirectories.files.collect { + fileTree(dir: it, excludes: excludedPaths) + }) } } diff --git a/gradle/publish-maven.gradle b/gradle/publish-maven.gradle index 1306fac7b..89f37d9a3 100644 --- a/gradle/publish-maven.gradle +++ b/gradle/publish-maven.gradle @@ -1,82 +1,82 @@ apply plugin: 'maven-publish' -if(gradle.ext.shouldSign) { - apply plugin: 'signing' - signing { - afterEvaluate { project -> - useGpgCmd() - sign publishing.publications +if (gradle.ext.shouldSign) { + apply plugin: 'signing' + signing { + afterEvaluate { project -> + useGpgCmd() + sign publishing.publications + } } - } } nexusPublishing { - repositories { - // see https://central.sonatype.org/publish/publish-portal-ossrh-staging-api/#configuration - sonatype { - nexusUrl.set(uri("https://ossrh-staging-api.central.sonatype.com/service/local/")) - snapshotRepositoryUrl.set(uri("https://central.sonatype.com/repository/maven-snapshots/")) + repositories { + // see https://central.sonatype.org/publish/publish-portal-ossrh-staging-api/#configuration + sonatype { + nexusUrl.set(uri("https://ossrh-staging-api.central.sonatype.com/service/local/")) + snapshotRepositoryUrl.set(uri("https://central.sonatype.com/repository/maven-snapshots/")) - username = project.hasProperty("centralTokenUsername") ? centralTokenUsername : "Unknown username" - password = project.hasProperty("centralTokenPassword") ? centralTokenPassword : "Unknown password" + username = project.hasProperty("centralTokenUsername") ? centralTokenUsername : "Unknown username" + password = project.hasProperty("centralTokenPassword") ? centralTokenPassword : "Unknown password" + } } - } } //now uploading will have to be configured on a per subproject basis subprojects { - publishing { + publishing { - publications { - "$project.name"(MavenPublication) { + publications { + "$project.name"(MavenPublication) { - afterEvaluate { - from components.java - artifactId = project.name - pom { - name = project.name - description = project.description - } - } + afterEvaluate { + from components.java + artifactId = project.name + pom { + name = project.name + description = project.description + } + } - pom { + pom { - url = "https://github.com/openEHR/archie" - organization { - name = "Nedap Healthcare" - url = "http://www.nedap-healthcare.com" - } - licenses { - license { - name = "Apache License, Version 2.0" - url = "http://www.apache.org/licenses/LICENSE-2.0" - distribution = "repo" - } - } - scm { - url = "https://github.com/openEHR/archie" - connection = "scm:git:git://github.com/openEHR/archie" - developerConnection = "scm:git:git://github.com/openEHR/archie" - } - developers { - developer { - id = "pieterbos" - name = "Pieter Bos" - email = "pieter.bos@nedap.com" - } - developer { - id = "tanja.dejong" - name = "Tanja de Jong" - email = "tanja.dejong@nedap.com" + url = "https://github.com/openEHR/archie" + organization { + name = "Nedap Healthcare" + url = "http://www.nedap-healthcare.com" + } + licenses { + license { + name = "Apache License, Version 2.0" + url = "http://www.apache.org/licenses/LICENSE-2.0" + distribution = "repo" + } + } + scm { + url = "https://github.com/openEHR/archie" + connection = "scm:git:git://github.com/openEHR/archie" + developerConnection = "scm:git:git://github.com/openEHR/archie" + } + developers { + developer { + id = "pieterbos" + name = "Pieter Bos" + email = "pieter.bos@nedap.com" + } + developer { + id = "tanja.dejong" + name = "Tanja de Jong" + email = "tanja.dejong@nedap.com" + } + } + issueManagement { + system = "Github" + url = "https://github.com/openEHR/archie/issues" + } + } } - } - issueManagement { - system = "Github" - url = "https://github.com/openEHR/archie/issues" - } } - } } - } } diff --git a/grammars/build.gradle b/grammars/build.gradle index fbe1f5185..8d2143cb2 100644 --- a/grammars/build.gradle +++ b/grammars/build.gradle @@ -2,20 +2,20 @@ description = "grammars for parsing ADL, ODIN and xpath" apply plugin: 'antlr' generateGrammarSource { //antlr4 - outputDirectory = new File("${project.buildDir}/generated-src/antlr/main/com/nedap/archie/adlparser/antlr".toString()) + outputDirectory = new File("${project.buildDir}/generated-src/antlr/main/com/nedap/archie/adlparser/antlr".toString()) arguments = ['-visitor', '-package', 'com.nedap.archie.adlparser.antlr', '-encoding', 'utf-8'] + arguments } sourcesJar { - dependsOn generateGrammarSource + dependsOn generateGrammarSource } classes { - dependsOn generateGrammarSource + dependsOn generateGrammarSource } dependencies { - antlr(libs.antlr4) - api(libs.antlr4.runtime) + antlr(libs.antlr4) + api(libs.antlr4.runtime) } diff --git a/json-schema/build.gradle b/json-schema/build.gradle index 86f89c413..5d5e1be12 100644 --- a/json-schema/build.gradle +++ b/json-schema/build.gradle @@ -13,15 +13,15 @@ plugins { description = "A tool that generates the official ITS-JSON json schema from the BMM files" -import com.nedap.archie.json.OpenEHRRmJSONSchemaCreator; -import com.nedap.archie.json.JsonSchemaUriProvider; -import com.nedap.archie.json.JsonSchemaUri; -import com.nedap.archie.json.ItsJsonUriProvider; -import org.openehr.referencemodels.BuiltinReferenceModels; -import jakarta.json.*; -import jakarta.json.stream.JsonGenerator; -import org.openehr.bmm.core.BmmClass; +import com.nedap.archie.json.ItsJsonUriProvider +import com.nedap.archie.json.JsonSchemaUri +import com.nedap.archie.json.OpenEHRRmJSONSchemaCreator +import jakarta.json.Json +import jakarta.json.JsonObject +import jakarta.json.JsonWriterFactory +import jakarta.json.stream.JsonGenerator +import org.openehr.referencemodels.BuiltinReferenceModels abstract class JsonSchemaCreationTask extends DefaultTask { @@ -81,23 +81,23 @@ abstract class JsonSchemaCreationTask extends DefaultTask { } def printSchemas(String version, Map schemas, JsonWriterFactory jsonWriterFactory) { - for(JsonSchemaUri name:schemas.keySet()) { + for (JsonSchemaUri name : schemas.keySet()) { def schema = schemas.get(name); def versionDir = getOutputDir().get().dir(version) - if(!versionDir.getAsFile().exists()) { + if (!versionDir.getAsFile().exists()) { versionDir.getAsFile().mkdir(); } System.out.println(name.getFilename()); def split = name.getFilename().split("/"); def fileName = null; - for(int i = 0; i < split.length-1;i++) { + for (int i = 0; i < split.length - 1; i++) { String dir = split[i]; versionDir = versionDir.dir(dir); - if(!versionDir.getAsFile().exists()) { + if (!versionDir.getAsFile().exists()) { versionDir.getAsFile().mkdir(); } } - fileName = split[split.length-1]; + fileName = split[split.length - 1]; versionDir.file(fileName).getAsFile().withWriter { writer -> jsonWriterFactory.createWriter(writer).write(schema); } @@ -109,5 +109,3 @@ abstract class JsonSchemaCreationTask extends DefaultTask { tasks.register('generateJsonSchema', JsonSchemaCreationTask) { outputDir = file(layout.buildDirectory.dir('schemaOutput')) } - - diff --git a/odin/build.gradle b/odin/build.gradle index 6ee48ea32..55875080b 100644 --- a/odin/build.gradle +++ b/odin/build.gradle @@ -1,6 +1,6 @@ description = "An odin implementation" dependencies { - api project(':grammars') - api project(':base') -} \ No newline at end of file + api project(':grammars') + api project(':base') +} diff --git a/openehr-rm/build.gradle b/openehr-rm/build.gradle index b9427b505..2866e4c89 100644 --- a/openehr-rm/build.gradle +++ b/openehr-rm/build.gradle @@ -1,9 +1,10 @@ description = "An implementation of the openehr reference model" dependencies { - api project(':base') - api project(':aom') //modelInfoLookup depends on CPrimitiveObject to convert from AOM objects to RM objects. So we need this dependency, at least for now - api project(':path-queries') - api project(':utils') - testImplementation project(':archie-utils') -} \ No newline at end of file + api project(':base') + //modelInfoLookup depends on CPrimitiveObject to convert from AOM objects to RM objects. So we need the AOM dependency, at least for now + api project(':aom') + api project(':path-queries') + api project(':utils') + testImplementation project(':archie-utils') +} diff --git a/path-queries/build.gradle b/path-queries/build.gradle index c2132c65f..3eaaa9512 100644 --- a/path-queries/build.gradle +++ b/path-queries/build.gradle @@ -1,9 +1,9 @@ description = "An implementation of openehr path queries" dependencies { - //only for the xpath grammar. perhaps include it here? - api project(':grammars') - api project(':base') - api project(':aom') //modelInfoLookup is here and should be split and moved - testImplementation project(':openehr-rm') -} \ No newline at end of file + //only for the xpath grammar. perhaps include it here? + api project(':grammars') + api project(':base') + api project(':aom') //modelInfoLookup is here and should be split and moved + testImplementation project(':openehr-rm') +} diff --git a/referencemodels/build.gradle b/referencemodels/build.gradle index 9fb6868ef..ab534c052 100644 --- a/referencemodels/build.gradle +++ b/referencemodels/build.gradle @@ -1,10 +1,10 @@ description = "tools to access OpenEHR reference model metadata" dependencies { - api project(':bmm') - api project(':odin') - api project(':aom') - testImplementation project(':openehr-rm') - testImplementation project(':test-rm') - testImplementation project(':archie-utils') -} \ No newline at end of file + api project(':bmm') + api project(':odin') + api project(':aom') + testImplementation project(':openehr-rm') + testImplementation project(':test-rm') + testImplementation project(':archie-utils') +} diff --git a/test-rm/build.gradle b/test-rm/build.gradle index d9a293192..76e32b58f 100644 --- a/test-rm/build.gradle +++ b/test-rm/build.gradle @@ -1,8 +1,9 @@ -description="OpenEHR Test RM package" +description = "OpenEHR Test RM package" dependencies { - api project(':base') - api project(':aom') //modelInfoLookup depends on CPrimitiveObject to convert from AOM objects to RM objects. So we need this dependency, at least for now - api project(':path-queries') - api project(':utils') - api project(':openehr-rm') -} \ No newline at end of file + api project(':base') + //modelInfoLookup depends on CPrimitiveObject to convert from AOM objects to RM objects. So we need the AOM dependency, at least for now + api project(':aom') + api project(':path-queries') + api project(':utils') + api project(':openehr-rm') +} diff --git a/tools/build.gradle b/tools/build.gradle index 69b9f1c73..24265b5e4 100644 --- a/tools/build.gradle +++ b/tools/build.gradle @@ -1,19 +1,19 @@ description = "tools that operate on the archie reference models and archetype object model" dependencies { - api project(':grammars') - api project(':base') - api project(':aom') - api project(':bmm') - api project(':path-queries') - api project(':utils') - api project(':openehr-terminology') - testImplementation project(':openehr-rm') - testImplementation project(':archie-utils') - testImplementation project(':i18n') - testImplementation project(':test-rm') - testImplementation project(':referencemodels') + api project(':grammars') + api project(':base') + api project(':aom') + api project(':bmm') + api project(':path-queries') + api project(':utils') + api project(':openehr-terminology') + testImplementation project(':openehr-rm') + testImplementation project(':archie-utils') + testImplementation project(':i18n') + testImplementation project(':test-rm') + testImplementation project(':referencemodels') - api(libs.leadpony.justify) - api(variantOf(libs.jakarta.json) {classifier("module") }) + api(libs.leadpony.justify) + api(variantOf(libs.jakarta.json) { classifier("module") }) } diff --git a/utils/build.gradle b/utils/build.gradle index 89a836df2..e2c0cd38d 100644 --- a/utils/build.gradle +++ b/utils/build.gradle @@ -1,5 +1,5 @@ description = "Basic utilities for use in the archie library" dependencies { - api project(':base') -} \ No newline at end of file + api project(':base') +} From d86be8bba776d4dfd49c7ae61b6f2e7342ca625f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 21 Oct 2025 13:15:57 +0200 Subject: [PATCH 16/25] Bump org.apache.commons:commons-lang3 from 3.18.0 to 3.19.0 (#722) Bumps org.apache.commons:commons-lang3 from 3.18.0 to 3.19.0. --- updated-dependencies: - dependency-name: org.apache.commons:commons-lang3 dependency-version: 3.19.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index e958d1d6f..f4500287f 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -19,7 +19,7 @@ antlr4-runtime = { module = "org.antlr:antlr4-runtime", version.ref = "antlr" } commons-io = { module = "commons-io:commons-io", version = "2.20.0" } -commons-lang3 = { module = "org.apache.commons:commons-lang3", version = "3.18.0" } +commons-lang3 = { module = "org.apache.commons:commons-lang3", version = "3.19.0" } commons-text = { module = "org.apache.commons:commons-text", version = "1.14.0" } From 72d239054755093a86ce498cbfcf1b0d16428990 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 21 Oct 2025 13:16:05 +0200 Subject: [PATCH 17/25] Bump com.google.guava:guava from 33.4.8-jre to 33.5.0-jre (#720) Bumps [com.google.guava:guava](https://github.com/google/guava) from 33.4.8-jre to 33.5.0-jre. - [Release notes](https://github.com/google/guava/releases) - [Commits](https://github.com/google/guava/commits) --- updated-dependencies: - dependency-name: com.google.guava:guava dependency-version: 33.5.0-jre dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index f4500287f..f988013aa 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -23,7 +23,7 @@ commons-lang3 = { module = "org.apache.commons:commons-lang3", version = "3.19.0 commons-text = { module = "org.apache.commons:commons-text", version = "1.14.0" } -guava = { module = "com.google.guava:guava", version = "33.4.8-jre" } +guava = { module = "com.google.guava:guava", version = "33.5.0-jre" } jackson-annotations = { module = "com.fasterxml.jackson.core:jackson-annotations", version.ref = "jackson" } jackson-databind = { module = "com.fasterxml.jackson.core:jackson-databind", version.ref = "jackson" } From 57a60720b13ac1f2085356c96102d701e5fd0b00 Mon Sep 17 00:00:00 2001 From: Mattijs Kuhlmann <47526389+MattijsK@users.noreply.github.com> Date: Wed, 5 Nov 2025 14:02:41 +0100 Subject: [PATCH 18/25] Forwards compatibility of ResourceDescription.lifecycleState: also deserialize from String (#725) * Initial forwards compatibility and tests * Remove some comments * Correct documentation --- .../adapters/LifecycleStateXmlAdapter.java | 86 +++++ .../xml/types/XmlResourceDescription.java | 3 + .../com/nedap/archie/json/AOMJacksonTest.java | 37 ++ .../com/nedap/archie/xml/JAXBAOMTest.java | 41 +++ ...th_overlay_empty_lifecycle_state_block.xml | 329 +++++++++++++++++ ...nt_with_overlay_lifecycle_state_string.xml | 329 +++++++++++++++++ ...with_overlay_lifecycle_state_term_code.xml | 331 ++++++++++++++++++ ..._overlay_newline_lifecycle_state_block.xml | 331 ++++++++++++++++++ 8 files changed, 1487 insertions(+) create mode 100644 aom/src/main/java/com/nedap/archie/xml/adapters/LifecycleStateXmlAdapter.java create mode 100644 tools/src/test/resources/com/nedap/archie/xml/to_flatten_parent_with_overlay_empty_lifecycle_state_block.xml create mode 100644 tools/src/test/resources/com/nedap/archie/xml/to_flatten_parent_with_overlay_lifecycle_state_string.xml create mode 100644 tools/src/test/resources/com/nedap/archie/xml/to_flatten_parent_with_overlay_lifecycle_state_term_code.xml create mode 100644 tools/src/test/resources/com/nedap/archie/xml/to_flatten_parent_with_overlay_newline_lifecycle_state_block.xml diff --git a/aom/src/main/java/com/nedap/archie/xml/adapters/LifecycleStateXmlAdapter.java b/aom/src/main/java/com/nedap/archie/xml/adapters/LifecycleStateXmlAdapter.java new file mode 100644 index 000000000..8aa02a030 --- /dev/null +++ b/aom/src/main/java/com/nedap/archie/xml/adapters/LifecycleStateXmlAdapter.java @@ -0,0 +1,86 @@ +package com.nedap.archie.xml.adapters; + +import com.nedap.archie.base.terminology.TerminologyCode; +import org.w3c.dom.Element; + +import javax.xml.bind.annotation.XmlAnyElement; +import javax.xml.bind.annotation.XmlMixed; +import javax.xml.bind.annotation.XmlRootElement; +import javax.xml.bind.annotation.adapters.XmlAdapter; +import java.util.List; + +/** + * JAXB adapter for deserializing lifecycle_state from XML. + *

+ * Supports two XML representations: + * 1. Future/simple text form: {@code published} + * 2. Current form of type terminology_code with a code_string: {@code published} + * + * The adapter always returns the lifecycle state value as a terminology_code with a code_string value, regardless of the input format. + */ +public class LifecycleStateXmlAdapter extends XmlAdapter { + + /** + * Unmarshalls a lifecycle_state element to a terminology_code. + * + * @param holder the mixed content holder containing the element's content + * @return the lifecycle_state value as a terminology_code, or null if no value is found + */ + @Override + public TerminologyCode unmarshal(MixedHolder holder) { + if (holder == null || holder.content == null || holder.content.isEmpty()) { + return null; + } + + TerminologyCode resultTerminologyCode = new TerminologyCode(); + + for (Object o : holder.content) { + if (o instanceof Element) { + Element element = (Element) o; + String elementName = element.getLocalName() != null ? element.getLocalName() : element.getNodeName(); + + if ("code_string".equals(elementName)) { + String text = element.getTextContent(); + if (text != null) { + resultTerminologyCode.setCodeString(text.trim()); + return resultTerminologyCode; + } + } + } + } + + for (Object o : holder.content) { + if (o instanceof String) { + String text = ((String) o).trim(); + if (!text.isEmpty()) { + resultTerminologyCode.setCodeString(text.trim()); + return resultTerminologyCode; + } + } + } + + return null; + } + + /** + * Not implemented for this adapter as marshaling is not required. + */ + @Override + public MixedHolder marshal(TerminologyCode v) { + return null; + } + + /** + * Holder class for mixed XML content (text and elements). + *

+ * Used by JAXB to capture both text nodes and child elements within the + * lifecycle_state element. The content list may include whitespace strings + * (from XML formatting) and Element objects. + */ + @XmlRootElement(name = "lifecycle_state") + public static class MixedHolder { + @XmlMixed + @XmlAnyElement(lax = true) + public List content; + } +} \ No newline at end of file diff --git a/aom/src/main/java/com/nedap/archie/xml/types/XmlResourceDescription.java b/aom/src/main/java/com/nedap/archie/xml/types/XmlResourceDescription.java index 976ed0321..8fb5d8c7f 100644 --- a/aom/src/main/java/com/nedap/archie/xml/types/XmlResourceDescription.java +++ b/aom/src/main/java/com/nedap/archie/xml/types/XmlResourceDescription.java @@ -1,11 +1,13 @@ package com.nedap.archie.xml.types; import com.nedap.archie.base.terminology.TerminologyCode; +import com.nedap.archie.xml.adapters.LifecycleStateXmlAdapter; import javax.xml.bind.annotation.XmlAccessType; import javax.xml.bind.annotation.XmlAccessorType; import javax.xml.bind.annotation.XmlElement; import javax.xml.bind.annotation.XmlType; +import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter; import java.util.List; /** @@ -24,6 +26,7 @@ public class XmlResourceDescription { @XmlElement(name = "other_contributors") private List otherContributors; @XmlElement(name = "lifecycle_state", required = true) + @XmlJavaTypeAdapter(LifecycleStateXmlAdapter.class) private TerminologyCode lifecycleState; @XmlElement(name="custodian_namespace") private String custodianNamespace; diff --git a/tools/src/test/java/com/nedap/archie/json/AOMJacksonTest.java b/tools/src/test/java/com/nedap/archie/json/AOMJacksonTest.java index 9d416eff5..4f1b7f1d0 100644 --- a/tools/src/test/java/com/nedap/archie/json/AOMJacksonTest.java +++ b/tools/src/test/java/com/nedap/archie/json/AOMJacksonTest.java @@ -8,6 +8,7 @@ import com.nedap.archie.aom.Archetype; import com.nedap.archie.aom.ArchetypeSlot; import com.nedap.archie.aom.CComplexObject; +import com.nedap.archie.aom.ResourceDescription; import com.nedap.archie.aom.primitives.CDuration; import com.nedap.archie.aom.primitives.CString; import com.nedap.archie.aom.primitives.CTerminologyCode; @@ -71,6 +72,42 @@ public void roundTripDeliriumObservationScreening() throws Exception { } } + @Test + public void parseLifecycleStateStringTest() throws Exception { + ObjectMapper objectMapper = JacksonUtil.getObjectMapper(ArchieJacksonConfiguration.createLegacyConfiguration()); + String resourceDescriptionJson = "{ \"lifecycle_state\" :\"unmanaged\" }"; + ResourceDescription resourceDescription = objectMapper.readValue(resourceDescriptionJson, ResourceDescription.class); + // assert that the lifecycle state is set to unmanaged + assertEquals("unmanaged", resourceDescription.getLifecycleState().getCodeString()); + } + + @Test + public void parseLifecycleStateTerminologyCodeTest() throws Exception { + ObjectMapper objectMapper = JacksonUtil.getObjectMapper(ArchieJacksonConfiguration.createLegacyConfiguration()); + String resourceDescriptionJson = "{ \"lifecycle_state\" : { \"code_string\" : \"unmanaged\" }}"; + ResourceDescription resourceDescription = objectMapper.readValue(resourceDescriptionJson, ResourceDescription.class); + // assert that the lifecycle state is set to unmanaged + assertEquals("unmanaged", resourceDescription.getLifecycleState().getCodeString()); + } + + @Test + public void parseLifecycleStateTerminologyCodeCodeStringNullTest() throws Exception { + ObjectMapper objectMapper = JacksonUtil.getObjectMapper(ArchieJacksonConfiguration.createLegacyConfiguration()); + String resourceDescriptionJson = "{ \"lifecycle_state\" : { \"code_string\" : null }}"; + ResourceDescription resourceDescription = objectMapper.readValue(resourceDescriptionJson, ResourceDescription.class); + // assert that the lifecycle state is set to unmanaged + assertNull(resourceDescription.getLifecycleState().getCodeString()); + } + + @Test + public void parseLifecycleStateTerminologyCodeNoCodeStringTest() throws Exception { + ObjectMapper objectMapper = JacksonUtil.getObjectMapper(ArchieJacksonConfiguration.createLegacyConfiguration()); + String resourceDescriptionJson = "{ \"lifecycle_state\" : { \"placeholder\" : \"placeholder\" }}"; + ResourceDescription resourceDescription = objectMapper.readValue(resourceDescriptionJson, ResourceDescription.class); + // assert that the lifecycle state is set to unmanaged + assertNull(resourceDescription.getLifecycleState().getCodeString()); + } + @Test public void motricityIndex() throws Exception { try(InputStream stream = getClass().getResourceAsStream( "/com/nedap/archie/rules/evaluation/openEHR-EHR-OBSERVATION.motricity_index.v1.0.0.adls")) { diff --git a/tools/src/test/java/com/nedap/archie/xml/JAXBAOMTest.java b/tools/src/test/java/com/nedap/archie/xml/JAXBAOMTest.java index f18b63052..316f91d96 100644 --- a/tools/src/test/java/com/nedap/archie/xml/JAXBAOMTest.java +++ b/tools/src/test/java/com/nedap/archie/xml/JAXBAOMTest.java @@ -17,6 +17,7 @@ import javax.xml.bind.Marshaller; import javax.xml.bind.Unmarshaller; +import java.io.InputStream; import java.io.StringReader; import java.io.StringWriter; import java.time.temporal.TemporalAmount; @@ -285,4 +286,44 @@ public void templateXml() throws Exception { } + @Test + public void parseWithLifecycleStateString() throws Exception { + try(InputStream stream = getClass().getResourceAsStream("to_flatten_parent_with_overlay_lifecycle_state_string.xml")) { + Unmarshaller unmarshaller = JAXBUtil.getArchieJAXBContext().createUnmarshaller(); + Archetype unmarshalled = (Archetype) unmarshaller.unmarshal(stream); + // assert that the lifecycle state is set to published + assertEquals("published", unmarshalled.getDescription().getLifecycleState().getCodeString()); + } + } + + @Test + public void parseWithLifecycleStateTerminologyCode() throws Exception { + try(InputStream stream = getClass().getResourceAsStream("to_flatten_parent_with_overlay_lifecycle_state_term_code.xml")) { + Unmarshaller unmarshaller = JAXBUtil.getArchieJAXBContext().createUnmarshaller(); + Archetype unmarshalled = (Archetype) unmarshaller.unmarshal(stream); + // assert that the lifecycle state is set to published + assertEquals("published", unmarshalled.getDescription().getLifecycleState().getCodeString()); + } + } + + @Test + public void parseWithEmptyLifecycleStateBlock() throws Exception { + try(InputStream stream = getClass().getResourceAsStream("to_flatten_parent_with_overlay_empty_lifecycle_state_block.xml")) { + Unmarshaller unmarshaller = JAXBUtil.getArchieJAXBContext().createUnmarshaller(); + Archetype unmarshalled = (Archetype) unmarshaller.unmarshal(stream); + // assert that the lifecycle state is set to published + assertEquals(null, unmarshalled.getDescription().getLifecycleState()); + } + } + + @Test + public void parseWithNewlineLifecycleStateBlock() throws Exception { + try(InputStream stream = getClass().getResourceAsStream("to_flatten_parent_with_overlay_newline_lifecycle_state_block.xml")) { + Unmarshaller unmarshaller = JAXBUtil.getArchieJAXBContext().createUnmarshaller(); + Archetype unmarshalled = (Archetype) unmarshaller.unmarshal(stream); + // assert that the lifecycle state is set to published + assertEquals(null, unmarshalled.getDescription().getLifecycleState()); + } + } + } diff --git a/tools/src/test/resources/com/nedap/archie/xml/to_flatten_parent_with_overlay_empty_lifecycle_state_block.xml b/tools/src/test/resources/com/nedap/archie/xml/to_flatten_parent_with_overlay_empty_lifecycle_state_block.xml new file mode 100644 index 000000000..04a638191 --- /dev/null +++ b/tools/src/test/resources/com/nedap/archie/xml/to_flatten_parent_with_overlay_empty_lifecycle_state_block.xml @@ -0,0 +1,329 @@ + + + + Pieter Bos + + copyright © 2004 openEHR Foundation <http://www.openEHR.org> +
+ + ISO_639-1 + en + + Test for flattening + ADL + test +
+
+ + ISO_639-1 + en + + + + + false + + + true + + false + false + + 1 + + + + + 1 + + + false + + + true + + false + false + + 3 + 3 + + + + + false + + + false + + + 0.0 + 1000.0 + + + + + false + + mmHg + + + + false + + + 1 + 1 + + + + + + false + + + 0.0 + 1000.0 + + + + + false + + mmHg + + + + false + + + 1 + 1 + + + + + + + 0.0 + 1000.0 + + + + mmHg + + + + 1 + 1 + + + + + + + + + + false + + + false + + + 0.0 + 1000.0 + + + + + false + + mmHg + + + + false + + + 1 + 1 + + + + + + false + + + 0.0 + 1000.0 + + + + + false + + mmHg + + + + false + + + 1 + 1 + + + + + + + 0.0 + 1000.0 + + + + mmHg + + + + 1 + 1 + + + + + + + + + + false + + + false + + + 0.0 + 1000.0 + + + + + false + + mmHg + + + + false + + + 1 + 1 + + + + + + false + + + 0.0 + 1000.0 + + + + + false + + mmHg + + + + false + + + 1 + 1 + + + + + + + 0.0 + 1000.0 + + + + mmHg + + + + 1 + 1 + + + + + + + + + + + + + + + + + id1 + + + The local measurement of arterial blood pressure which is a surrogate for arterial. pressure in the systemic circulation. Most commonly, use of the term 'blood pressure' refers to measurement of brachial artery pressure in the upper arm. + Blood Pressure + + + any event + any event + + + Systolic Pressure + systolic + + + -- diastolic pressure + diastolic pressure + + + testing 1 2 3 + pressure difference + + + ingocnito mode activated + some subject + + + + + + /subject + hide + + local + at12 + + + + /data[id2]/events[id3]/data[id4]/items[id5] + show + + + /data[id2]/events[id3]/data[id4]/items[id6] + show + + +
diff --git a/tools/src/test/resources/com/nedap/archie/xml/to_flatten_parent_with_overlay_lifecycle_state_string.xml b/tools/src/test/resources/com/nedap/archie/xml/to_flatten_parent_with_overlay_lifecycle_state_string.xml new file mode 100644 index 000000000..1393c0900 --- /dev/null +++ b/tools/src/test/resources/com/nedap/archie/xml/to_flatten_parent_with_overlay_lifecycle_state_string.xml @@ -0,0 +1,329 @@ + + + + Pieter Bos + published + copyright © 2004 openEHR Foundation <http://www.openEHR.org> +
+ + ISO_639-1 + en + + Test for flattening + ADL + test +
+
+ + ISO_639-1 + en + + + + + false + + + true + + false + false + + 1 + + + + + 1 + + + false + + + true + + false + false + + 3 + 3 + + + + + false + + + false + + + 0.0 + 1000.0 + + + + + false + + mmHg + + + + false + + + 1 + 1 + + + + + + false + + + 0.0 + 1000.0 + + + + + false + + mmHg + + + + false + + + 1 + 1 + + + + + + + 0.0 + 1000.0 + + + + mmHg + + + + 1 + 1 + + + + + + + + + + false + + + false + + + 0.0 + 1000.0 + + + + + false + + mmHg + + + + false + + + 1 + 1 + + + + + + false + + + 0.0 + 1000.0 + + + + + false + + mmHg + + + + false + + + 1 + 1 + + + + + + + 0.0 + 1000.0 + + + + mmHg + + + + 1 + 1 + + + + + + + + + + false + + + false + + + 0.0 + 1000.0 + + + + + false + + mmHg + + + + false + + + 1 + 1 + + + + + + false + + + 0.0 + 1000.0 + + + + + false + + mmHg + + + + false + + + 1 + 1 + + + + + + + 0.0 + 1000.0 + + + + mmHg + + + + 1 + 1 + + + + + + + + + + + + + + + + + id1 + + + The local measurement of arterial blood pressure which is a surrogate for arterial. pressure in the systemic circulation. Most commonly, use of the term 'blood pressure' refers to measurement of brachial artery pressure in the upper arm. + Blood Pressure + + + any event + any event + + + Systolic Pressure + systolic + + + -- diastolic pressure + diastolic pressure + + + testing 1 2 3 + pressure difference + + + ingocnito mode activated + some subject + + + + + + /subject + hide + + local + at12 + + + + /data[id2]/events[id3]/data[id4]/items[id5] + show + + + /data[id2]/events[id3]/data[id4]/items[id6] + show + + +
diff --git a/tools/src/test/resources/com/nedap/archie/xml/to_flatten_parent_with_overlay_lifecycle_state_term_code.xml b/tools/src/test/resources/com/nedap/archie/xml/to_flatten_parent_with_overlay_lifecycle_state_term_code.xml new file mode 100644 index 000000000..54845877b --- /dev/null +++ b/tools/src/test/resources/com/nedap/archie/xml/to_flatten_parent_with_overlay_lifecycle_state_term_code.xml @@ -0,0 +1,331 @@ + + + + Pieter Bos + + published + + copyright © 2004 openEHR Foundation <http://www.openEHR.org> +
+ + ISO_639-1 + en + + Test for (de)serialization + ADL + test +
+
+ + ISO_639-1 + en + + + + + false + + + true + + false + false + + 1 + + + + + 1 + + + false + + + true + + false + false + + 3 + 3 + + + + + false + + + false + + + 0.0 + 1000.0 + + + + + false + + mmHg + + + + false + + + 1 + 1 + + + + + + false + + + 0.0 + 1000.0 + + + + + false + + mmHg + + + + false + + + 1 + 1 + + + + + + + 0.0 + 1000.0 + + + + mmHg + + + + 1 + 1 + + + + + + + + + + false + + + false + + + 0.0 + 1000.0 + + + + + false + + mmHg + + + + false + + + 1 + 1 + + + + + + false + + + 0.0 + 1000.0 + + + + + false + + mmHg + + + + false + + + 1 + 1 + + + + + + + 0.0 + 1000.0 + + + + mmHg + + + + 1 + 1 + + + + + + + + + + false + + + false + + + 0.0 + 1000.0 + + + + + false + + mmHg + + + + false + + + 1 + 1 + + + + + + false + + + 0.0 + 1000.0 + + + + + false + + mmHg + + + + false + + + 1 + 1 + + + + + + + 0.0 + 1000.0 + + + + mmHg + + + + 1 + 1 + + + + + + + + + + + + + + + + + id1 + + + The local measurement of arterial blood pressure which is a surrogate for arterial. pressure in the systemic circulation. Most commonly, use of the term 'blood pressure' refers to measurement of brachial artery pressure in the upper arm. + Blood Pressure + + + any event + any event + + + Systolic Pressure + systolic + + + -- diastolic pressure + diastolic pressure + + + testing 1 2 3 + pressure difference + + + ingocnito mode activated + some subject + + + + + + /subject + hide + + local + at12 + + + + /data[id2]/events[id3]/data[id4]/items[id5] + show + + + /data[id2]/events[id3]/data[id4]/items[id6] + show + + +
diff --git a/tools/src/test/resources/com/nedap/archie/xml/to_flatten_parent_with_overlay_newline_lifecycle_state_block.xml b/tools/src/test/resources/com/nedap/archie/xml/to_flatten_parent_with_overlay_newline_lifecycle_state_block.xml new file mode 100644 index 000000000..c1ce5877d --- /dev/null +++ b/tools/src/test/resources/com/nedap/archie/xml/to_flatten_parent_with_overlay_newline_lifecycle_state_block.xml @@ -0,0 +1,331 @@ + + + + Pieter Bos + + + + copyright © 2004 openEHR Foundation <http://www.openEHR.org> +
+ + ISO_639-1 + en + + Test for flattening + ADL + test +
+
+ + ISO_639-1 + en + + + + + false + + + true + + false + false + + 1 + + + + + 1 + + + false + + + true + + false + false + + 3 + 3 + + + + + false + + + false + + + 0.0 + 1000.0 + + + + + false + + mmHg + + + + false + + + 1 + 1 + + + + + + false + + + 0.0 + 1000.0 + + + + + false + + mmHg + + + + false + + + 1 + 1 + + + + + + + 0.0 + 1000.0 + + + + mmHg + + + + 1 + 1 + + + + + + + + + + false + + + false + + + 0.0 + 1000.0 + + + + + false + + mmHg + + + + false + + + 1 + 1 + + + + + + false + + + 0.0 + 1000.0 + + + + + false + + mmHg + + + + false + + + 1 + 1 + + + + + + + 0.0 + 1000.0 + + + + mmHg + + + + 1 + 1 + + + + + + + + + + false + + + false + + + 0.0 + 1000.0 + + + + + false + + mmHg + + + + false + + + 1 + 1 + + + + + + false + + + 0.0 + 1000.0 + + + + + false + + mmHg + + + + false + + + 1 + 1 + + + + + + + 0.0 + 1000.0 + + + + mmHg + + + + 1 + 1 + + + + + + + + + + + + + + + + + id1 + + + The local measurement of arterial blood pressure which is a surrogate for arterial. pressure in the systemic circulation. Most commonly, use of the term 'blood pressure' refers to measurement of brachial artery pressure in the upper arm. + Blood Pressure + + + any event + any event + + + Systolic Pressure + systolic + + + -- diastolic pressure + diastolic pressure + + + testing 1 2 3 + pressure difference + + + ingocnito mode activated + some subject + + + + + + /subject + hide + + local + at12 + + + + /data[id2]/events[id3]/data[id4]/items[id5] + show + + + /data[id2]/events[id3]/data[id4]/items[id6] + show + + +
From a3ac4e69c8be7349a2d81c9eff10c93f684948ee Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 26 Nov 2025 17:20:00 +0700 Subject: [PATCH 19/25] Bump jacksonVersion from 2.19.2 to 2.20.0 (#705) * Bump jacksonVersion from 2.19.2 to 2.20.0 Bumps `jacksonVersion` from 2.19.2 to 2.20.0. Updates `com.fasterxml.jackson.core:jackson-annotations` from 2.19.2 to 2.20.0 Updates `com.fasterxml.jackson.core:jackson-databind` from 2.19.2 to 2.20.0 - [Commits](https://github.com/FasterXML/jackson/commits) Updates `com.fasterxml.jackson.datatype:jackson-datatype-jsr310` from 2.19.2 to 2.20.0 --- updated-dependencies: - dependency-name: com.fasterxml.jackson.core:jackson-annotations dependency-version: 2.20.0 dependency-type: direct:production update-type: version-update:semver-minor - dependency-name: com.fasterxml.jackson.core:jackson-databind dependency-version: 2.20.0 dependency-type: direct:production update-type: version-update:semver-minor - dependency-name: com.fasterxml.jackson.datatype:jackson-datatype-jsr310 dependency-version: 2.20.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] * Jackson 2.20* deprecation fixes --------- Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Mattijs Kuhlmann --- .../nedap/archie/json/ArchieRMObjectMapperProvider.java | 2 +- .../src/main/java/com/nedap/archie/json/JacksonUtil.java | 2 +- .../openehr/bmm/v2/persistence/jackson/BmmJacksonUtil.java | 2 +- gradle/libs.versions.toml | 5 +++-- .../archie/serializer/odin/AdlOdinToJsonConverter.java | 2 +- .../nedap/archie/serializer/odin/OdinToJsonConverter.java | 4 ++-- .../src/main/java/org/openehr/odin/jackson/ODINMapper.java | 7 ++----- 7 files changed, 11 insertions(+), 13 deletions(-) diff --git a/archie-utils/src/main/java/com/nedap/archie/json/ArchieRMObjectMapperProvider.java b/archie-utils/src/main/java/com/nedap/archie/json/ArchieRMObjectMapperProvider.java index 91396bd48..eee93c7f6 100644 --- a/archie-utils/src/main/java/com/nedap/archie/json/ArchieRMObjectMapperProvider.java +++ b/archie-utils/src/main/java/com/nedap/archie/json/ArchieRMObjectMapperProvider.java @@ -22,7 +22,7 @@ public class ArchieRMObjectMapperProvider implements RMObjectMapperProvider { public ObjectMapper getInputOdinObjectMapper() { ObjectMapper odinMapper = new ObjectMapper(); JacksonUtil.configureObjectMapper(odinMapper); - odinMapper.setPropertyNamingStrategy(PropertyNamingStrategy.SNAKE_CASE); + odinMapper.setPropertyNamingStrategy(PropertyNamingStrategies.SNAKE_CASE); //keywords = <"value"> is indistinguishable from keywords = <"value1", "value2"> odinMapper.enable(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY); //odin sometimes does <> where it can mean either an empty array OR a null object. Nastyness diff --git a/archie-utils/src/main/java/com/nedap/archie/json/JacksonUtil.java b/archie-utils/src/main/java/com/nedap/archie/json/JacksonUtil.java index 1506253e0..886483f6a 100644 --- a/archie-utils/src/main/java/com/nedap/archie/json/JacksonUtil.java +++ b/archie-utils/src/main/java/com/nedap/archie/json/JacksonUtil.java @@ -69,7 +69,7 @@ public static void configureObjectMapper(ObjectMapper objectMapper, ArchieJackso objectMapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS); objectMapper.disable(SerializationFeature.WRITE_DURATIONS_AS_TIMESTAMPS); objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL); - objectMapper.setPropertyNamingStrategy(PropertyNamingStrategy.SNAKE_CASE); + objectMapper.setPropertyNamingStrategy(PropertyNamingStrategies.SNAKE_CASE); objectMapper.enable(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY); objectMapper.enable(DeserializationFeature.UNWRAP_SINGLE_VALUE_ARRAYS); objectMapper.configure(MapperFeature.ACCEPT_CASE_INSENSITIVE_ENUMS, true); diff --git a/bmm/src/main/java/org/openehr/bmm/v2/persistence/jackson/BmmJacksonUtil.java b/bmm/src/main/java/org/openehr/bmm/v2/persistence/jackson/BmmJacksonUtil.java index a4b2a4ae5..0b452c42f 100644 --- a/bmm/src/main/java/org/openehr/bmm/v2/persistence/jackson/BmmJacksonUtil.java +++ b/bmm/src/main/java/org/openehr/bmm/v2/persistence/jackson/BmmJacksonUtil.java @@ -45,7 +45,7 @@ public static ObjectMapper getObjectMapper() { * @param objectMapper */ public static void configureObjectMapper(ObjectMapper objectMapper) { - objectMapper.setPropertyNamingStrategy(PropertyNamingStrategy.SNAKE_CASE); + objectMapper.setPropertyNamingStrategy(PropertyNamingStrategies.SNAKE_CASE); //keywords = <"value"> is indistinguishable from keywords = <"value1", "value2"> objectMapper.enable(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY); objectMapper.enable(JsonParser.Feature.STRICT_DUPLICATE_DETECTION); diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index f988013aa..593b7ada5 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,7 +1,8 @@ [versions] antlr = "4.13.2" -jackson = "2.19.2" +jackson = "2.20.0" +jackson_annotations = "2.20" slf4j = "1.7.36" @@ -25,7 +26,7 @@ commons-text = { module = "org.apache.commons:commons-text", version = "1.14.0" guava = { module = "com.google.guava:guava", version = "33.5.0-jre" } -jackson-annotations = { module = "com.fasterxml.jackson.core:jackson-annotations", version.ref = "jackson" } +jackson-annotations = { module = "com.fasterxml.jackson.core:jackson-annotations", version.ref = "jackson_annotations" } jackson-databind = { module = "com.fasterxml.jackson.core:jackson-databind", version.ref = "jackson" } jackson-datatype-jsr310 = { module = "com.fasterxml.jackson.datatype:jackson-datatype-jsr310", version.ref = "jackson" } diff --git a/odin/src/main/java/com/nedap/archie/serializer/odin/AdlOdinToJsonConverter.java b/odin/src/main/java/com/nedap/archie/serializer/odin/AdlOdinToJsonConverter.java index a8a67f28a..ff0ea97d7 100644 --- a/odin/src/main/java/com/nedap/archie/serializer/odin/AdlOdinToJsonConverter.java +++ b/odin/src/main/java/com/nedap/archie/serializer/odin/AdlOdinToJsonConverter.java @@ -38,7 +38,7 @@ public static ObjectMapper getObjectMapper() { } public static void configureObjectMapper(ObjectMapper objectMapper, boolean allowDuplicates) { - objectMapper.setPropertyNamingStrategy(PropertyNamingStrategy.SNAKE_CASE); + objectMapper.setPropertyNamingStrategy(PropertyNamingStrategies.SNAKE_CASE); //keywords = <"value"> is indistinguishable from keywords = <"value1", "value2"> objectMapper.enable(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY); //odin sometimes does <> where it can mean either an empty array OR a null object. Nastyness diff --git a/odin/src/main/java/com/nedap/archie/serializer/odin/OdinToJsonConverter.java b/odin/src/main/java/com/nedap/archie/serializer/odin/OdinToJsonConverter.java index 1624d1aa1..c93fd1cbe 100644 --- a/odin/src/main/java/com/nedap/archie/serializer/odin/OdinToJsonConverter.java +++ b/odin/src/main/java/com/nedap/archie/serializer/odin/OdinToJsonConverter.java @@ -4,7 +4,7 @@ import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.DeserializationFeature; import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.PropertyNamingStrategy; +import com.fasterxml.jackson.databind.PropertyNamingStrategies; import com.nedap.archie.adlparser.antlr.odinParser.*; import org.apache.commons.text.StringEscapeUtils; @@ -29,7 +29,7 @@ public class OdinToJsonConverter { private StringBuilder output = new StringBuilder(); static { - objectMapper.setPropertyNamingStrategy(PropertyNamingStrategy.SNAKE_CASE); + objectMapper.setPropertyNamingStrategy(PropertyNamingStrategies.SNAKE_CASE); //keywords = <"value"> is indistinguishable from keywords = <"value1", "value2"> objectMapper.enable(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY); objectMapper.enable(JsonParser.Feature.STRICT_DUPLICATE_DETECTION); diff --git a/odin/src/main/java/org/openehr/odin/jackson/ODINMapper.java b/odin/src/main/java/org/openehr/odin/jackson/ODINMapper.java index fc963ab4e..d051e4442 100644 --- a/odin/src/main/java/org/openehr/odin/jackson/ODINMapper.java +++ b/odin/src/main/java/org/openehr/odin/jackson/ODINMapper.java @@ -2,10 +2,7 @@ import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.core.JsonParser; -import com.fasterxml.jackson.databind.MappingJsonFactory; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.PropertyNamingStrategy; -import com.fasterxml.jackson.databind.SerializationFeature; +import com.fasterxml.jackson.databind.*; import com.fasterxml.jackson.databind.module.SimpleModule; import com.nedap.archie.base.Interval; import com.nedap.archie.base.terminology.TerminologyCode; @@ -44,7 +41,7 @@ public ODINMapper(ODINMapper base) { private void setup() { - setPropertyNamingStrategy(PropertyNamingStrategy.SNAKE_CASE); + setPropertyNamingStrategy(PropertyNamingStrategies.SNAKE_CASE); disable(SerializationFeature.WRITE_NULL_MAP_VALUES); disable(SerializationFeature.WRITE_EMPTY_JSON_ARRAYS); enable(SerializationFeature.INDENT_OUTPUT); From f0d815421e6fc8f55566ef34c5ab35c6bcfb4de2 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 1 Dec 2025 16:26:19 +0700 Subject: [PATCH 20/25] Bump jackson from 2.20.0 to 2.20.1 (#728) Bumps `jackson` from 2.20.0 to 2.20.1. Updates `com.fasterxml.jackson.core:jackson-databind` from 2.20.0 to 2.20.1 - [Commits](https://github.com/FasterXML/jackson/commits) Updates `com.fasterxml.jackson.datatype:jackson-datatype-jsr310` from 2.20.0 to 2.20.1 --- updated-dependencies: - dependency-name: com.fasterxml.jackson.core:jackson-databind dependency-version: 2.20.1 dependency-type: direct:production update-type: version-update:semver-patch - dependency-name: com.fasterxml.jackson.datatype:jackson-datatype-jsr310 dependency-version: 2.20.1 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 593b7ada5..ceced0b7a 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,7 +1,7 @@ [versions] antlr = "4.13.2" -jackson = "2.20.0" +jackson = "2.20.1" jackson_annotations = "2.20" slf4j = "1.7.36" From 0732ba9c1716a81dc07248dc2a5ed4dbbc4a6195 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 1 Dec 2025 16:26:28 +0700 Subject: [PATCH 21/25] Bump org.apache.commons:commons-lang3 from 3.19.0 to 3.20.0 (#727) Bumps org.apache.commons:commons-lang3 from 3.19.0 to 3.20.0. --- updated-dependencies: - dependency-name: org.apache.commons:commons-lang3 dependency-version: 3.20.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index ceced0b7a..04a6bf445 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -20,7 +20,7 @@ antlr4-runtime = { module = "org.antlr:antlr4-runtime", version.ref = "antlr" } commons-io = { module = "commons-io:commons-io", version = "2.20.0" } -commons-lang3 = { module = "org.apache.commons:commons-lang3", version = "3.19.0" } +commons-lang3 = { module = "org.apache.commons:commons-lang3", version = "3.20.0" } commons-text = { module = "org.apache.commons:commons-text", version = "1.14.0" } From b11af702fce0c4b4b1706398e0c65e8fd38f298d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 1 Dec 2025 16:26:36 +0700 Subject: [PATCH 22/25] Bump commons-io:commons-io from 2.20.0 to 2.21.0 (#726) Bumps [commons-io:commons-io](https://github.com/apache/commons-io) from 2.20.0 to 2.21.0. - [Changelog](https://github.com/apache/commons-io/blob/master/RELEASE-NOTES.txt) - [Commits](https://github.com/apache/commons-io/compare/rel/commons-io-2.20.0...rel/commons-io-2.21.0) --- updated-dependencies: - dependency-name: commons-io:commons-io dependency-version: 2.21.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 04a6bf445..5b4f66cbb 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -18,7 +18,7 @@ activation = { module = "javax.activation:activation", version = "1.1.1" } antlr4 = { module = "org.antlr:antlr4", version.ref = "antlr" } antlr4-runtime = { module = "org.antlr:antlr4-runtime", version.ref = "antlr" } -commons-io = { module = "commons-io:commons-io", version = "2.20.0" } +commons-io = { module = "commons-io:commons-io", version = "2.21.0" } commons-lang3 = { module = "org.apache.commons:commons-lang3", version = "3.20.0" } From cc04a765ed73b448ba1e0102dfc74bef05391afd Mon Sep 17 00:00:00 2001 From: Mattijs Kuhlmann <47526389+MattijsK@users.noreply.github.com> Date: Tue, 2 Dec 2025 15:04:32 +0700 Subject: [PATCH 23/25] Update Archie to 3.16.0 (#729) --- README.md | 6 +++--- build.gradle | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 890ebee27..4ef0362f6 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,7 @@ You can depend on parts of Archie, or the entire library at once. If you want th ```gradle dependencies { - compile 'com.nedap.healthcare.archie:archie-all:3.15.0' + compile 'com.nedap.healthcare.archie:archie-all:3.16.0' } ``` @@ -28,11 +28,11 @@ or if you use maven, in your pom.xml com.nedap.healthcare.archie archie-all - 3.15.0 + 3.16.0 ``` -If you want to depend on just the AOM and BMM, without any reference model implementation, depend on com.nedap.healthcare.archie:tools:3.15.0 and com.nedap.healthcare.archie:referencemodels:3.15.0 instead +If you want to depend on just the AOM and BMM, without any reference model implementation, depend on com.nedap.healthcare.archie:tools:3.16.0 and com.nedap.healthcare.archie:referencemodels:3.16.0 instead ## Build diff --git a/build.gradle b/build.gradle index c02ab8097..f47bcc2f9 100644 --- a/build.gradle +++ b/build.gradle @@ -8,7 +8,7 @@ repositories { allprojects { - version = '3.15.0' + version = '3.16.0' group = 'com.nedap.healthcare.archie' ext.gradleScriptDir = "${rootProject.projectDir}/gradle" //archivesBaseName = 'archie' From 9e735cb08a33d23b2e5e90d89f29bd40e589eaff Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 29 Dec 2025 11:30:17 +0100 Subject: [PATCH 24/25] Bump org.apache.commons:commons-text from 1.14.0 to 1.15.0 (#730) Bumps [org.apache.commons:commons-text](https://github.com/apache/commons-text) from 1.14.0 to 1.15.0. - [Changelog](https://github.com/apache/commons-text/blob/master/RELEASE-NOTES.txt) - [Commits](https://github.com/apache/commons-text/compare/rel/commons-text-1.14.0...rel/commons-text-1.15.0) --- updated-dependencies: - dependency-name: org.apache.commons:commons-text dependency-version: 1.15.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 5b4f66cbb..e61e1dfbb 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -22,7 +22,7 @@ commons-io = { module = "commons-io:commons-io", version = "2.21.0" } commons-lang3 = { module = "org.apache.commons:commons-lang3", version = "3.20.0" } -commons-text = { module = "org.apache.commons:commons-text", version = "1.14.0" } +commons-text = { module = "org.apache.commons:commons-text", version = "1.15.0" } guava = { module = "com.google.guava:guava", version = "33.5.0-jre" } From 60b8d3f5a8c65ae5c3ccedcb23b31f884e4a07bd Mon Sep 17 00:00:00 2001 From: Jelte Zeilstra Date: Thu, 8 Jan 2026 16:56:27 +0100 Subject: [PATCH 25/25] Create AttributeAccessor utility class (#732) * Create AttributeAccessor utility class * Deprecate RMObjectAttributes and RMObjectCreator set/add methods * Replace deprecated RMObjectAttributes and RMObjectCreator usages * Use AttributeAccessor where possible * Apply suggestions from code review Co-authored-by: Mattijs Kuhlmann <47526389+MattijsK@users.noreply.github.com> * Fix documentation --------- Co-authored-by: Mattijs Kuhlmann <47526389+MattijsK@users.noreply.github.com> --- .../com/nedap/archie/aom/CAttributeTuple.java | 19 +- .../archie/rminfo/AttributeAccessor.java | 304 +++++ .../archie/rminfo/AttributeAccessorTest.java | 1021 +++++++++++++++++ .../com/nedap/archie/rmutil/PathableUtil.java | 8 +- .../archie/query/RMObjectAttributes.java | 6 + .../com/nedap/archie/query/RMPathQuery.java | 206 ++-- .../archie/creation/RMObjectCreator.java | 18 +- .../archie/json/flat/FlatJsonGenerator.java | 12 +- .../nedap/archie/query/RMQueryContext.java | 14 +- .../rmobjectvalidator/RmTupleValidator.java | 8 +- .../rmobjectvalidator/ValidationHelper.java | 19 +- .../validations/RMTupleValidation.java | 5 +- .../rules/evaluation/AssertionsFixer.java | 46 +- .../rules/evaluation/RuleEvaluation.java | 6 +- .../archie/creation/RMObjectCreatorTest.java | 11 + .../archie/query/RMObjectAttributesTest.java | 1 + .../com/nedap/archie/testutil/TestUtil.java | 7 +- 17 files changed, 1518 insertions(+), 193 deletions(-) create mode 100644 aom/src/main/java/com/nedap/archie/rminfo/AttributeAccessor.java create mode 100644 aom/src/test/java/com/nedap/archie/rminfo/AttributeAccessorTest.java diff --git a/aom/src/main/java/com/nedap/archie/aom/CAttributeTuple.java b/aom/src/main/java/com/nedap/archie/aom/CAttributeTuple.java index 5618be9ff..3be731f89 100644 --- a/aom/src/main/java/com/nedap/archie/aom/CAttributeTuple.java +++ b/aom/src/main/java/com/nedap/archie/aom/CAttributeTuple.java @@ -1,12 +1,11 @@ package com.nedap.archie.aom; +import com.nedap.archie.rminfo.AttributeAccessor; import com.nedap.archie.rminfo.ModelInfoLookup; -import com.nedap.archie.rminfo.RMAttributeInfo; import javax.annotation.Nullable; import javax.xml.bind.annotation.XmlType; -import java.lang.reflect.InvocationTargetException; import java.util.ArrayList; import java.util.HashMap; import java.util.List; @@ -96,18 +95,14 @@ private boolean isValid(ModelInfoLookup lookup, CPrimitiveTuple tuple, HashMap members = new HashMap<>(); for(CAttribute attribute:getMembers()) { - RMAttributeInfo attributeInfo = lookup.getAttributeInfo(value.getClass(), attribute.getRmAttributeName()); - try { - if (attributeInfo != null && attributeInfo.getGetMethod() != null) { - members.put(attribute.getRmAttributeName(), attributeInfo.getGetMethod().invoke(value)); - } else { - //warn? throw exception? - } - } catch (InvocationTargetException | IllegalAccessException e) { - throw new RuntimeException(e); + String attributeName = attribute.getRmAttributeName(); + if (attributeAccessor.hasAttribute(value, attributeName)) { + members.put(attributeName, attributeAccessor.getValue(value, attributeName)); + } else { + //warn? throw exception? } } return isValid(lookup, members); diff --git a/aom/src/main/java/com/nedap/archie/rminfo/AttributeAccessor.java b/aom/src/main/java/com/nedap/archie/rminfo/AttributeAccessor.java new file mode 100644 index 000000000..f67f57439 --- /dev/null +++ b/aom/src/main/java/com/nedap/archie/rminfo/AttributeAccessor.java @@ -0,0 +1,304 @@ +package com.nedap.archie.rminfo; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.Objects; + +/** + * This class provides access to the attributes of AOM and RM objects. + *

+ * In this class, attributes of type array (e.g. {@code byte[]}) are treated as single valued attributes. + */ +public class AttributeAccessor { + private final ModelInfoLookup modelInfoLookup; + + public AttributeAccessor(ModelInfoLookup modelInfoLookup) { + this.modelInfoLookup = Objects.requireNonNull(modelInfoLookup); + } + + /** + * Add value(s) to the given attribute in the given object. + *

+ * Will add the given value or values to the attribute using the {@link RMAttributeInfo#getAddMethod() add method} + * of the attribute if available. If the attribute does not have an add method, the value will be added by adding it + * to the collection obtained via the {@link RMAttributeInfo#getGetMethod() get method} or a new collection will be + * created via the {@link RMAttributeInfo#getSetMethod() set method} if the attribute is null. + * + * @param object Object to add the values to + * @param attributeName Name of the attribute of the object + * @param value A single value or {@link Collection} of values to add + * @throws IllegalArgumentException if the attribute is not a valid attribute of the object, the attribute is not + * a multiple valued attribute or the type of the value does not match the type of + * the attribute. + * @throws RuntimeException if the underlying add, get or set method throws an exception. + */ + public void addValue(Object object, String attributeName, Object value) throws IllegalArgumentException { + RMAttributeInfo attributeInfo = getAttributeInfo(object, attributeName); + + if (!attributeInfo.isMultipleValued() || attributeInfo.getType().isArray()) { + throw new IllegalArgumentException("Attribute " + attributeName + " of object " + object.getClass().getSimpleName() + " is not a multiple valued attribute"); + } + + Collection convertedValue = handleCollection(object, attributeInfo, Objects.requireNonNull(value, "value must not be null")); + + Method addMethod = attributeInfo.getAddMethod(); + if (addMethod != null) { + try { + for (Object v : convertedValue) { + addMethod.invoke(object, v); + } + } catch (IllegalAccessException | InvocationTargetException e) { + throw new RuntimeException( + "Error adding value to attribute " + attributeName + " of object " + object.getClass().getSimpleName(), + e + ); + } + } else { + @SuppressWarnings("unchecked") Collection attributeCollection = (Collection) getValue(object, attributeName); + if (attributeCollection == null) { + attributeCollection = newCollectionInstance(attributeInfo); + setValue(object, attributeName, attributeCollection); + } + attributeCollection.addAll(convertedValue); + } + } + + /** + * Add or set attribute value(s) in the given object. + *

+ * For single valued attributes, the value will be set, overwriting any existing value. This is equivalent to + * calling {@link #setValue(Object, String, Object)}. + *

+ * For multiple valued attributes, the value will be added to the existing values. This is equivalent to calling + * {@link #addValue(Object, String, Object)}. + * + * @param object Object to add the values to or set the attribute value of + * @param attributeName Name of the attribute of the object + * @param value Value(s) to add or set, or null to remove the value + * @throws IllegalArgumentException if the attribute is not a valid attribute of the object, the attribute is a + * read-only attribute, the type of the value does not match the type of the + * attribute or multiple values are assigned to a single valued attribute. + * @throws RuntimeException if the underlying add, get or set method throws an exception. + */ + public void addOrSetValue(Object object, String attributeName, Object value) throws IllegalArgumentException { + RMAttributeInfo attributeInfo = getAttributeInfo(object, attributeName); + + if (attributeInfo.isMultipleValued() && !attributeInfo.getType().isArray()) { + addValue(object, attributeName, value); + } else { + setValue(object, attributeName, value); + } + } + + /** + * Get attribute value in the given object. + *

+ * Will get the given value of the attribute using the {@link RMAttributeInfo#getGetMethod() get method} + * of the attribute. + * + * @param object Object to get the attribute value of + * @param attributeName Name of the attribute of the object + * @throws IllegalArgumentException if the attribute is not a valid attribute of the object. + * @throws RuntimeException if the underlying get method throws an exception. + */ + public Object getValue(Object object, String attributeName) throws IllegalArgumentException { + RMAttributeInfo attributeInfo = getAttributeInfo(object, attributeName); + + try { + return attributeInfo.getGetMethod().invoke(object); + } catch (IllegalAccessException | InvocationTargetException e) { + throw new RuntimeException( + "Error getting value of attribute " + attributeName + " of object " + object.getClass().getSimpleName(), + e + ); + } + } + + /** + * Check that given object has an attribute of the given name. + * + * @param object Object to check the attribute of + * @param attributeName Name of the attribute of the object + * @return True if the given object has an attribute of the given name + */ + public boolean hasAttribute(Object object, String attributeName) { + return modelInfoLookup.getAttributeInfo( + Objects.requireNonNull(object, "object must not be null").getClass(), + Objects.requireNonNull(attributeName, "attributeName must not be null") + ) != null; + } + + /** + * Set attribute value(s) in the given object. + *

+ * Will set the given value or values to the attribute using the {@link RMAttributeInfo#getSetMethod() set method} + * of the attribute, overwriting any existing value. + *

+ * For single valued attributes, this method unwraps single values from a given {@link Collection}. + *

+ * For multiple valued attributes, this method wraps a single value in a new instance of the collection type. + * + * @param object Object to set the attribute value of + * @param attributeName Name of the attribute of the object + * @param value Value(s) to set, or null to remove the value + * @throws IllegalArgumentException if the attribute is not a valid attribute of the object, the attribute is a + * read-only attribute, the type of the value does not match the type of the + * attribute or multiple values are assigned to a single valued attribute. + * @throws RuntimeException if the underlying set method throws an exception. + */ + public void setValue(Object object, String attributeName, Object value) throws IllegalArgumentException { + RMAttributeInfo attributeInfo = getAttributeInfo(object, attributeName); + + Method setMethod = attributeInfo.getSetMethod(); + if (setMethod == null) { + throw new IllegalArgumentException( + "Attribute " + attributeName + " of object " + object.getClass().getSimpleName() + " is a read-only attribute" + ); + } + + Object convertedValue; + if (attributeInfo.isMultipleValued() && !attributeInfo.getType().isArray()) { + convertedValue = handleCollection(object, attributeInfo, value); + } else { + // Handle arrays (byte[]) as a single value + convertedValue = handleSingleValue(object, attributeInfo, value); + } + + try { + setMethod.invoke(object, convertedValue); + } catch (IllegalAccessException | InvocationTargetException e) { + throw new RuntimeException( + "Error setting value on attribute " + attributeName + " of object " + object.getClass().getSimpleName(), + e + ); + } + } + + /** + * Get attribute info for the given object and attribute name. + * + * @param object Object to get the attribute info of + * @param attributeName Name of the attribute of the object + * @return Attribute info object + * @throws NullPointerException if the object or attribute name is null. + * @throws IllegalArgumentException if the attribute is not a valid attribute of the object. + */ + private RMAttributeInfo getAttributeInfo(Object object, String attributeName) { + RMAttributeInfo attributeInfo = modelInfoLookup.getAttributeInfo( + Objects.requireNonNull(object, "object must not be null").getClass(), + Objects.requireNonNull(attributeName, "attributeName must not be null") + ); + if (attributeInfo == null) { + throw new IllegalArgumentException( + "Attribute " + attributeName + " of object " + object.getClass().getSimpleName() + " is not a valid attribute" + ); + } + return attributeInfo; + } + + /** + * Validate and convert the given value for assignment to a multiple valued (collection) attribute. + *

+ * Non-collection values will be wrapped in a collection. + * + * @param object Object to set the attribute value of (for exception message) + * @param attributeInfo Attribute info object + * @param value value to validate and convert + * @return converted value or null if the given value is null + * @throws IllegalArgumentException if the given value is not assignable to the attribute type or multiple values + * are assigned to a single valued attribute + */ + private Collection handleCollection(Object object, RMAttributeInfo attributeInfo, Object value) + throws IllegalArgumentException { + String attributeName = attributeInfo.getRmName(); + Class typeInCollection = attributeInfo.getTypeInCollection(); + Collection collection; + + if (value == null) { + collection = null; + } else if (value instanceof Collection) { + collection = (Collection) value; + validateType(object, attributeName, collection, attributeInfo.getType()); + + for (Object element : collection) { + validateType(object, attributeName, element, typeInCollection); + } + } else { + validateType(object, attributeName, value, typeInCollection); + List newCollection = newCollectionInstance(attributeInfo); + newCollection.add(value); + collection = newCollection; + } + + return collection; + } + + /** + * Validate and convert the given value for assignment to a single valued attribute. + *

+ * Single valued attributes include byte arrays. + *

+ * This will unpack a collection with zero or one elements. + * + * @param object Object to set the attribute value of (for exception message) + * @param attributeInfo Attribute info object + * @param value value to validate and convert + * @return converted value or null if the given value is null or an empty collection + * @throws IllegalArgumentException if the given value is not assignable to the attribute type or the value is a + * collection with multiple elements. + */ + private Object handleSingleValue(Object object, RMAttributeInfo attributeInfo, Object value) + throws IllegalArgumentException { + if (value instanceof Collection) { + Collection collection = (Collection) value; + if (collection.size() > 1) { + throw new IllegalArgumentException( + "Attribute " + attributeInfo.getRmName() + " of object " + object.getClass().getSimpleName() + " does not support multiple values" + ); + } + value = collection.isEmpty() ? null : collection.iterator().next(); + } + + validateType(object, attributeInfo.getRmName(), value, attributeInfo.getType()); + return value; + } + + /** + * Validate that the given value is assignable to the given type. + * + * @param object Object to set the attribute value of (for exception message) + * @param attributeName Name of the attribute of the object (for exception message) + * @param value Value to check the type of + * @param type The required type for the value + * @throws IllegalArgumentException if the given value is not assignable to the given type. + */ + private void validateType(Object object, String attributeName, Object value, Class type) + throws IllegalArgumentException { + if (value != null && !type.isAssignableFrom(value.getClass())) { + throw new IllegalArgumentException( + "Value type " + value.getClass().getTypeName() + " is not a valid type for attribute " + attributeName + " of object " + object.getClass().getSimpleName() + ); + } + } + + /** + * Create new collection instance for the given attribute. + *

+ * Assumes the collection type is List. + * + * @param attributeInfo Attribute info object + * @return Empty list + * @throws IllegalArgumentException if the attribute type is not List. + */ + private List newCollectionInstance(RMAttributeInfo attributeInfo) throws IllegalArgumentException { + Class type = attributeInfo.getType(); + if (type.equals(List.class)) { + return new ArrayList<>(); + } else { + throw new IllegalArgumentException("Unknown collection type " + type.getTypeName()); + } + } +} diff --git a/aom/src/test/java/com/nedap/archie/rminfo/AttributeAccessorTest.java b/aom/src/test/java/com/nedap/archie/rminfo/AttributeAccessorTest.java new file mode 100644 index 000000000..21c773487 --- /dev/null +++ b/aom/src/test/java/com/nedap/archie/rminfo/AttributeAccessorTest.java @@ -0,0 +1,1021 @@ +package com.nedap.archie.rminfo; + +import com.google.common.collect.Lists; +import com.google.common.collect.Sets; +import com.nedap.archie.aom.Archetype; +import com.nedap.archie.aom.CObject; +import com.nedap.archie.aom.CPrimitiveObject; +import org.junit.Test; + +import java.util.*; + +import static org.junit.Assert.*; + +public class AttributeAccessorTest { + private static final ModelInfoLookup modelInfoLookup = new LocalClassInfoLookup(); + private static final AttributeAccessor attributeAccessor = new AttributeAccessor(modelInfoLookup); + + private static class Dummy { + } + + @SuppressWarnings("unused") + private static class Thing { + private String name; + + private byte[] data; + + public Thing() { + } + + public Thing(String name) { + this.name = name; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public byte[] getData() { + return data; + } + + public void setData(byte[] data) { + this.data = data; + } + + public int getFour() { + // Read-only attribute + return 4; + } + } + + @SuppressWarnings("unused") + private static class Group { + private List subgroups = new ArrayList<>(); + + private List things = new ArrayList<>(); + + private Thing mainThing; + + public List getSubgroups() { + return subgroups; + } + + public void setSubgroups(List subgroups) { + this.subgroups = subgroups; + } + + public List getThings() { + return things; + } + + public void setThings(List things) { + this.things = things; + } + + public void addThing(Thing thing) { + if (things == null) { + things = new ArrayList<>(); + } + this.things.add(thing); + } + + public Thing getMainThing() { + return mainThing; + } + + public void setMainThing(Thing mainThing) { + this.mainThing = mainThing; + } + } + + @SuppressWarnings({"unused", "FieldMayBeFinal"}) + private static class BrokenClass { + // This single valued attribute throws an exception when accessed + private BrokenClass child; + + // This multiple valued attribute throws an exception when accessed + private List items = new ArrayList<>(); + + private Set someSet = new HashSet<>(); + + public BrokenClass getChild() { + throw new RuntimeException("Some exception"); + } + + public void setChild(BrokenClass child) { + throw new RuntimeException("Some exception"); + } + + public List getItems() { + throw new RuntimeException("Some exception"); + } + + public void setItems(List values) { + throw new RuntimeException("Some exception"); + } + + public void addItem(BrokenClass value) { + throw new RuntimeException("Some exception"); + } + + public Set getSomeSet() { + return someSet; + } + + public void setSomeSet(Set values) { + this.someSet = values; + } + + public void addSomeSet(BrokenClass value) { + this.someSet.add(value); + } + } + + public static class LocalClassInfoLookup extends ReflectionModelInfoLookup { + private LocalClassInfoLookup() { + super(new ArchieModelNamingStrategy(), Object.class); + } + + @Override + protected void addTypes(Class baseClass) { + addClass(Thing.class); + addClass(Group.class); + addClass(BrokenClass.class); + } + + @Override + public void processCreatedObject(Object createdObject, CObject constraint) { + // Do nothing + } + + @Override + public String getArchetypeNodeIdFromRMObject(Object rmObject) { + return null; + } + + @Override + public String getArchetypeIdFromArchetypedRmObject(Object rmObject) { + return null; + } + + @Override + public String getNameFromRMObject(Object rmObject) { + return null; + } + + @Override + public Object clone(Object rmObject) { + throw new UnsupportedOperationException(); + } + + @Override + public Map pathHasBeenUpdated(Object rmObject, Archetype archetype, String pathOfParent, Object parent) { + return new HashMap<>(); + } + + @Override + public boolean validatePrimitiveType(String rmTypeName, String rmAttributeName, CPrimitiveObject cObject) { + return false; + } + + @Override + public Collection getId() { + return Lists.newArrayList(new RMPackageId("openEHR", "BROKEN")); + } + } + + public static class AddValue { + + @Test + public void testMultipleValuedSingle() { + Group group = new Group(); + Thing thing1 = new Thing(); + Thing thing2 = new Thing(); + group.setThings(Lists.newArrayList(thing1, thing2)); + + Thing thing3 = new Thing(); + + attributeAccessor.addValue(group, "things", thing3); + + assertEquals(3, group.getThings().size()); + assertSame(thing1, group.getThings().get(0)); + assertSame(thing2, group.getThings().get(1)); + assertSame(thing3, group.getThings().get(2)); + } + + @Test + public void testMultipleValuedNull() { + Group group = new Group(); + group.setThings(Lists.newArrayList(new Thing(), new Thing())); + + NullPointerException exception = assertThrows(NullPointerException.class, () -> attributeAccessor.addValue(group, "things", null)); + assertEquals("value must not be null", exception.getMessage()); + + assertEquals(2, group.getThings().size()); + } + + @Test + public void testMultipleValuedListIntialEmpty() { + Group group = new Group(); + + Thing thing1 = new Thing(); + Thing thing2 = new Thing(); + List newThings = Lists.newArrayList(thing1, thing2); + + attributeAccessor.addValue(group, "things", newThings); + + assertNotSame("A new collection should be created", newThings, group.getThings()); + assertEquals(2, group.getThings().size()); + assertSame(thing1, group.getThings().get(0)); + assertSame(thing2, group.getThings().get(1)); + } + + @Test + public void testMultipleValuedListIntialNull() { + Group group = new Group(); + group.setThings(null); + + Thing thing1 = new Thing(); + Thing thing2 = new Thing(); + List newThings = Lists.newArrayList(thing1, thing2); + + attributeAccessor.addValue(group, "things", newThings); + + assertNotSame("A new collection should be created", newThings, group.getThings()); + assertEquals(2, group.getThings().size()); + assertSame(thing1, group.getThings().get(0)); + assertSame(thing2, group.getThings().get(1)); + } + + @Test + public void testMultipleValuedListIntialFilled() { + Group group = new Group(); + Thing thing1 = new Thing(); + Thing thing2 = new Thing(); + group.setThings(Lists.newArrayList(thing1, thing2)); + + Thing thing3 = new Thing(); + Thing thing4 = new Thing(); + List newThings = Lists.newArrayList(thing3, thing4); + + attributeAccessor.addValue(group, "things", newThings); + + assertEquals(4, group.getThings().size()); + assertSame(thing1, group.getThings().get(0)); + assertSame(thing2, group.getThings().get(1)); + assertSame(thing3, group.getThings().get(2)); + assertSame(thing4, group.getThings().get(3)); + } + + @Test + public void testMultipleValuedListEmpty() { + Group group = new Group(); + Thing thing1 = new Thing(); + Thing thing2 = new Thing(); + group.setThings(Lists.newArrayList(thing1, thing2)); + + attributeAccessor.addValue(group, "things", Collections.emptyList()); + + assertEquals(2, group.getThings().size()); + assertSame(thing1, group.getThings().get(0)); + assertSame(thing2, group.getThings().get(1)); + } + + @Test + public void testMultipleValuedListNull() { + Group group = new Group(); + Thing thing1 = new Thing(); + Thing thing2 = new Thing(); + group.setThings(Lists.newArrayList(thing1, thing2)); + + attributeAccessor.addValue(group, "things", Collections.singletonList(null)); + + assertEquals(3, group.getThings().size()); + assertSame(thing1, group.getThings().get(0)); + assertSame(thing2, group.getThings().get(1)); + assertNull(group.getThings().get(2)); + } + + @Test + public void testMultipleValuedFallback() { + // Group has no addSubgroup method + Group group = new Group(); + group.setSubgroups(null); + + Group subgroup1 = new Group(); + Group subgroup2 = new Group(); + List newSubgroups = Lists.newArrayList(subgroup1, subgroup2); + + attributeAccessor.addValue(group, "subgroups", newSubgroups); + + assertNotSame("A new collection should be created", newSubgroups, group.getSubgroups()); + assertEquals(2, group.getSubgroups().size()); + assertSame(subgroup1, group.getSubgroups().get(0)); + assertSame(subgroup2, group.getSubgroups().get(1)); + } + + @Test + public void testMultipleValuedWrongCollection() { + Group group = new Group(); + Set things = new HashSet<>(); + things.add(new Thing()); + things.add(new Thing()); + + IllegalArgumentException throwable = assertThrows(IllegalArgumentException.class, () -> attributeAccessor.addValue(group, "things", things)); + assertEquals("Value type java.util.HashSet is not a valid type for attribute things of object Group", throwable.getMessage()); + } + + @Test + public void testMultipleValuedWrongType() { + Group group = new Group(); + List newThings = Lists.newArrayList(new Thing(), new Dummy()); + + IllegalArgumentException throwable = assertThrows(IllegalArgumentException.class, () -> attributeAccessor.addValue(group, "things", newThings)); + assertEquals("Value type com.nedap.archie.rminfo.AttributeAccessorTest$Dummy is not a valid type for attribute things of object Group", throwable.getMessage()); + } + + @Test + public void testMultipleValuedException() { + AttributeAccessor attributeAccessor = new AttributeAccessor(new LocalClassInfoLookup()); + BrokenClass brokenClass = new BrokenClass(); + + RuntimeException throwable = assertThrows(RuntimeException.class, () -> attributeAccessor.addValue(brokenClass, "items", new BrokenClass())); + assertEquals("Error adding value to attribute items of object BrokenClass", throwable.getMessage()); + } + + @Test + public void testMultipleValuedSetType() { + AttributeAccessor attributeAccessor = new AttributeAccessor(new LocalClassInfoLookup()); + BrokenClass brokenClass = new BrokenClass(); + + IllegalArgumentException throwable = assertThrows(IllegalArgumentException.class, () -> attributeAccessor.addValue(brokenClass, "some_set", new BrokenClass())); + assertEquals("Unknown collection type java.util.Set", throwable.getMessage()); + } + + @Test + public void testSingleValued() { + Thing thing = new Thing("old value"); + + IllegalArgumentException throwable = assertThrows(IllegalArgumentException.class, () -> attributeAccessor.addValue(thing, "name", "new value")); + assertEquals("Attribute name of object Thing is not a multiple valued attribute", throwable.getMessage()); + + assertEquals("old value", thing.getName()); + } + + @Test + public void testByteArray() { + Thing thing = new Thing(); + byte[] bytes = new byte[]{33, 42}; + + IllegalArgumentException throwable = assertThrows(IllegalArgumentException.class, () -> attributeAccessor.addValue(thing, "data", bytes)); + assertEquals("Attribute data of object Thing is not a multiple valued attribute", throwable.getMessage()); + + assertNull(thing.getData()); + } + + @Test + public void testUnknownAttribute() { + Thing thing = new Thing(); + + IllegalArgumentException throwable = assertThrows(IllegalArgumentException.class, () -> attributeAccessor.addValue(thing, "unknown", "test string")); + assertEquals("Attribute unknown of object Thing is not a valid attribute", throwable.getMessage()); + } + + @Test + public void testNonRmObject() { + Dummy dummy = new Dummy(); + + IllegalArgumentException throwable = assertThrows(IllegalArgumentException.class, () -> attributeAccessor.addValue(dummy, "value", 12345)); + assertEquals("Attribute value of object Dummy is not a valid attribute", throwable.getMessage()); + } + } + + public static class AddOrSetValue { + + @Test + public void testMultipleValuedSingle() { + Group group = new Group(); + Thing thing1 = new Thing(); + Thing thing2 = new Thing(); + group.setThings(Lists.newArrayList(thing1, thing2)); + + Thing thing3 = new Thing(); + + attributeAccessor.addOrSetValue(group, "things", thing3); + + assertEquals(3, group.getThings().size()); + assertSame(thing1, group.getThings().get(0)); + assertSame(thing2, group.getThings().get(1)); + assertSame(thing3, group.getThings().get(2)); + } + + @Test + public void testMultipleValuedNull() { + Group group = new Group(); + group.setThings(Lists.newArrayList(new Thing(), new Thing())); + + NullPointerException exception = assertThrows(NullPointerException.class, () -> attributeAccessor.addOrSetValue(group, "things", null)); + assertEquals("value must not be null", exception.getMessage()); + + assertEquals(2, group.getThings().size()); + } + + @Test + public void testMultipleValuedListIntialEmpty() { + Group group = new Group(); + + Thing thing1 = new Thing(); + Thing thing2 = new Thing(); + List newThings = Lists.newArrayList(thing1, thing2); + + attributeAccessor.addOrSetValue(group, "things", newThings); + + assertNotSame("A new collection should be created", newThings, group.getThings()); + assertEquals(2, group.getThings().size()); + assertSame(thing1, group.getThings().get(0)); + assertSame(thing2, group.getThings().get(1)); + } + + @Test + public void testMultipleValuedListIntialNull() { + // Group has no addRow method + Group group = new Group(); + group.setThings(null); + + Thing thing1 = new Thing(); + Thing thing2 = new Thing(); + List newThings = Lists.newArrayList(thing1, thing2); + + attributeAccessor.addOrSetValue(group, "things", newThings); + + assertNotSame("A new collection should be created", newThings, group.getThings()); + assertEquals(2, group.getThings().size()); + assertSame(thing1, group.getThings().get(0)); + assertSame(thing2, group.getThings().get(1)); + } + + @Test + public void testMultipleValuedListIntialFilled() { + Group group = new Group(); + Thing thing1 = new Thing(); + Thing thing2 = new Thing(); + group.setThings(Lists.newArrayList(thing1, thing2)); + + Thing thing3 = new Thing(); + Thing thing4 = new Thing(); + List newThings = Lists.newArrayList(thing3, thing4); + + attributeAccessor.addOrSetValue(group, "things", newThings); + + assertEquals(4, group.getThings().size()); + assertSame(thing1, group.getThings().get(0)); + assertSame(thing2, group.getThings().get(1)); + assertSame(thing3, group.getThings().get(2)); + assertSame(thing4, group.getThings().get(3)); + } + + @Test + public void testMultipleValuedListEmpty() { + Group group = new Group(); + group.setThings(Lists.newArrayList(new Thing(), new Thing())); + + attributeAccessor.addOrSetValue(group, "things", Collections.emptyList()); + + assertEquals(2, group.getThings().size()); + } + + @Test + public void testMultipleValuedListNull() { + Group group = new Group(); + Thing thing1 = new Thing(); + Thing thing2 = new Thing(); + group.setThings(Lists.newArrayList(thing1, thing2)); + + attributeAccessor.addOrSetValue(group, "things", Collections.singletonList(null)); + + assertEquals(3, group.getThings().size()); + assertSame(thing1, group.getThings().get(0)); + assertSame(thing2, group.getThings().get(1)); + assertNull(group.getThings().get(2)); + } + + @Test + public void testMultipleValuedFallback() { + // Group has no addRow method + Group group = new Group(); + + Group subgroup1 = new Group(); + Group subgroup2 = new Group(); + List newSubgroups = Lists.newArrayList(subgroup1, subgroup2); + + attributeAccessor.addOrSetValue(group, "subgroups", newSubgroups); + + assertNotSame("A new collection should be created", newSubgroups, group.getSubgroups()); + assertEquals(2, group.getSubgroups().size()); + assertSame(subgroup1, group.getSubgroups().get(0)); + assertSame(subgroup2, group.getSubgroups().get(1)); + } + + @Test + public void testMultipleValuedWrongCollection() { + Group group = new Group(); + Set things = new HashSet<>(); + things.add(new Thing()); + things.add(new Thing()); + + IllegalArgumentException throwable = assertThrows(IllegalArgumentException.class, () -> attributeAccessor.addOrSetValue(group, "things", things)); + assertEquals("Value type java.util.HashSet is not a valid type for attribute things of object Group", throwable.getMessage()); + } + + @Test + public void testMultipleValuedWrongType() { + Group group = new Group(); + List newThings = Lists.newArrayList(new Thing(), new Dummy()); + + IllegalArgumentException throwable = assertThrows(IllegalArgumentException.class, () -> attributeAccessor.addOrSetValue(group, "things", newThings)); + assertEquals("Value type com.nedap.archie.rminfo.AttributeAccessorTest$Dummy is not a valid type for attribute things of object Group", throwable.getMessage()); + } + + @Test + public void testMultipleValuedException() { + AttributeAccessor attributeAccessor = new AttributeAccessor(new LocalClassInfoLookup()); + BrokenClass brokenClass = new BrokenClass(); + + RuntimeException throwable = assertThrows(RuntimeException.class, () -> attributeAccessor.addOrSetValue(brokenClass, "items", new BrokenClass())); + assertEquals("Error adding value to attribute items of object BrokenClass", throwable.getMessage()); + } + + @Test + public void testMultipleValuedSetType() { + AttributeAccessor attributeAccessor = new AttributeAccessor(new LocalClassInfoLookup()); + BrokenClass brokenClass = new BrokenClass(); + + IllegalArgumentException throwable = assertThrows(IllegalArgumentException.class, () -> attributeAccessor.addOrSetValue(brokenClass, "some_set", new BrokenClass())); + assertEquals("Unknown collection type java.util.Set", throwable.getMessage()); + } + + @Test + public void testSingleValued() { + Thing thing = new Thing("old value"); + attributeAccessor.addOrSetValue(thing, "name", "new value"); + assertEquals("new value", thing.getName()); + } + + @Test + public void testSingleValuedNull() { + Thing thing = new Thing("old value"); + attributeAccessor.addOrSetValue(thing, "name", null); + assertNull(thing.getName()); + } + + @Test + public void testSingleValuedList() { + Thing thing = new Thing("old value"); + List newValue = Lists.newArrayList("new value"); + attributeAccessor.addOrSetValue(thing, "name", newValue); + assertEquals("new value", thing.getName()); + } + + @Test + public void testSingleValuedListEmpty() { + Thing thing = new Thing("old value"); + List newValue = Lists.newArrayList(); + attributeAccessor.addOrSetValue(thing, "name", newValue); + assertNull(thing.getName()); + } + + @Test + public void testSingleValuedListNull() { + Thing thing = new Thing("old value"); + List newValue = Lists.newArrayList(); + newValue.add(null); + attributeAccessor.addOrSetValue(thing, "name", newValue); + assertNull(thing.getName()); + } + + @Test + public void testSingleValuedListMultiple() { + Thing thing = new Thing("old value"); + List newValue = Lists.newArrayList(); + newValue.add("first string"); + newValue.add("second string"); + + IllegalArgumentException throwable = assertThrows(IllegalArgumentException.class, () -> attributeAccessor.addOrSetValue(thing, "name", newValue)); + assertEquals("Attribute name of object Thing does not support multiple values", throwable.getMessage()); + + assertEquals("old value", thing.getName()); + } + + @Test + public void testSingleValuedSet() { + Thing thing = new Thing("old value"); + Set newValue = Sets.newHashSet("new value"); + attributeAccessor.addOrSetValue(thing, "name", newValue); + assertEquals("new value", thing.getName()); + } + + @Test + public void testSingleValuedReadOnlyAttribute() { + Thing thing = new Thing(); + + IllegalArgumentException throwable = assertThrows(IllegalArgumentException.class, () -> attributeAccessor.addOrSetValue(thing, "four", 5)); + assertEquals("Attribute four of object Thing is a read-only attribute", throwable.getMessage()); + } + + @Test + public void testSingleValuedWrongType() { + Thing thing = new Thing("old value"); + + IllegalArgumentException throwable = assertThrows(IllegalArgumentException.class, () -> attributeAccessor.addOrSetValue(thing, "name", 12345)); + assertEquals("Value type java.lang.Integer is not a valid type for attribute name of object Thing", throwable.getMessage()); + + assertEquals("old value", thing.getName()); + } + + @Test + public void testSingleValuedObject() { + Group group = new Group(); + Thing thing = new Thing(); + attributeAccessor.addOrSetValue(group, "main_thing", thing); + assertSame(thing, group.getMainThing()); + } + + @Test + public void testSingleValuedException() { + AttributeAccessor attributeAccessor = new AttributeAccessor(new LocalClassInfoLookup()); + BrokenClass brokenClass = new BrokenClass(); + + RuntimeException throwable = assertThrows(RuntimeException.class, () -> attributeAccessor.addOrSetValue(brokenClass, "child", new BrokenClass())); + assertEquals("Error setting value on attribute child of object BrokenClass", throwable.getMessage()); + } + + @Test + public void testByteArray() { + Thing thing = new Thing(); + byte[] bytes = new byte[]{33, 42}; + attributeAccessor.addOrSetValue(thing, "data", bytes); + assertSame(bytes, thing.getData()); + } + + @Test + public void testByteArrayByte() { + Thing thing = new Thing(); + byte singleByte = 42; + + IllegalArgumentException throwable = assertThrows(IllegalArgumentException.class, () -> attributeAccessor.addOrSetValue(thing, "data", singleByte)); + assertEquals("Value type java.lang.Byte is not a valid type for attribute data of object Thing", throwable.getMessage()); + } + + @Test + public void testByteArrayIntArray() { + Thing thing = new Thing(); + int[] ints = new int[]{33, 42}; + + IllegalArgumentException throwable = assertThrows(IllegalArgumentException.class, () -> attributeAccessor.addOrSetValue(thing, "data", ints)); + assertEquals("Value type int[] is not a valid type for attribute data of object Thing", throwable.getMessage()); + } + + @Test + public void testUnknownAttribute() { + Thing thing = new Thing(); + + IllegalArgumentException throwable = assertThrows(IllegalArgumentException.class, () -> attributeAccessor.addOrSetValue(thing, "unknown", "test string")); + assertEquals("Attribute unknown of object Thing is not a valid attribute", throwable.getMessage()); + } + + @Test + public void testNonRmObject() { + Dummy dummy = new Dummy(); + + IllegalArgumentException throwable = assertThrows(IllegalArgumentException.class, () -> attributeAccessor.addOrSetValue(dummy, "value", 12345)); + assertEquals("Attribute value of object Dummy is not a valid attribute", throwable.getMessage()); + } + } + + public static class GetValue { + @Test + public void testNormal() { + Thing thing = new Thing("test string"); + assertEquals("test string", attributeAccessor.getValue(thing, "name")); + } + + @Test + public void testNull() { + Thing thing = new Thing(); + assertNull(attributeAccessor.getValue(thing, "name")); + } + + @Test + public void testUnknownAttribute() { + Thing thing = new Thing(); + + IllegalArgumentException throwable = assertThrows(IllegalArgumentException.class, () -> attributeAccessor.getValue(thing, "unknown")); + assertEquals("Attribute unknown of object Thing is not a valid attribute", throwable.getMessage()); + } + + @Test + public void testNonRmObject() { + Dummy dummy = new Dummy(); + + IllegalArgumentException throwable = assertThrows(IllegalArgumentException.class, () -> attributeAccessor.getValue(dummy, "value")); + assertEquals("Attribute value of object Dummy is not a valid attribute", throwable.getMessage()); + } + + @Test + public void testException() { + AttributeAccessor attributeAccessor = new AttributeAccessor(new LocalClassInfoLookup()); + BrokenClass brokenClass = new BrokenClass(); + + RuntimeException throwable = assertThrows(RuntimeException.class, () -> attributeAccessor.getValue(brokenClass, "items")); + assertEquals("Error getting value of attribute items of object BrokenClass", throwable.getMessage()); + } + } + + public static class HasAttribute { + @Test + public void testHasAttribute() { + assertTrue(attributeAccessor.hasAttribute(new Thing(), "name")); + assertFalse(attributeAccessor.hasAttribute(new Thing(), "unknown")); + assertFalse(attributeAccessor.hasAttribute(new Dummy(), "value")); + } + } + + public static class SetValue { + @Test + public void testMultipleValuedSingle() { + Group group = new Group(); + Thing thing1 = new Thing(); + Thing thing2 = new Thing(); + group.setThings(Lists.newArrayList(thing1, thing2)); + + Thing thing3 = new Thing(); + + attributeAccessor.setValue(group, "things", thing3); + + assertEquals(1, group.getThings().size()); + assertSame(thing3, group.getThings().get(0)); + } + + @Test + public void testMultipleValuedNull() { + Group group = new Group(); + group.setThings(Lists.newArrayList(new Thing(), new Thing())); + + attributeAccessor.setValue(group, "things", null); + + assertNull(group.getThings()); + } + + @Test + public void testMultipleValuedListIntialEmpty() { + Group group = new Group(); + + Thing thing1 = new Thing(); + Thing thing2 = new Thing(); + List newThings = Lists.newArrayList(thing1, thing2); + + attributeAccessor.setValue(group, "things", newThings); + + assertEquals(2, group.getThings().size()); + assertSame(thing1, group.getThings().get(0)); + assertSame(thing2, group.getThings().get(1)); + } + + @Test + public void testMultipleValuedListIntialNull() { + Group group = new Group(); + group.setThings(null); + + Thing thing1 = new Thing(); + Thing thing2 = new Thing(); + List newThings = Lists.newArrayList(thing1, thing2); + + attributeAccessor.setValue(group, "things", newThings); + + assertEquals(2, group.getThings().size()); + assertSame(thing1, group.getThings().get(0)); + assertSame(thing2, group.getThings().get(1)); + } + + @Test + public void testMultipleValuedListIntialFilled() { + Group group = new Group(); + Thing thing1 = new Thing(); + Thing thing2 = new Thing(); + group.setThings(Lists.newArrayList(thing1, thing2)); + + Thing thing3 = new Thing(); + Thing thing4 = new Thing(); + List newThings = Lists.newArrayList(thing3, thing4); + + attributeAccessor.setValue(group, "things", newThings); + + assertEquals(2, group.getThings().size()); + assertSame(thing3, group.getThings().get(0)); + assertSame(thing4, group.getThings().get(1)); + } + + @Test + public void testMultipleValuedListEmpty() { + Group group = new Group(); + group.setThings(Lists.newArrayList(new Thing(), new Thing())); + + attributeAccessor.setValue(group, "things", Collections.emptyList()); + + assertEquals(0, group.getThings().size()); + } + + @Test + public void testMultipleValuedListNull() { + Group group = new Group(); + Thing thing1 = new Thing(); + Thing thing2 = new Thing(); + group.setThings(Lists.newArrayList(thing1, thing2)); + + attributeAccessor.setValue(group, "things", Collections.singletonList(null)); + + assertEquals(1, group.getThings().size()); + assertNull(group.getThings().get(0)); + } + + @Test + public void testMultipleValuedWrongCollection() { + Group group = new Group(); + Set things = new HashSet<>(); + things.add(new Thing()); + things.add(new Thing()); + + IllegalArgumentException throwable = assertThrows(IllegalArgumentException.class, () -> attributeAccessor.setValue(group, "things", things)); + assertEquals("Value type java.util.HashSet is not a valid type for attribute things of object Group", throwable.getMessage()); + } + + @Test + public void testMultipleValuedWrongType() { + Group group = new Group(); + List newThings = Lists.newArrayList(new Thing(), new Dummy()); + + IllegalArgumentException throwable = assertThrows(IllegalArgumentException.class, () -> attributeAccessor.setValue(group, "things", newThings)); + assertEquals("Value type com.nedap.archie.rminfo.AttributeAccessorTest$Dummy is not a valid type for attribute things of object Group", throwable.getMessage()); + } + + @Test + public void testMultipleValuedException() { + AttributeAccessor attributeAccessor = new AttributeAccessor(new LocalClassInfoLookup()); + BrokenClass brokenClass = new BrokenClass(); + + RuntimeException throwable = assertThrows(RuntimeException.class, () -> attributeAccessor.setValue(brokenClass, "items", new BrokenClass())); + assertEquals("Error setting value on attribute items of object BrokenClass", throwable.getMessage()); + } + + @Test + public void testMultipleValuedSetType() { + AttributeAccessor attributeAccessor = new AttributeAccessor(new LocalClassInfoLookup()); + BrokenClass brokenClass = new BrokenClass(); + + IllegalArgumentException throwable = assertThrows(IllegalArgumentException.class, () -> attributeAccessor.setValue(brokenClass, "some_set", new BrokenClass())); + assertEquals("Unknown collection type java.util.Set", throwable.getMessage()); + } + + @Test + public void testSingleValued() { + Thing thing = new Thing("old value"); + attributeAccessor.setValue(thing, "name", "new value"); + assertEquals("new value", thing.getName()); + } + + @Test + public void testSingleValuedNull() { + Thing thing = new Thing("old value"); + attributeAccessor.setValue(thing, "name", null); + assertNull(thing.getName()); + } + + @Test + public void testSingleValuedList() { + Thing thing = new Thing("old value"); + List newValue = Lists.newArrayList("new value"); + attributeAccessor.setValue(thing, "name", newValue); + assertEquals("new value", thing.getName()); + } + + @Test + public void testSingleValuedListEmpty() { + Thing thing = new Thing("old value"); + List newValue = Lists.newArrayList(); + attributeAccessor.setValue(thing, "name", newValue); + assertNull(thing.getName()); + } + + @Test + public void testSingleValuedListNull() { + Thing thing = new Thing("old value"); + List newValue = Lists.newArrayList(); + newValue.add(null); + attributeAccessor.setValue(thing, "name", newValue); + assertNull(thing.getName()); + } + + @Test + public void testSingleValuedListMultiple() { + Thing thing = new Thing("old value"); + List newValue = Lists.newArrayList(); + newValue.add("first string"); + newValue.add("second string"); + + IllegalArgumentException throwable = assertThrows(IllegalArgumentException.class, () -> attributeAccessor.setValue(thing, "name", newValue)); + assertEquals("Attribute name of object Thing does not support multiple values", throwable.getMessage()); + + assertEquals("old value", thing.getName()); + } + + @Test + public void testSingleValuedSet() { + Thing thing = new Thing("old value"); + Set newValue = Sets.newHashSet("new value"); + attributeAccessor.setValue(thing, "name", newValue); + assertEquals("new value", thing.getName()); + } + + @Test + public void testSingleValuedReadOnlyAttribute() { + Thing thing = new Thing(); + + IllegalArgumentException throwable = assertThrows(IllegalArgumentException.class, () -> attributeAccessor.setValue(thing, "four", 5)); + assertEquals("Attribute four of object Thing is a read-only attribute", throwable.getMessage()); + } + + @Test + public void testSingleValuedWrongType() { + Thing thing = new Thing("old value"); + + IllegalArgumentException throwable = assertThrows(IllegalArgumentException.class, () -> attributeAccessor.setValue(thing, "name", 12345)); + assertEquals("Value type java.lang.Integer is not a valid type for attribute name of object Thing", throwable.getMessage()); + + assertEquals("old value", thing.getName()); + } + + @Test + public void testSingleValuedObject() { + Group group = new Group(); + Thing thing = new Thing(); + attributeAccessor.setValue(group, "main_thing", thing); + assertSame(thing, group.getMainThing()); + } + + @Test + public void testSingleValuedException() { + AttributeAccessor attributeAccessor = new AttributeAccessor(new LocalClassInfoLookup()); + BrokenClass brokenClass = new BrokenClass(); + + RuntimeException throwable = assertThrows(RuntimeException.class, () -> attributeAccessor.setValue(brokenClass, "child", new BrokenClass())); + assertEquals("Error setting value on attribute child of object BrokenClass", throwable.getMessage()); + } + + @Test + public void testByteArray() { + Thing thing = new Thing(); + byte[] bytes = new byte[]{33, 42}; + attributeAccessor.setValue(thing, "data", bytes); + assertSame(bytes, thing.getData()); + } + + @Test + public void testByteArrayByte() { + Thing thing = new Thing(); + byte singleByte = 42; + + IllegalArgumentException throwable = assertThrows(IllegalArgumentException.class, () -> attributeAccessor.setValue(thing, "data", singleByte)); + assertEquals("Value type java.lang.Byte is not a valid type for attribute data of object Thing", throwable.getMessage()); + } + + @Test + public void testByteArrayIntArray() { + Thing thing = new Thing(); + int[] ints = new int[]{33, 42}; + + IllegalArgumentException throwable = assertThrows(IllegalArgumentException.class, () -> attributeAccessor.setValue(thing, "data", ints)); + assertEquals("Value type int[] is not a valid type for attribute data of object Thing", throwable.getMessage()); + } + + @Test + public void testUnknownAttribute() { + Thing thing = new Thing(); + + IllegalArgumentException throwable = assertThrows(IllegalArgumentException.class, () -> attributeAccessor.setValue(thing, "unknown", "test string")); + assertEquals("Attribute unknown of object Thing is not a valid attribute", throwable.getMessage()); + } + + @Test + public void testNonRmObject() { + Dummy dummy = new Dummy(); + + IllegalArgumentException throwable = assertThrows(IllegalArgumentException.class, () -> attributeAccessor.setValue(dummy, "value", 12345)); + assertEquals("Attribute value of object Dummy is not a valid attribute", throwable.getMessage()); + } + } +} diff --git a/openehr-rm/src/main/java/com/nedap/archie/rmutil/PathableUtil.java b/openehr-rm/src/main/java/com/nedap/archie/rmutil/PathableUtil.java index 79e68914e..cd918df8b 100644 --- a/openehr-rm/src/main/java/com/nedap/archie/rmutil/PathableUtil.java +++ b/openehr-rm/src/main/java/com/nedap/archie/rmutil/PathableUtil.java @@ -2,16 +2,17 @@ import com.nedap.archie.paths.PathSegment; import com.nedap.archie.paths.PathUtil; -import com.nedap.archie.query.RMObjectAttributes; import com.nedap.archie.rm.archetyped.Pathable; import com.nedap.archie.rminfo.ArchieRMInfoLookup; -import com.nedap.archie.rminfo.ModelInfoLookup; +import com.nedap.archie.rminfo.AttributeAccessor; import java.util.ArrayList; import java.util.Collection; import java.util.List; public class PathableUtil { + private static final AttributeAccessor attributeAccessor = new AttributeAccessor(ArchieRMInfoLookup.getInstance()); + /** * Determine the unique path segments from the toplevel-RM object. *

@@ -36,8 +37,7 @@ private static PathSegment getUniquePathSegment(Pathable pathable) { Pathable parent = pathable.getParent(); String parentAttributeName = unindexedPathSegment.getNodeName(); - ModelInfoLookup modelInfoLookup = ArchieRMInfoLookup.getInstance(); - Object attributeValue = RMObjectAttributes.getAttributeValueFromRMObject(parent, parentAttributeName, modelInfoLookup); + Object attributeValue = attributeAccessor.getValue(parent, parentAttributeName); Integer index = null; if (attributeValue instanceof Collection) { diff --git a/path-queries/src/main/java/com/nedap/archie/query/RMObjectAttributes.java b/path-queries/src/main/java/com/nedap/archie/query/RMObjectAttributes.java index afe8e5bd6..091905053 100644 --- a/path-queries/src/main/java/com/nedap/archie/query/RMObjectAttributes.java +++ b/path-queries/src/main/java/com/nedap/archie/query/RMObjectAttributes.java @@ -5,6 +5,10 @@ import java.lang.reflect.InvocationTargetException; +/** + * @deprecated Use {@link com.nedap.archie.rminfo.AttributeAccessor} + */ +@Deprecated public class RMObjectAttributes { /** * Get the value of an attribute of a RM object. @@ -13,7 +17,9 @@ public class RMObjectAttributes { * @param attributeName The name of the attribute. * @return The value of the attribute. * @throws IllegalArgumentException When no attribute exists with the given attribute name. + * @deprecated Use {@link com.nedap.archie.rminfo.AttributeAccessor#getValue(Object, String)} */ + @Deprecated public static Object getAttributeValueFromRMObject(Object object, String attributeName, ModelInfoLookup modelInfoLookup) { Object result; diff --git a/path-queries/src/main/java/com/nedap/archie/query/RMPathQuery.java b/path-queries/src/main/java/com/nedap/archie/query/RMPathQuery.java index 4f98b3a39..254c33090 100644 --- a/path-queries/src/main/java/com/nedap/archie/query/RMPathQuery.java +++ b/path-queries/src/main/java/com/nedap/archie/query/RMPathQuery.java @@ -5,13 +5,11 @@ import com.nedap.archie.aom.utils.AOMUtils; import com.nedap.archie.definitions.AdlCodeDefinitions; import com.nedap.archie.paths.PathSegment; +import com.nedap.archie.rminfo.AttributeAccessor; import com.nedap.archie.rminfo.ModelInfoLookup; -import com.nedap.archie.rminfo.RMAttributeInfo; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; @@ -46,152 +44,138 @@ public RMPathQuery(String query, boolean matchSpecialisedNodes) { //TODO: get diagnostic information about where the finder stopped in the path - could be very useful! public T find(ModelInfoLookup lookup, Object root) { + AttributeAccessor attributeAccessor = new AttributeAccessor(lookup); Object currentObject = root; - try { - for (PathSegment segment : pathSegments) { - if (currentObject == null) { - return null; + for (PathSegment segment : pathSegments) { + if (currentObject == null) { + return null; + } + if (!attributeAccessor.hasAttribute(currentObject, segment.getNodeName())) { + return null; + } + currentObject = attributeAccessor.getValue(currentObject, segment.getNodeName()); + if (currentObject == null) { + return null; + } + + String archetypeNodeIdFromObject = lookup.getArchetypeNodeIdFromRMObject(currentObject); + if (currentObject instanceof Collection) { + Collection collection = (Collection) currentObject; + if (!segment.hasExpressions()) { + //TODO: check if this is correct + currentObject = collection; + } else { + currentObject = findRMObject(lookup, segment, collection); } - RMAttributeInfo attributeInfo = lookup.getAttributeInfo(currentObject.getClass(), segment.getNodeName()); - if (attributeInfo == null) { - return null; + } else if (archetypeNodeIdFromObject != null) { + + if (segment.hasExpressions()) { + if (segment.hasIdCode()) { + if (!archetypeNodeIdFromObject.equals(segment.getNodeId())) { + return null; + } + } else if (segment.hasNumberIndex()) { + int number = segment.getIndex(); + if (number != 1) { + return null; + } + } else if (segment.hasArchetypeRef()) { + //operational templates in RM Objects have their archetype node ID set to an archetype ref. That + //we support. Other things not so much + if (!archetypeNodeIdFromObject.equals(segment.getNodeId())) { + throw new IllegalArgumentException("cannot handle RM-queries with node names or archetype references yet"); + } + + } } - Method method = attributeInfo.getGetMethod(); - currentObject = method.invoke(currentObject); - if (currentObject == null) { + } else if (segment.hasNumberIndex()) { + int number = segment.getIndex(); + if (number != 1) { return null; } + } else { + //not a locatable, but that's fine + //in openehr, in archetypes everythign has node ids. Datavalues do not in the rm. a bit ugly if you ask + //me, but that's why there's no 'if there's a nodeId set, this won't match!' code here. + } + } + return (T) currentObject; + } + /** + * You will want to use RMQueryContext in many cases. For perforamnce reasons, this could still be useful + */ + public List findList(ModelInfoLookup lookup, Object root) { + AttributeAccessor attributeAccessor = new AttributeAccessor(lookup); + List currentObjects = Lists.newArrayList(new RMObjectWithPath(root, "/")); + for (PathSegment segment : pathSegments) { + if(currentObjects.isEmpty()){ + return Collections.emptyList(); + } + List newCurrentObjects = new ArrayList<>(); + + for(int i = 0; i < currentObjects.size(); i++) { + RMObjectWithPath currentObject = currentObjects.get(i); + Object currentRMObject = currentObject.getObject(); + if (!attributeAccessor.hasAttribute(currentRMObject, segment.getNodeName())) { + continue; + } + currentRMObject = attributeAccessor.getValue(currentRMObject, segment.getNodeName()); + String pathSeparator = "/"; + if(currentObject.getPath().endsWith("/")) { + pathSeparator = ""; + } + String newPath = currentObject.getPath() + pathSeparator + segment.getNodeName(); + + if (currentRMObject == null) { + continue; + } String archetypeNodeIdFromObject = lookup.getArchetypeNodeIdFromRMObject(currentObject); - if (currentObject instanceof Collection) { - Collection collection = (Collection) currentObject; + if (currentRMObject instanceof Collection) { + Collection collection = (Collection) currentRMObject; if (!segment.hasExpressions()) { - //TODO: check if this is correct - currentObject = collection; + addAllFromCollection(lookup, newCurrentObjects, collection, newPath); } else { - currentObject = findRMObject(lookup, segment, collection); + //TODO + newCurrentObjects.addAll(findRMObjectsWithPathCollection(lookup, segment, collection, newPath)); } } else if (archetypeNodeIdFromObject != null) { if (segment.hasExpressions()) { if (segment.hasIdCode()) { if (!archetypeNodeIdFromObject.equals(segment.getNodeId())) { - return null; + continue; } } else if (segment.hasNumberIndex()) { int number = segment.getIndex(); if (number != 1) { - return null; + continue; } } else if (segment.hasArchetypeRef()) { //operational templates in RM Objects have their archetype node ID set to an archetype ref. That //we support. Other things not so much if (!archetypeNodeIdFromObject.equals(segment.getNodeId())) { - throw new IllegalArgumentException("cannot handle RM-queries with node names or archetype references yet"); + continue; } } + newCurrentObjects.add(createRMObjectWithPath(lookup, currentRMObject, newPath)); } } else if (segment.hasNumberIndex()) { int number = segment.getIndex(); if (number != 1) { - return null; + continue; } } else { - //not a locatable, but that's fine + //The object does not have an archetypeNodeId //in openehr, in archetypes everythign has node ids. Datavalues do not in the rm. a bit ugly if you ask //me, but that's why there's no 'if there's a nodeId set, this won't match!' code here. + newCurrentObjects.add(createRMObjectWithPath(lookup, currentRMObject, newPath)); } } - return (T) currentObject; - } catch (InvocationTargetException e) { - throw new RuntimeException(e); - } catch (IllegalAccessException e) { - throw new RuntimeException(e); - } - } - - /** - * You will want to use RMQueryContext in many cases. For perforamnce reasons, this could still be useful - */ - public List findList(ModelInfoLookup lookup, Object root) { - List currentObjects = Lists.newArrayList(new RMObjectWithPath(root, "/")); - try { - for (PathSegment segment : pathSegments) { - if(currentObjects.isEmpty()){ - return Collections.emptyList(); - } - List newCurrentObjects = new ArrayList<>(); - - for(int i = 0; i < currentObjects.size(); i++) { - RMObjectWithPath currentObject = currentObjects.get(i); - Object currentRMObject = currentObject.getObject(); - RMAttributeInfo attributeInfo = lookup.getAttributeInfo(currentRMObject.getClass(), segment.getNodeName()); - if (attributeInfo == null) { - continue; - } - Method method = attributeInfo.getGetMethod(); - currentRMObject = method.invoke(currentRMObject); - String pathSeparator = "/"; - if(currentObject.getPath().endsWith("/")) { - pathSeparator = ""; - } - String newPath = currentObject.getPath() + pathSeparator + segment.getNodeName(); - - if (currentRMObject == null) { - continue; - } - String archetypeNodeIdFromObject = lookup.getArchetypeNodeIdFromRMObject(currentObject); - if (currentRMObject instanceof Collection) { - Collection collection = (Collection) currentRMObject; - if (!segment.hasExpressions()) { - addAllFromCollection(lookup, newCurrentObjects, collection, newPath); - } else { - //TODO - newCurrentObjects.addAll(findRMObjectsWithPathCollection(lookup, segment, collection, newPath)); - } - } else if (archetypeNodeIdFromObject != null) { - - if (segment.hasExpressions()) { - if (segment.hasIdCode()) { - if (!archetypeNodeIdFromObject.equals(segment.getNodeId())) { - continue; - } - } else if (segment.hasNumberIndex()) { - int number = segment.getIndex(); - if (number != 1) { - continue; - } - } else if (segment.hasArchetypeRef()) { - //operational templates in RM Objects have their archetype node ID set to an archetype ref. That - //we support. Other things not so much - if (!archetypeNodeIdFromObject.equals(segment.getNodeId())) { - continue; - } - - } - newCurrentObjects.add(createRMObjectWithPath(lookup, currentRMObject, newPath)); - } - } else if (segment.hasNumberIndex()) { - int number = segment.getIndex(); - if (number != 1) { - continue; - } - } else { - //The object does not have an archetypeNodeId - //in openehr, in archetypes everythign has node ids. Datavalues do not in the rm. a bit ugly if you ask - //me, but that's why there's no 'if there's a nodeId set, this won't match!' code here. - newCurrentObjects.add(createRMObjectWithPath(lookup, currentRMObject, newPath)); - } - } - currentObjects = newCurrentObjects; - } - return currentObjects; - } catch (InvocationTargetException e) { - throw new RuntimeException(e); - } catch (IllegalAccessException e) { - throw new RuntimeException(e); + currentObjects = newCurrentObjects; } + return currentObjects; } diff --git a/tools/src/main/java/com/nedap/archie/creation/RMObjectCreator.java b/tools/src/main/java/com/nedap/archie/creation/RMObjectCreator.java index 7d8661daa..512305e6b 100644 --- a/tools/src/main/java/com/nedap/archie/creation/RMObjectCreator.java +++ b/tools/src/main/java/com/nedap/archie/creation/RMObjectCreator.java @@ -11,8 +11,7 @@ import java.util.*; /** - * Utility to create Reference model objects based on their RM name. Also can set attribute values on RM Objects based - * on their RM Attribute name. + * Utility to create Reference model objects based on their RM name. * * Created by pieter.bos on 03/02/16. */ @@ -39,6 +38,10 @@ public T create(CObject constraint) { } } + /** + * @deprecated Use {@link com.nedap.archie.rminfo.AttributeAccessor#setValue(Object, String, Object)} + */ + @Deprecated public void set(Object object, String rmAttributeName, List values) { try { RMAttributeInfo attributeInfo = modelInfoLookup.getAttributeInfo(object.getClass(), rmAttributeName); @@ -69,6 +72,7 @@ public void set(Object object, String rmAttributeName, List values) { } + @Deprecated private void setSingleValuedAttribute(Object object, String rmAttributeName, List values, RMAttributeInfo attributeInfo) throws InvocationTargetException, IllegalAccessException { if(values == null || values.isEmpty()) { setField(object, attributeInfo, null); @@ -81,6 +85,7 @@ private void setSingleValuedAttribute(Object object, String rmAttributeName, Lis } } + @Deprecated private Object newInstance(RMAttributeInfo attributeInfo) throws InstantiationException, IllegalAccessException { if(attributeInfo.getType().equals(List.class)) { return new ArrayList<>(); @@ -93,6 +98,7 @@ private Object newInstance(RMAttributeInfo attributeInfo) throws InstantiationEx } } + @Deprecated private void setField(Object object, RMAttributeInfo field, Object value) throws InvocationTargetException, IllegalAccessException { Method setMethod = field.getSetMethod(); if(setMethod == null) { @@ -106,6 +112,10 @@ private void setField(Object object, RMAttributeInfo field, Object value) throws } } + /** + * @deprecated Use {@link com.nedap.archie.rminfo.AttributeAccessor#addValue(Object, String, Object)} + */ + @Deprecated public void addElementToList(Object object, RMAttributeInfo attributeInfo, Object element) { try { if(attributeInfo.getAddMethod() != null) { @@ -132,6 +142,10 @@ public void addElementToList(Object object, RMAttributeInfo attributeInfo, Objec } } + /** + * @deprecated Use {@link com.nedap.archie.rminfo.AttributeAccessor#addOrSetValue(Object, String, Object)} + */ + @Deprecated public void addElementToListOrSetSingleValues(Object object, String rmAttributeName, Object element) { RMAttributeInfo attributeInfo = this.modelInfoLookup.getAttributeInfo(object.getClass(), rmAttributeName); if(attributeInfo == null) { diff --git a/tools/src/main/java/com/nedap/archie/json/flat/FlatJsonGenerator.java b/tools/src/main/java/com/nedap/archie/json/flat/FlatJsonGenerator.java index 841f8293f..f2538027e 100644 --- a/tools/src/main/java/com/nedap/archie/json/flat/FlatJsonGenerator.java +++ b/tools/src/main/java/com/nedap/archie/json/flat/FlatJsonGenerator.java @@ -7,11 +7,11 @@ import com.nedap.archie.aom.terminology.ArchetypeTerm; import com.nedap.archie.base.OpenEHRBase; import com.nedap.archie.datetime.DateTimeSerializerFormatters; +import com.nedap.archie.rminfo.AttributeAccessor; import com.nedap.archie.rminfo.ModelInfoLookup; import com.nedap.archie.rminfo.RMAttributeInfo; import com.nedap.archie.rminfo.RMTypeInfo; -import java.lang.reflect.InvocationTargetException; import java.time.temporal.ChronoUnit; import java.time.temporal.Temporal; import java.time.temporal.TemporalAccessor; @@ -31,6 +31,7 @@ public class FlatJsonGenerator { private final ModelInfoLookup modelInfoLookup; + private final AttributeAccessor attributeAccessor; private final List ignoredAttributes; @@ -51,6 +52,7 @@ public class FlatJsonGenerator { */ public FlatJsonGenerator(ModelInfoLookup modelInfoLookup, FlatJsonFormatConfiguration config) { this.modelInfoLookup = modelInfoLookup; + this.attributeAccessor = new AttributeAccessor(modelInfoLookup); this.writePipesForPrimitiveTypes = config.isWritePipesForPrimitiveTypes(); this.humanReadableFormat = false;//TODO: this is quite a bit of work to do properly, so definately not doing this now. this.indexNotation = config.getIndexNotation(); @@ -127,12 +129,8 @@ private void buildPathsAndValuesInner(Map result, RMTypeInfo rmA continue; } } - try { - Object child = attributeInfo.getGetMethod().invoke(rmObject); - addAttribute(result, pathSoFar, rmObject, child, attributeName,null, cAttribute); - } catch (IllegalAccessException | InvocationTargetException e) { - throw new RuntimeException(e);//TODO: fine for now... - } + Object child = attributeAccessor.getValue(rmObject, attributeName); + addAttribute(result, pathSoFar, rmObject, child, attributeName,null, cAttribute); } } diff --git a/tools/src/main/java/com/nedap/archie/query/RMQueryContext.java b/tools/src/main/java/com/nedap/archie/query/RMQueryContext.java index e04101b24..d9fa70c45 100644 --- a/tools/src/main/java/com/nedap/archie/query/RMQueryContext.java +++ b/tools/src/main/java/com/nedap/archie/query/RMQueryContext.java @@ -1,7 +1,7 @@ package com.nedap.archie.query; +import com.nedap.archie.rminfo.AttributeAccessor; import com.nedap.archie.rminfo.ModelInfoLookup; -import com.nedap.archie.rminfo.RMAttributeInfo; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.w3c.dom.Document; @@ -19,7 +19,6 @@ import javax.xml.xpath.XPathConstants; import javax.xml.xpath.XPathExpressionException; import javax.xml.xpath.XPathFactory; -import java.lang.reflect.InvocationTargetException; import java.util.ArrayList; import java.util.List; @@ -34,7 +33,7 @@ public class RMQueryContext { private final XPathFactory xPathFactory; - private final ModelInfoLookup modelInfoLooup; + private final AttributeAccessor attributeAccessor; private Binder binder; private Document domForQueries; private Object rootNode; @@ -55,7 +54,7 @@ public class RMQueryContext { public RMQueryContext(ModelInfoLookup lookup, Object rootNode, JAXBContext jaxbContext) { try { this.rootNode = rootNode; - this.modelInfoLooup = lookup; + this.attributeAccessor = new AttributeAccessor(lookup); this.binder = jaxbContext.createBinder(); domForQueries = createBlankDOMDocument(true); @@ -129,12 +128,7 @@ private T getJAXBNode(Node node) { logger.error("trying to get a node without a parent"); return null; } - RMAttributeInfo attributeInfo = modelInfoLooup.getAttributeInfo(parent.getClass(), nodeName); - try { - return (T) attributeInfo.getGetMethod().invoke(parent); - } catch (IllegalAccessException | InvocationTargetException e) { - throw new RuntimeException(e); - } + return (T) attributeAccessor.getValue(parent, nodeName); } } diff --git a/tools/src/main/java/com/nedap/archie/rmobjectvalidator/RmTupleValidator.java b/tools/src/main/java/com/nedap/archie/rmobjectvalidator/RmTupleValidator.java index f35860830..f60290d45 100644 --- a/tools/src/main/java/com/nedap/archie/rmobjectvalidator/RmTupleValidator.java +++ b/tools/src/main/java/com/nedap/archie/rmobjectvalidator/RmTupleValidator.java @@ -1,20 +1,20 @@ package com.nedap.archie.rmobjectvalidator; import com.nedap.archie.aom.*; -import com.nedap.archie.query.RMObjectAttributes; import com.nedap.archie.query.RMObjectWithPath; +import com.nedap.archie.rminfo.AttributeAccessor; import com.nedap.archie.rminfo.ModelInfoLookup; import java.util.ArrayList; import java.util.List; class RmTupleValidator { - private final ModelInfoLookup lookup; + private final AttributeAccessor attributeAccessor; private final ValidationHelper validationHelper; private final RmPrimitiveObjectValidator rmPrimitiveObjectValidator; RmTupleValidator(ModelInfoLookup lookup, ValidationHelper validationHelper, RmPrimitiveObjectValidator rmPrimitiveObjectValidator) { - this.lookup = lookup; + this.attributeAccessor = new AttributeAccessor(lookup); this.validationHelper = validationHelper; this.rmPrimitiveObjectValidator = rmPrimitiveObjectValidator; } @@ -56,7 +56,7 @@ private List validateSingleTuple(String pathSoFar, Ob for(CAttribute attribute:attributeTuple.getMembers()) { String attributeName = attribute.getRmAttributeName(); CPrimitiveObject cPrimitiveObject = tuple.getMembers().get(index); - Object value = RMObjectAttributes.getAttributeValueFromRMObject(rmObject, attributeName, lookup); + Object value = attributeAccessor.getValue(rmObject, attributeName); String path = pathSoFar + "/" + attributeName + "[" + cPrimitiveObject.getNodeId() + "]"; result.addAll(rmPrimitiveObjectValidator.validate_inner(value, path, cPrimitiveObject)); diff --git a/tools/src/main/java/com/nedap/archie/rmobjectvalidator/ValidationHelper.java b/tools/src/main/java/com/nedap/archie/rmobjectvalidator/ValidationHelper.java index 5d5ab4bdb..522719689 100644 --- a/tools/src/main/java/com/nedap/archie/rmobjectvalidator/ValidationHelper.java +++ b/tools/src/main/java/com/nedap/archie/rmobjectvalidator/ValidationHelper.java @@ -4,10 +4,9 @@ import com.nedap.archie.aom.CAttributeTuple; import com.nedap.archie.aom.CPrimitiveObject; import com.nedap.archie.aom.CPrimitiveTuple; +import com.nedap.archie.rminfo.AttributeAccessor; import com.nedap.archie.rminfo.ModelInfoLookup; -import com.nedap.archie.rminfo.RMAttributeInfo; -import java.lang.reflect.InvocationTargetException; import java.util.HashMap; /** @@ -15,10 +14,12 @@ */ public class ValidationHelper { private final ModelInfoLookup lookup; + private final AttributeAccessor attributeAccessor; private final PrimitiveObjectConstraintHelper primitiveObjectConstraintHelper; public ValidationHelper(ModelInfoLookup lookup, ValidationConfiguration validationConfiguration) { this.lookup = lookup; + this.attributeAccessor = new AttributeAccessor(lookup); this.primitiveObjectConstraintHelper = new PrimitiveObjectConstraintHelper(validationConfiguration); } @@ -84,15 +85,11 @@ boolean isValid(CAttributeTuple cAttributeTuple, Object value) { HashMap members = new HashMap<>(); for(CAttribute attribute:cAttributeTuple.getMembers()) { - RMAttributeInfo attributeInfo = lookup.getAttributeInfo(value.getClass(), attribute.getRmAttributeName()); - try { - if (attributeInfo != null && attributeInfo.getGetMethod() != null) { - members.put(attribute.getRmAttributeName(), attributeInfo.getGetMethod().invoke(value)); - } else { - //warn? throw exception? - } - } catch (InvocationTargetException | IllegalAccessException e) { - throw new RuntimeException(e); + String attributeName = attribute.getRmAttributeName(); + if (attributeAccessor.hasAttribute(value, attributeName)) { + members.put(attributeName, attributeAccessor.getValue(value, attributeName)); + } else { + //warn? throw exception? } } return isValid(cAttributeTuple, members); diff --git a/tools/src/main/java/com/nedap/archie/rmobjectvalidator/validations/RMTupleValidation.java b/tools/src/main/java/com/nedap/archie/rmobjectvalidator/validations/RMTupleValidation.java index 696dffcb0..ea109e54d 100644 --- a/tools/src/main/java/com/nedap/archie/rmobjectvalidator/validations/RMTupleValidation.java +++ b/tools/src/main/java/com/nedap/archie/rmobjectvalidator/validations/RMTupleValidation.java @@ -1,8 +1,8 @@ package com.nedap.archie.rmobjectvalidator.validations; import com.nedap.archie.aom.*; -import com.nedap.archie.query.RMObjectAttributes; import com.nedap.archie.query.RMObjectWithPath; +import com.nedap.archie.rminfo.AttributeAccessor; import com.nedap.archie.rminfo.ModelInfoLookup; import com.nedap.archie.rmobjectvalidator.RMObjectValidationMessage; import com.nedap.archie.rmobjectvalidator.RMObjectValidationMessageIds; @@ -48,6 +48,7 @@ public static List validate(ModelInfoLookup lookup, C * This will check each attribute in the tuple individually to get more specific validation messages. */ private static List validateSingleTuple(ModelInfoLookup lookup, String pathSoFar, Object rmObject, CAttributeTuple attributeTuple) { + AttributeAccessor attributeAccessor = new AttributeAccessor(lookup); List result = new ArrayList<>(); CPrimitiveTuple tuple = attributeTuple.getTuples().get(0); @@ -56,7 +57,7 @@ private static List validateSingleTuple(ModelInfoLook for(CAttribute attribute:attributeTuple.getMembers()) { String attributeName = attribute.getRmAttributeName(); CPrimitiveObject cPrimitiveObject = tuple.getMembers().get(index); - Object value = RMObjectAttributes.getAttributeValueFromRMObject(rmObject, attributeName, lookup); + Object value = attributeAccessor.getValue(rmObject, attributeName); String path = pathSoFar + "/" + attributeName + "[" + cPrimitiveObject.getNodeId() + "]"; result.addAll(RMPrimitiveObjectValidation.validate_inner(lookup, value, path, cPrimitiveObject)); diff --git a/tools/src/main/java/com/nedap/archie/rules/evaluation/AssertionsFixer.java b/tools/src/main/java/com/nedap/archie/rules/evaluation/AssertionsFixer.java index 166ca264c..6924f536e 100644 --- a/tools/src/main/java/com/nedap/archie/rules/evaluation/AssertionsFixer.java +++ b/tools/src/main/java/com/nedap/archie/rules/evaluation/AssertionsFixer.java @@ -1,16 +1,15 @@ package com.nedap.archie.rules.evaluation; -import com.google.common.collect.Lists; import com.nedap.archie.aom.*; import com.nedap.archie.creation.RMObjectCreator; import com.nedap.archie.query.RMObjectWithPath; import com.nedap.archie.query.RMPathQuery; +import com.nedap.archie.rminfo.AttributeAccessor; import com.nedap.archie.rminfo.ModelInfoLookup; import com.nedap.archie.rminfo.RMAttributeInfo; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.lang.reflect.InvocationTargetException; import java.util.ArrayList; import java.util.HashMap; import java.util.List; @@ -24,17 +23,25 @@ public class AssertionsFixer { private static final Logger logger = LoggerFactory.getLogger(AssertionsFixer.class); - private final RMObjectCreator creator; private final RuleEvaluation ruleEvaluation; private final RMObjectCreator rmObjectCreator; private ModelInfoLookup modelInfoLookup; + private final AttributeAccessor attributeAccessor; + /** + * @deprecated Not intended for direct usage. Use RuleEvaluation instead. + */ + @Deprecated public AssertionsFixer(RuleEvaluation evaluation, RMObjectCreator creator) { - this.creator = creator; + this(evaluation); + } + + AssertionsFixer(RuleEvaluation evaluation) { this.ruleEvaluation = evaluation; this.modelInfoLookup = ruleEvaluation.getModelInfoLookup(); rmObjectCreator = new RMObjectCreator(evaluation.getModelInfoLookup()); + this.attributeAccessor = new AttributeAccessor(modelInfoLookup); } public Map fixSetPathAssertions(Archetype archetype, AssertionResult assertionResult) { @@ -63,15 +70,15 @@ public Map fixSetPathAssertions(Archetype archetype, AssertionRe throw new IllegalStateException("attribute " + lastPathSegment + " does not exist on type " + parent.getClass()); } if (value.getValue() == null) { - creator.set(parent, lastPathSegment, Lists.newArrayList(value.getValue())); + attributeAccessor.setValue(parent, lastPathSegment, value.getValue()); } else if (attributeInfo.getType().equals(Long.class) && value.getValue().getClass().equals(Double.class)) { Long convertedValue = ((Double) value.getValue()).longValue(); //TODO or should this round? - creator.set(parent, lastPathSegment, Lists.newArrayList(convertedValue)); + attributeAccessor.setValue(parent, lastPathSegment, convertedValue); } else if (attributeInfo.getType().equals(Double.class) && value.getValue().getClass().equals(Long.class)) { Double convertedValue = ((Long) value.getValue()).doubleValue(); //TODO or should this round? - creator.set(parent, lastPathSegment, Lists.newArrayList(convertedValue)); + attributeAccessor.setValue(parent, lastPathSegment, convertedValue); } else { - creator.set(parent, lastPathSegment, Lists.newArrayList(value.getValue())); + attributeAccessor.setValue(parent, lastPathSegment, value.getValue()); } result.putAll(modelInfoLookup.pathHasBeenUpdated(ruleEvaluation.getRMRoot(), archetype, pathOfParent, parent)); @@ -107,7 +114,7 @@ private void constructMissingStructure(Archetype archetype, String pathOfParent, Object newEmptyObject = null; newEmptyObject = constructEmptySimpleObject(newLastPathSegment, object, newEmptyObject); - creator.addElementToListOrSetSingleValues(object, newLastPathSegment, Lists.newArrayList(newEmptyObject)); + attributeAccessor.addOrSetValue(object, newLastPathSegment, newEmptyObject); ruleEvaluation.refreshQueryContext(); } else { CObject constraint = getCObjectFromResult(constraints); @@ -127,7 +134,7 @@ private void constructMissingStructure(Archetype archetype, String pathOfParent, attributeName = newLastPathSegment.substring(0, bracketIndex); } - creator.addElementToListOrSetSingleValues(object, attributeName, Lists.newArrayList(newEmptyObject)); + attributeAccessor.addOrSetValue(object, attributeName, newEmptyObject); ruleEvaluation.refreshQueryContext(); } @@ -202,18 +209,13 @@ private void removeObject(ObjectToRemove objectToRemove) { Object parent = objectToRemove.getParent(); Object object = objectToRemove.getObject(); - RMAttributeInfo attributeInfo = modelInfoLookup.getAttributeInfo(parent.getClass(), objectToRemove.getAttributeName()); - try { - Object attributeValue = attributeInfo.getGetMethod().invoke(parent); - if (attributeValue instanceof List) { - ((List) attributeValue).remove(object); - } else if (attributeValue == object) { - attributeInfo.getSetMethod().invoke(parent, (Object) null); - } else { - throw new IllegalStateException("Attribute value is not a list and not the object to remove"); - } - } catch (IllegalAccessException | InvocationTargetException e) { - throw new RuntimeException(e); + Object attributeValue = attributeAccessor.getValue(parent, objectToRemove.getAttributeName()); + if (attributeValue instanceof List) { + ((List) attributeValue).remove(object); + } else if (attributeValue == object) { + attributeAccessor.setValue(parent, objectToRemove.getAttributeName(), null); + } else { + throw new IllegalStateException("Attribute value is not a list and not the object to remove"); } } diff --git a/tools/src/main/java/com/nedap/archie/rules/evaluation/RuleEvaluation.java b/tools/src/main/java/com/nedap/archie/rules/evaluation/RuleEvaluation.java index b03e79c30..1066d9879 100644 --- a/tools/src/main/java/com/nedap/archie/rules/evaluation/RuleEvaluation.java +++ b/tools/src/main/java/com/nedap/archie/rules/evaluation/RuleEvaluation.java @@ -2,7 +2,6 @@ import com.google.common.collect.ArrayListMultimap; import com.nedap.archie.aom.Archetype; -import com.nedap.archie.creation.RMObjectCreator; import com.nedap.archie.query.RMObjectWithPath; import com.nedap.archie.query.RMQueryContext; import com.nedap.archie.rminfo.ModelInfoLookup; @@ -47,8 +46,6 @@ public class RuleEvaluation { private ModelInfoLookup modelInfoLookup; - private RMObjectCreator creator; - private final JAXBContext jaxbContext; private RMQueryContext rmQueryContext; private APathQueryCache queryCache = new APathQueryCache(); @@ -96,8 +93,7 @@ public RuleEvaluation(ModelInfoLookup modelInfoLookup, JAXBContext jaxbContext, private RuleEvaluation(ModelInfoLookup modelInfoLookup, ValidationConfiguration validationConfiguration, JAXBContext jaxbContext, Archetype archetype) { this.jaxbContext = jaxbContext; this.modelInfoLookup = modelInfoLookup; - this.creator = new RMObjectCreator(modelInfoLookup); - this.assertionsFixer = new AssertionsFixer(this, creator); + this.assertionsFixer = new AssertionsFixer(this); this.archetype = archetype; this.functionEvaluator = new FunctionEvaluator(); add(new VariableDeclarationEvaluator()); diff --git a/tools/src/test/java/com/nedap/archie/creation/RMObjectCreatorTest.java b/tools/src/test/java/com/nedap/archie/creation/RMObjectCreatorTest.java index 846748f51..142830d81 100644 --- a/tools/src/test/java/com/nedap/archie/creation/RMObjectCreatorTest.java +++ b/tools/src/test/java/com/nedap/archie/creation/RMObjectCreatorTest.java @@ -87,6 +87,7 @@ public void createUnknownType() { } @Test + @Deprecated public void setSingleValuedValue() { Element element = new Element(); DvBoolean booleanValue = new DvBoolean(); @@ -95,6 +96,7 @@ public void setSingleValuedValue() { } @Test + @Deprecated public void setSingleValuedValuePrimitive() { DvBoolean booleanValue = new DvBoolean(); creator.set(booleanValue, "value", Lists.newArrayList(true)); @@ -102,6 +104,7 @@ public void setSingleValuedValuePrimitive() { } @Test(expected = IllegalArgumentException.class) + @Deprecated public void setSingleValuedValueIncorrectly() { Element element = new Element(); DvBoolean booleanValue = new DvBoolean(); @@ -110,6 +113,7 @@ public void setSingleValuedValueIncorrectly() { } @Test(expected = IllegalArgumentException.class) + @Deprecated public void setSingleValuedValueUnknownArgument() { Element element = new Element(); DvBoolean booleanValue = new DvBoolean(); @@ -117,6 +121,7 @@ public void setSingleValuedValueUnknownArgument() { } @Test + @Deprecated public void setMultiValuedValue() { Cluster cluster = new Cluster(); Element element = new Element(); @@ -125,6 +130,7 @@ public void setMultiValuedValue() { } @Test + @Deprecated public void setMultiValuedValue2() { Cluster cluster = new Cluster(); Element element = new Element(); @@ -134,6 +140,7 @@ public void setMultiValuedValue2() { } @Test + @Deprecated public void addToListOrSetSingleValue() { Cluster cluster = new Cluster(); Element element = new Element(); @@ -144,6 +151,7 @@ public void addToListOrSetSingleValue() { } @Test + @Deprecated public void addToListOrSetSingleValue2() { Cluster cluster = new Cluster(); Element element = new Element(); @@ -155,6 +163,7 @@ public void addToListOrSetSingleValue2() { } @Test + @Deprecated public void addToListOrSetSingleValueWithSingleValue() { Element element = new Element(); DvBoolean booleanValue = new DvBoolean(); @@ -163,6 +172,7 @@ public void addToListOrSetSingleValueWithSingleValue() { } @Test + @Deprecated public void addToListOrSetSingleValueWithSingleValue2() { Element element = new Element(); DvBoolean booleanValue = new DvBoolean(); @@ -171,6 +181,7 @@ public void addToListOrSetSingleValueWithSingleValue2() { } @Test(expected = IllegalArgumentException.class) + @Deprecated public void addToListOrSetSingleValueWithSingleValueIncorrect() { Element element = new Element(); DvBoolean booleanValue = new DvBoolean(); diff --git a/tools/src/test/java/com/nedap/archie/query/RMObjectAttributesTest.java b/tools/src/test/java/com/nedap/archie/query/RMObjectAttributesTest.java index f9e641619..8ade2073c 100644 --- a/tools/src/test/java/com/nedap/archie/query/RMObjectAttributesTest.java +++ b/tools/src/test/java/com/nedap/archie/query/RMObjectAttributesTest.java @@ -23,6 +23,7 @@ import static com.nedap.archie.query.RMObjectAttributes.getAttributeValueFromRMObject; import static org.junit.Assert.assertSame; +@Deprecated public class RMObjectAttributesTest { private TestUtil testUtil; diff --git a/tools/src/test/java/com/nedap/archie/testutil/TestUtil.java b/tools/src/test/java/com/nedap/archie/testutil/TestUtil.java index 55e04ffde..21228970f 100644 --- a/tools/src/test/java/com/nedap/archie/testutil/TestUtil.java +++ b/tools/src/test/java/com/nedap/archie/testutil/TestUtil.java @@ -1,6 +1,5 @@ package com.nedap.archie.testutil; -import com.google.common.collect.Lists; import com.nedap.archie.adlparser.ADLParseException; import com.nedap.archie.adlparser.ADLParser; import com.nedap.archie.antlr.errors.ANTLRParserErrors; @@ -10,6 +9,7 @@ import com.nedap.archie.flattener.InMemoryFullArchetypeRepository; import com.nedap.archie.rm.RMObject; import com.nedap.archie.rminfo.ArchieRMInfoLookup; +import com.nedap.archie.rminfo.AttributeAccessor; import org.reflections.Reflections; import org.reflections.scanners.Scanners; import org.slf4j.Logger; @@ -34,6 +34,7 @@ public class TestUtil { private static final Logger logger = LoggerFactory.getLogger(TestUtil.class); private RMObjectCreator creator = new RMObjectCreator(ArchieRMInfoLookup.getInstance()); + private final AttributeAccessor attributeAccessor = new AttributeAccessor(ArchieRMInfoLookup.getInstance()); /** * Creates an empty RM Object, fully nested, one object per CObject found. @@ -61,10 +62,10 @@ public RMObject constructEmptyRMObject(CObject object) { } if(!children.isEmpty()) { if(attribute.isMultiple()) { - creator.set(result, attribute.getRmAttributeName(), children); + attributeAccessor.setValue(result, attribute.getRmAttributeName(), children); } else if(!children.isEmpty()){ //set the first possible result in case of multiple children for a single valued value - creator.set(result, attribute.getRmAttributeName(), Lists.newArrayList(children.get(0))); + attributeAccessor.setValue(result, attribute.getRmAttributeName(), children.get(0)); } } }