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 ead22a1eb..0e667efb3 100644 --- a/aom/src/main/java/com/nedap/archie/adl14/ADL14NodeIDConverter.java +++ b/aom/src/main/java/com/nedap/archie/adl14/ADL14NodeIDConverter.java @@ -396,8 +396,7 @@ private static void fixArchetypeSlotExpression(Expression expression) { Expression rightOperand = binary.getRightOperand(); if (rightOperand instanceof Constraint) { Constraint constraint = (Constraint) rightOperand; - if (constraint.getItem() != null && constraint.getItem().getConstraint() != null && !constraint.getItem().getConstraint().isEmpty() && - constraint.getItem() instanceof CString) { + if (constraint.getItem() != null && constraint.getItem() instanceof CString && constraint.getItem().getConstraint() != null && !((CString) constraint.getItem()).getConstraint().isEmpty()) { CString cString = (CString) constraint.getItem(); if (cString.getConstraint() == null || cString.getConstraint().isEmpty()) { return; diff --git a/aom/src/main/java/com/nedap/archie/adl14/ADL14TermConstraintConverter.java b/aom/src/main/java/com/nedap/archie/adl14/ADL14TermConstraintConverter.java index c76bffff4..d75d6dd97 100644 --- a/aom/src/main/java/com/nedap/archie/adl14/ADL14TermConstraintConverter.java +++ b/aom/src/main/java/com/nedap/archie/adl14/ADL14TermConstraintConverter.java @@ -1,6 +1,5 @@ package com.nedap.archie.adl14; -import com.google.common.collect.Lists; import com.nedap.archie.adl14.log.CreatedCode; import com.nedap.archie.adl14.log.ReasonForCodeCreation; import com.nedap.archie.aom.*; @@ -56,8 +55,8 @@ private void convert(CObject cObject) { for (CPrimitiveObject cPrimitiveObject : termCodes) { CTerminologyCode cTerminologyCode = (CTerminologyCode) cPrimitiveObject; convertCTerminologyCode(cTerminologyCode); - if(cTerminologyCode.getConstraint().size() == 1) { - String constraint = cTerminologyCode.getConstraint().get(0); + if(cTerminologyCode.getConstraint() != null) { + String constraint = cTerminologyCode.getConstraint(); if(AOMUtils.isValueCode(constraint)) { atCodes.add(constraint); } @@ -91,103 +90,132 @@ private void convert(CAttribute attribute) { } } + /** + * Converts a single-code {@link CTerminologyCode} constraint from ADL 1.4 to ADL 2 format. + * Multi-code constraints (stored via {@link CTerminologyCode#getPendingCodes()} by the ADL 1.4 parser) + * are delegated to {@link #convertMultiCodeTerminologyCode}. + *

+ * Three cases are handled: + *

+ */ private void convertCTerminologyCode(CTerminologyCode cTerminologyCode) { - if(cTerminologyCode.getConstraint() != null && !cTerminologyCode.getConstraint().isEmpty()) { - String firstConstraint = cTerminologyCode.getConstraint().get(0); - TerminologyCode termCode = TerminologyCode.createFromString(firstConstraint); - boolean isLocalCode = termCode.getTerminologyId() == null || termCode.getTerminologyId().equalsIgnoreCase("local"); - if(isLocalCode && AOMUtils.isValueCode(firstConstraint)) { - //local codes - if(cTerminologyCode.getConstraint().size() == 1) { - //do not create a value set, just convert the code - String newCode = converter.convertValueCode(firstConstraint); - converter.addConvertedCode(firstConstraint, newCode); - cTerminologyCode.setConstraint(Lists.newArrayList(newCode)); - } else { - Set localCodes = new LinkedHashSet<>(); - for(String code:cTerminologyCode.getConstraint()) { - String newCode = converter.convertValueCode(code); - converter.addConvertedCode(code, newCode); - localCodes.add(newCode); - } + List pendingCodes = cTerminologyCode.getPendingCodes(); + if (pendingCodes != null && !pendingCodes.isEmpty()) { + convertMultiCodeTerminologyCode(cTerminologyCode, pendingCodes); + return; + } - ValueSet valueSet = findOrCreateValueSet(cTerminologyCode.getArchetype(), localCodes, cTerminologyCode); - cTerminologyCode.setConstraint(Lists.newArrayList(valueSet.getId())); - } - } else if (isLocalCode && AOMUtils.isValueSetCode(termCode.getCodeString())) { - List newConstraint = new ArrayList<>(); - for(String constraint:cTerminologyCode.getConstraint()) { - TerminologyCode code = TerminologyCode.createFromString(constraint); - String newCode = converter.convertValueSetCode(code.getCodeString()); - converter.addConvertedCode(termCode.getCodeString(), newCode); - newConstraint.add(newCode); - } - cTerminologyCode.setConstraint(newConstraint); - - } else { - if (cTerminologyCode.getConstraint().size() == 1) { - try { - //do not create a value set, create a code plus binding to the old non-local code - URI uri = new ADL14ConversionUtil(converter.getConversionConfiguration()).convertToUri(termCode); - Map termBindingsMap = findOrCreateTermBindings(termCode); - - //TODO: check if this is a converted or old term binding - old is unusual, but could be possible! - String termBinding = findOrAddTermBindingAndCode(termCode, uri, termBindingsMap); - cTerminologyCode.setConstraint(Lists.newArrayList(termBinding)); - } catch (URISyntaxException e) { - //TODO - logger.error("error converting term", e); - } - } else { - String terminologyId = cTerminologyCode.getConstraint().get(0); - termCode = TerminologyCode.createFromString(terminologyId, null, cTerminologyCode.getConstraint().get(1)); - Map termBindingsMap = findOrCreateTermBindings(termCode); - List atCodes = new ArrayList<>(); - List constraints = new ArrayList<>(cTerminologyCode.getConstraint()); - cTerminologyCode.setConstraint(atCodes); - for(int i = 1; i < constraints.size(); i++) { - String constraint = constraints.get(i); - try { - if(constraint.startsWith("[") && constraint.endsWith("]")) { - TerminologyCode constraintCode = TerminologyCode.createFromString(constraint); - URI uri = new ADL14ConversionUtil(converter.getConversionConfiguration()).convertToUri(constraintCode); - atCodes.add(findOrAddTermBindingAndCode(constraintCode, uri, termBindingsMap)); - } else { - TerminologyCode constraintCode = new TerminologyCode(); - constraintCode.setTerminologyId(terminologyId); - constraintCode.setCodeString(constraint); - URI uri = new ADL14ConversionUtil(converter.getConversionConfiguration()).convertToUri(constraintCode); - atCodes.add(findOrAddTermBindingAndCode(constraintCode, uri, termBindingsMap)); - } + String constraint = cTerminologyCode.getConstraint(); + if (constraint == null) { + return; + } - } catch (URISyntaxException e) { - e.printStackTrace(); - } - } - ValueSet valueSet = findOrCreateValueSet(cTerminologyCode.getArchetype(), new LinkedHashSet<>(atCodes), cTerminologyCode); - cTerminologyCode.setConstraint(Lists.newArrayList(valueSet.getId())); + TerminologyCode termCode = TerminologyCode.createFromString(constraint); + boolean isLocalCode = termCode.getTerminologyId() == null + || termCode.getTerminologyId().equalsIgnoreCase("local"); - } + if (isLocalCode && AOMUtils.isValueCode(constraint)) { + // Single local at-code: convert it to its ADL 2 equivalent + String newCode = converter.convertValueCode(constraint); + converter.addConvertedCode(constraint, newCode); + cTerminologyCode.setConstraint(newCode); + } else if (isLocalCode && AOMUtils.isValueSetCode(termCode.getCodeString())) { + // Local value-set reference: convert the ac-code to its ADL 2 equivalent + String newCode = converter.convertValueSetCode(termCode.getCodeString()); + converter.addConvertedCode(termCode.getCodeString(), newCode); + cTerminologyCode.setConstraint(newCode); + } else { + // External terminology: create a term binding and generate a new at-code to reference it + try { + URI uri = new ADL14ConversionUtil(converter.getConversionConfiguration()).convertToUri(termCode); + Map termBindingsMap = findOrCreateTermBindings(termCode); + cTerminologyCode.setConstraint(findOrAddTermBindingAndCode(termCode, uri, termBindingsMap)); + } catch (URISyntaxException e) { + logger.error("error converting term", e); } - if(cTerminologyCode.getAssumedValue() != null) { - TerminologyCode assumedValue = cTerminologyCode.getAssumedValue(); - if(isLocalCode) { - String newCode = converter.convertValueCode(assumedValue.getCodeString()); - assumedValue.setCodeString(newCode); - assumedValue.setTerminologyId(null); - } else { - try { - Map termBindingsMap = findOrCreateTermBindings(assumedValue); - URI uri = new ADL14ConversionUtil(converter.getConversionConfiguration()).convertToUri(assumedValue); - assumedValue.setCodeString(findOrAddTermBindingAndCode(assumedValue, uri, termBindingsMap)); - assumedValue.setTerminologyId(null); - assumedValue.setTerminologyVersion(null); - } catch (URISyntaxException e) { - //TODO - e.printStackTrace(); - } + } + + convertAssumedValue(cTerminologyCode, isLocalCode); + } + + /** + * Converts a multi-code {@link CTerminologyCode} constraint from ADL 1.4 to ADL 2 format. + * In ADL 1.4, a constraint may reference multiple codes inline (e.g. + * {@code [local::at0001, at0002]} or {@code [snomed-ct::12345, 67890]}). ADL 2 represents + * these as a value set (ac-code), which this method creates. + *

+ * The {@code pendingCodes} list was populated by the ADL 1.4 parser: + *

    + *
  • For local codes: raw at-codes, e.g. {@code ["at0001", "at0002"]}.
  • + *
  • For external codes: full term code refs normalised by the parser, + * e.g. {@code ["[snomed-ct::12345]", "[snomed-ct::67890]"]}.
  • + *
+ * In both cases a value set is created and the constraint is set to its ac-code. + */ + private void convertMultiCodeTerminologyCode(CTerminologyCode cTerminologyCode, List pendingCodes) { + TerminologyCode firstCode = TerminologyCode.createFromString(pendingCodes.get(0)); + boolean isLocalCode = firstCode.getTerminologyId() == null + || firstCode.getTerminologyId().equalsIgnoreCase("local"); + + if (isLocalCode) { + // Convert each at-code and group them into a new value set + Set convertedCodes = new LinkedHashSet<>(); + for (String code : pendingCodes) { + String newCode = converter.convertValueCode(code); + converter.addConvertedCode(code, newCode); + convertedCodes.add(newCode); + } + ValueSet valueSet = findOrCreateValueSet(cTerminologyCode.getArchetype(), convertedCodes, cTerminologyCode); + cTerminologyCode.setConstraint(valueSet.getId()); + } else { + // Create a term binding for each external code, then group the resulting at-codes into a value set + Map termBindingsMap = findOrCreateTermBindings(firstCode); + List atCodes = new ArrayList<>(); + for (String code : pendingCodes) { + TerminologyCode termCode = TerminologyCode.createFromString(code); + try { + URI uri = new ADL14ConversionUtil(converter.getConversionConfiguration()).convertToUri(termCode); + atCodes.add(findOrAddTermBindingAndCode(termCode, uri, termBindingsMap)); + } catch (URISyntaxException e) { + logger.error("error converting term", e); } } + if (!atCodes.isEmpty()) { + ValueSet valueSet = findOrCreateValueSet(cTerminologyCode.getArchetype(), new LinkedHashSet<>(atCodes), cTerminologyCode); + cTerminologyCode.setConstraint(valueSet.getId()); + } + } + + convertAssumedValue(cTerminologyCode, isLocalCode); + } + + /** + * Converts the assumed value of a {@link CTerminologyCode} from ADL 1.4 to ADL 2 format, + * mirroring the logic used for the constraint itself. + */ + private void convertAssumedValue(CTerminologyCode cTerminologyCode, boolean isLocalCode) { + if (cTerminologyCode.getAssumedValue() == null) { + return; + } + TerminologyCode assumedValue = cTerminologyCode.getAssumedValue(); + if (isLocalCode) { + assumedValue.setCodeString(converter.convertValueCode(assumedValue.getCodeString())); + assumedValue.setTerminologyId(null); + } else { + try { + Map termBindingsMap = findOrCreateTermBindings(assumedValue); + URI uri = new ADL14ConversionUtil(converter.getConversionConfiguration()).convertToUri(assumedValue); + assumedValue.setCodeString(findOrAddTermBindingAndCode(assumedValue, uri, termBindingsMap)); + assumedValue.setTerminologyId(null); + assumedValue.setTerminologyVersion(null); + } catch (URISyntaxException e) { + logger.error("error converting term", e); + } } } @@ -250,9 +278,9 @@ private ValueSet findOrCreateValueSet(Archetype archetype, Set localCode CObject cObject = cAttributeInParent.getChildren().get(0); if(cObject instanceof CTerminologyCode) { CTerminologyCode termCodeInParent = (CTerminologyCode) cObject; - if(termCodeInParent.getConstraint() != null && !termCodeInParent.getConstraint().isEmpty()) { - if(termCodeInParent.getConstraint().get(0).startsWith("ac")) { - idInparent = termCodeInParent.getConstraint().get(0); + if(termCodeInParent.getConstraint() != null) { + if(termCodeInParent.getConstraint().startsWith("ac")) { + idInparent = termCodeInParent.getConstraint(); } } } diff --git a/aom/src/main/java/com/nedap/archie/adl14/PreviousConversionApplier.java b/aom/src/main/java/com/nedap/archie/adl14/PreviousConversionApplier.java index 473f6de6c..89870fca8 100644 --- a/aom/src/main/java/com/nedap/archie/adl14/PreviousConversionApplier.java +++ b/aom/src/main/java/com/nedap/archie/adl14/PreviousConversionApplier.java @@ -199,7 +199,8 @@ private Set gatherUsedValueSets(CAttribute attribute) { Set result = new LinkedHashSet<>(); for(CObject child:attribute.getChildren()) { if(child instanceof CTerminologyCode) { - for(String constraint:((CTerminologyCode) child).getConstraint()) { + String constraint = ((CTerminologyCode) child).getConstraint(); + if(constraint != null) { if(constraint.startsWith("ac")) { result.add(constraint); } @@ -215,7 +216,7 @@ private Set gatherUsedValueSets(CAttribute attribute) { for(CPrimitiveTuple primitiveTuple:tuple.getTuples()) { CTerminologyCode cTermCode = (CTerminologyCode) primitiveTuple.getMember(symbolIndex); if(cTermCode != null) { - atCodes.addAll(cTermCode.getConstraint()); + atCodes.addAll(cTermCode.getConstraintAsList()); } } } diff --git a/aom/src/main/java/com/nedap/archie/adl14/aom14/CDVOrdinalItem.java b/aom/src/main/java/com/nedap/archie/adl14/aom14/CDVOrdinalItem.java index 8f0f3ed99..771c80009 100644 --- a/aom/src/main/java/com/nedap/archie/adl14/aom14/CDVOrdinalItem.java +++ b/aom/src/main/java/com/nedap/archie/adl14/aom14/CDVOrdinalItem.java @@ -6,8 +6,6 @@ import com.nedap.archie.base.Interval; import com.nedap.archie.base.terminology.TerminologyCode; -import java.util.Arrays; - public class CDVOrdinalItem { private Integer value; @@ -35,7 +33,7 @@ public CTerminologyCode getSymbolAdl2() { return null; } CTerminologyCode result = new CTerminologyCode(); - result.setConstraint(Arrays.asList(symbol.toString())); + result.setConstraint(symbol.toString()); return result; } diff --git a/aom/src/main/java/com/nedap/archie/adl14/treewalkers/Adl14CComplexObjectParser.java b/aom/src/main/java/com/nedap/archie/adl14/treewalkers/Adl14CComplexObjectParser.java index 26f8cbfd0..2d2290808 100644 --- a/aom/src/main/java/com/nedap/archie/adl14/treewalkers/Adl14CComplexObjectParser.java +++ b/aom/src/main/java/com/nedap/archie/adl14/treewalkers/Adl14CComplexObjectParser.java @@ -206,7 +206,7 @@ private CObject parseNonPrimitiveObject(C_non_primitive_objectContext objectCont CTerminologyCode cCode = new CTerminologyCode(); TerminologyCode code = TerminologyCode.createFromString(ordinal_termContext.c_terminology_code().getText()); - cCode.addConstraint(code.getCodeString()); + cCode.setConstraint(code.getCodeString()); primitiveTuple.addMember(cValue); primitiveTuple.addMember(cCode); @@ -275,7 +275,7 @@ private void parseCDVQuantity(C_non_primitive_objectContext objectContext, CComp CAttribute property = new CAttribute("property"); CTerminologyCode code = new CTerminologyCode(); //will be converted later - code.addConstraint(cdvQuantity.getProperty().toString()); + code.setConstraint(cdvQuantity.getProperty().toString()); property.addChild(code); result.addAttribute(property); } diff --git a/aom/src/main/java/com/nedap/archie/adl14/treewalkers/Adl14PrimitivesConstraintParser.java b/aom/src/main/java/com/nedap/archie/adl14/treewalkers/Adl14PrimitivesConstraintParser.java index 2aa0ddfcb..be423ccde 100644 --- a/aom/src/main/java/com/nedap/archie/adl14/treewalkers/Adl14PrimitivesConstraintParser.java +++ b/aom/src/main/java/com/nedap/archie/adl14/treewalkers/Adl14PrimitivesConstraintParser.java @@ -17,6 +17,7 @@ import org.antlr.v4.runtime.CommonTokenStream; import org.antlr.v4.runtime.tree.TerminalNode; +import java.util.ArrayList; import java.util.List; /** @@ -103,23 +104,29 @@ public CTerminologyCode parseCTerminologyCode(Adl14Parser.C_terminology_codeCont //need to do parsing here because the lexer matched the entire term code ref TerminologyCode terminologyCode = TerminologyCode.createFromString(qualifiedTermCodeContext.TERM_CODE_REF().getText()); if (terminologyCode.getTerminologyId() != null && terminologyCode.getTerminologyId().equalsIgnoreCase("local")) { - result.addConstraint(terminologyCode.getCodeString()); + result.setConstraint(terminologyCode.getCodeString()); } else { //non-local term constraints. Just add the text here, it will be converted later - result.addConstraint(qualifiedTermCodeContext.TERM_CODE_REF().getText()); + result.setConstraint(qualifiedTermCodeContext.TERM_CODE_REF().getText()); } } else { String terminologyId = qualifiedTermCodeContext.identifier(0).getText(); if (terminologyId.equalsIgnoreCase("local")) { - //we need to create a value set. For now just add the constraint, the value set will come after - //the parser + List pendingCodes = new ArrayList<>(); for (int i = 1; i < qualifiedTermCodeContext.identifier().size(); i++) { - result.addConstraint(qualifiedTermCodeContext.identifier(i).getText()); + pendingCodes.add(qualifiedTermCodeContext.identifier(i).getText()); + } + if (!pendingCodes.isEmpty()) { + result.setPendingCodes(pendingCodes); } } else { - //non-local term constraints. Add the text here, will be converted later - for (int i = 0; i < qualifiedTermCodeContext.identifier().size(); i++) { - result.addConstraint(qualifiedTermCodeContext.identifier(i).getText()); + // Normalise to full term code refs so the converter can treat all pending codes uniformly + List pendingCodes = new ArrayList<>(); + for (int i = 1; i < qualifiedTermCodeContext.identifier().size(); i++) { + pendingCodes.add("[" + terminologyId + "::" + qualifiedTermCodeContext.identifier(i).getText() + "]"); + } + if (!pendingCodes.isEmpty()) { + result.setPendingCodes(pendingCodes); } } @@ -130,7 +137,7 @@ public CTerminologyCode parseCTerminologyCode(Adl14Parser.C_terminology_codeCont } else { //this is an AC-code. if(terminologyCodeContext.localTermCode().AC_CODE() != null) { - result.addConstraint(terminologyCodeContext.localTermCode().AC_CODE().getText()); + result.setConstraint(terminologyCodeContext.localTermCode().AC_CODE().getText()); } else { throw new RuntimeException("unknown terminology code format - this looks adl2 inside the adl 1.4 format?"); } diff --git a/aom/src/main/java/com/nedap/archie/adlparser/treewalkers/PrimitivesConstraintParser.java b/aom/src/main/java/com/nedap/archie/adlparser/treewalkers/PrimitivesConstraintParser.java index 534be0060..2e58b78dc 100644 --- a/aom/src/main/java/com/nedap/archie/adlparser/treewalkers/PrimitivesConstraintParser.java +++ b/aom/src/main/java/com/nedap/archie/adlparser/treewalkers/PrimitivesConstraintParser.java @@ -110,12 +110,12 @@ public CTerminologyCode parseCTerminologyCode(AdlParser.C_terminology_codeContex String assumedValueString = terminologyCodeContext.AT_CODE().getText(); assumedValue.setCodeString(assumedValueString); result.setAssumedValue(assumedValue); - result.addConstraint(assumedValue.getTerminologyIdString()); + result.setConstraint(assumedValue.getTerminologyIdString()); } else { if(terminologyCodeContext.AC_CODE() != null) { - result.addConstraint(terminologyCodeContext.AC_CODE().getText()); + result.setConstraint(terminologyCodeContext.AC_CODE().getText()); } else { - result.addConstraint(terminologyCodeContext.AT_CODE().getText()); + result.setConstraint(terminologyCodeContext.AT_CODE().getText()); } } diff --git a/aom/src/main/java/com/nedap/archie/aom/Archetype.java b/aom/src/main/java/com/nedap/archie/aom/Archetype.java index a9d6604da..c47611ad5 100644 --- a/aom/src/main/java/com/nedap/archie/aom/Archetype.java +++ b/aom/src/main/java/com/nedap/archie/aom/Archetype.java @@ -205,8 +205,8 @@ public Set getAllUsedCodes() { if(cObject instanceof CTerminologyCode) { CTerminologyCode terminologyCode = (CTerminologyCode) cObject; result.addAll(terminologyCode.getValueSetExpanded()); - if(!terminologyCode.getConstraint().isEmpty()) { - result.add(terminologyCode.getConstraint().get(0)); + if(terminologyCode.getConstraint() != null) { + result.add(terminologyCode.getConstraint()); } } for(CAttribute attribute:cObject.getAttributes()) { diff --git a/aom/src/main/java/com/nedap/archie/aom/CPrimitiveObject.java b/aom/src/main/java/com/nedap/archie/aom/CPrimitiveObject.java index c14458a19..31c65e886 100644 --- a/aom/src/main/java/com/nedap/archie/aom/CPrimitiveObject.java +++ b/aom/src/main/java/com/nedap/archie/aom/CPrimitiveObject.java @@ -1,6 +1,7 @@ package com.nedap.archie.aom; import com.fasterxml.jackson.annotation.JsonAlias; +import com.fasterxml.jackson.annotation.JsonIgnore; import com.nedap.archie.aom.utils.ConformanceCheckResult; import com.nedap.archie.archetypevalidator.ErrorType; import com.nedap.archie.rminfo.ArchieModelNamingStrategy; @@ -35,11 +36,10 @@ public abstract class CPrimitiveObject extends CDefinedOb public abstract void setAssumedValue(ValueType assumedValue); - public abstract List getConstraint(); + public abstract Constraint getConstraint(); - public abstract void setConstraint(List constraint); - - public abstract void addConstraint(Constraint constraint); + @JsonIgnore + public abstract List getConstraintAsList(); @JsonAlias("is_enumerated_type_constraint") @RMProperty("is_enumerated_type_constraint") @@ -74,10 +74,10 @@ public void setNodeId(String nodeId) { */ @Deprecated public boolean isValidValue(ValueType value) { - if(getConstraint().isEmpty()) { + if(getConstraintAsList().isEmpty()) { return true; } - for(Constraint constraint:getConstraint()) { + for(Object constraint:getConstraintAsList()) { if(Objects.equals(constraint, value)) { return true; } @@ -105,7 +105,7 @@ public String toString() { StringBuilder result = new StringBuilder(); result.append("{"); boolean first = true; - for(Constraint constraint:getConstraint()) { + for(Object constraint:getConstraintAsList()) { if(!first) { result.append(", "); } diff --git a/aom/src/main/java/com/nedap/archie/aom/primitives/CBoolean.java b/aom/src/main/java/com/nedap/archie/aom/primitives/CBoolean.java index ad02763d5..40f5911d0 100644 --- a/aom/src/main/java/com/nedap/archie/aom/primitives/CBoolean.java +++ b/aom/src/main/java/com/nedap/archie/aom/primitives/CBoolean.java @@ -20,7 +20,7 @@ */ @XmlAccessorType(XmlAccessType.FIELD) @XmlType(name="C_BOOLEAN") -public class CBoolean extends CPrimitiveObject { +public class CBoolean extends CPrimitiveObject, Boolean> { @XmlElement(name="assumed_value") @Nullable private Boolean assumedValue; @@ -43,12 +43,15 @@ public List getConstraint() { } @Override + public List getConstraintAsList() { + return getConstraint(); + } + public void setConstraint(List constraint) { this.constraint = constraint; } - @Override public void addConstraint(Boolean constraint) { this.constraint.add(constraint); } diff --git a/aom/src/main/java/com/nedap/archie/aom/primitives/COrdered.java b/aom/src/main/java/com/nedap/archie/aom/primitives/COrdered.java index 7bd3a4f60..170d76b99 100644 --- a/aom/src/main/java/com/nedap/archie/aom/primitives/COrdered.java +++ b/aom/src/main/java/com/nedap/archie/aom/primitives/COrdered.java @@ -7,12 +7,23 @@ import com.nedap.archie.base.Interval; import org.openehr.utils.message.I18n; +import java.util.List; import java.util.function.BiFunction; /** * Created by pieter.bos on 15/10/15. */ -public abstract class COrdered extends CPrimitiveObject, T> { +public abstract class COrdered extends CPrimitiveObject>, T> { + + public abstract List> getConstraint(); + + public List> getConstraintAsList() { + return getConstraint(); + } + + public abstract void setConstraint(List> constraint); + + public abstract void addConstraint(Interval constraint); @Override @Deprecated diff --git a/aom/src/main/java/com/nedap/archie/aom/primitives/CString.java b/aom/src/main/java/com/nedap/archie/aom/primitives/CString.java index 425ca8dcd..6ae793b49 100644 --- a/aom/src/main/java/com/nedap/archie/aom/primitives/CString.java +++ b/aom/src/main/java/com/nedap/archie/aom/primitives/CString.java @@ -22,7 +22,7 @@ */ @XmlType(name="C_STRING") @XmlAccessorType(XmlAccessType.FIELD) -public class CString extends CPrimitiveObject { +public class CString extends CPrimitiveObject, String> { @XmlElement(name="assumed_value") @Nullable @@ -53,11 +53,14 @@ public List getConstraint() { } @Override + public List getConstraintAsList() { + return getConstraint(); + } + public void setConstraint(List constraint) { this.constraint = constraint; } - @Override public void addConstraint(String constraint) { this.constraint.add(constraint); } diff --git a/aom/src/main/java/com/nedap/archie/aom/primitives/CTerminologyCode.java b/aom/src/main/java/com/nedap/archie/aom/primitives/CTerminologyCode.java index 3063e518c..bba7040f9 100644 --- a/aom/src/main/java/com/nedap/archie/aom/primitives/CTerminologyCode.java +++ b/aom/src/main/java/com/nedap/archie/aom/primitives/CTerminologyCode.java @@ -18,12 +18,14 @@ import jakarta.xml.bind.annotation.XmlAccessType; import jakarta.xml.bind.annotation.XmlAccessorType; import jakarta.xml.bind.annotation.XmlElement; +import jakarta.xml.bind.annotation.XmlTransient; import jakarta.xml.bind.annotation.XmlType; import org.openehr.utils.message.I18n; import javax.annotation.Nullable; import java.net.URI; import java.util.ArrayList; +import java.util.Collections; import java.util.List; import java.util.function.BiFunction; @@ -38,11 +40,16 @@ public class CTerminologyCode extends CPrimitiveObject @XmlElement(name="assumed_value") @Nullable private TerminologyCode assumedValue; - private List constraint = new ArrayList<>(); + private String constraint; @Nullable private ConstraintStatus constraintStatus; + /** Temporary storage for multi-code ADL 1.4 constraints during conversion. Never serialized. */ + @JsonIgnore + @XmlTransient + private List pendingCodes; + @Override public TerminologyCode getAssumedValue() { return assumedValue; @@ -54,18 +61,17 @@ public void setAssumedValue(TerminologyCode assumedValue) { } @Override - public List getConstraint() { + public String getConstraint() { return this.constraint; } @Override - public void setConstraint(List constraint) { - this.constraint = constraint; + public List getConstraintAsList() { + return getConstraint() == null ? Collections.emptyList() : Collections.singletonList(getConstraint()); } - @Override - public void addConstraint(String constraint) { - this.constraint.add(constraint); + public void setConstraint(String constraint) { + this.constraint = constraint; } public ConstraintStatus getConstraintStatus() { @@ -76,6 +82,16 @@ public void setConstraintStatus(ConstraintStatus constraintStatus) { this.constraintStatus = constraintStatus; } + @JsonIgnore + public List getPendingCodes() { + return pendingCodes; + } + + @JsonIgnore + public void setPendingCodes(List pendingCodes) { + this.pendingCodes = pendingCodes; + } + @JsonIgnore public boolean isConstraintRequired() { return getEffectiveConstraintStatus() == ConstraintStatus.REQUIRED; @@ -88,7 +104,7 @@ public ConstraintStatus getEffectiveConstraintStatus() { @Override @Deprecated public boolean isValidValue(TerminologyCode value) { - if(getConstraint().isEmpty()) { + if(getConstraint() == null) { return true; } if(isConstraintRequired()) { @@ -137,7 +153,7 @@ public List getTerms() { ArchetypeTerminology terminology = archetype.getTerminology(this); String language = ArchieLanguageConfiguration.getMeaningAndDescriptionLanguage(); String defaultLanguage = ArchieLanguageConfiguration.getDefaultMeaningAndDescriptionLanguage(); - for(String constraint:getConstraint()) { + if(constraint != null) { if(constraint.startsWith("at")) { ArchetypeTerm termDefinition = terminology.getTermDefinition(language, constraint); if(termDefinition == null) { @@ -182,7 +198,7 @@ private ArchetypeTerminology getTerminology() { public List getValueSetExpanded() { List result = new ArrayList<>(); ArchetypeTerminology terminology = getTerminology(); - for(String constraint:getConstraint()) { + if(constraint != null) { if(constraint.startsWith("at")) { result.add(constraint); } else if (constraint.startsWith("ac")) { @@ -231,11 +247,13 @@ public ConformanceCheckResult cConformsTo(CObject other, BiFunction valueSet = getValueSetExpanded(); List otherValueSet = otherCode.getValueSetExpanded(); - if(constraint.size() != 1) { - return ConformanceCheckResult.fails(ErrorType.VPOV, I18n.t("child CTerminology code contains more than one constraint, that is not valid. Constraints are: {0}", constraint)); + // A null constraint means unconstrained — an unconstrained parent accepts anything, + // and an unconstrained child trivially conforms to any parent. + if(otherCode.constraint == null) { + return ConformanceCheckResult.conforms(); } - if(otherCode.constraint.size() != 1) { - return ConformanceCheckResult.fails(ErrorType.VPOV, I18n.t("parent CTerminology code contains more than one constraint, that is not valid. Constraints are: {0}", constraint)); + if(constraint == null) { + return ConformanceCheckResult.conforms(); } if(!getEffectiveConstraintStatus().cConformsTo(otherCode.getEffectiveConstraintStatus()) ) { @@ -243,8 +261,8 @@ public ConformanceCheckResult cConformsTo(CObject other, BiFunction constraint = (Constraint) rightOperand; - if(constraint.getItem() != null && constraint.getItem().getConstraint() != null && !constraint.getItem().getConstraint().isEmpty() && - constraint.getItem() instanceof CString) { + if(constraint.getItem() != null && constraint.getItem() instanceof CString && constraint.getItem().getConstraint() != null && !((CString) constraint.getItem()).getConstraint().isEmpty()) { String pattern = ((CString) constraint.getItem()).getConstraint().get(0); if (pattern.startsWith("^") || pattern.startsWith("/")) { //regexp diff --git a/aom/src/main/java/com/nedap/archie/serializer/adl/constraints/CTerminologyCodeSerializer.java b/aom/src/main/java/com/nedap/archie/serializer/adl/constraints/CTerminologyCodeSerializer.java index d5e2242be..e071c0983 100644 --- a/aom/src/main/java/com/nedap/archie/serializer/adl/constraints/CTerminologyCodeSerializer.java +++ b/aom/src/main/java/com/nedap/archie/serializer/adl/constraints/CTerminologyCodeSerializer.java @@ -16,7 +16,7 @@ public CTerminologyCodeSerializer(ADLDefinitionSerializer serializer) { @Override public void serialize(CTerminologyCode cobj) { - if (!cobj.getConstraint().isEmpty()) { + if (cobj.getConstraint() != null) { if(cobj.getConstraintStatus() != null) { String constraintStatusString = null; switch(cobj.getConstraintStatus()) { @@ -39,7 +39,7 @@ public void serialize(CTerminologyCode cobj) { builder.append(" "); } builder.append("["); - String constraint = cobj.getConstraint().get(0); + String constraint = cobj.getConstraint(); builder.append(constraint); if (cobj.getAssumedValue() != null && cobj.getAssumedValue().getCodeString()!=null) { builder.append("; ").append(cobj.getAssumedValue().getCodeString()); @@ -49,8 +49,8 @@ public void serialize(CTerminologyCode cobj) { } public String getSimpleCommentText(CTerminologyCode cobj) { - if (!cobj.getConstraint().isEmpty()) { - String constraint = cobj.getConstraint().get(0); + if (cobj.getConstraint() != null) { + String constraint = cobj.getConstraint(); if(AOMUtils.isValueSetCode(constraint) || AOMUtils.isValueCode(constraint)) { return serializer.getTermText(cobj, constraint); } diff --git a/openehr-rm/src/main/java/com/nedap/archie/rminfo/UpdatedValueHandler.java b/openehr-rm/src/main/java/com/nedap/archie/rminfo/UpdatedValueHandler.java index 3ea7d117c..75b3377ef 100644 --- a/openehr-rm/src/main/java/com/nedap/archie/rminfo/UpdatedValueHandler.java +++ b/openehr-rm/src/main/java/com/nedap/archie/rminfo/UpdatedValueHandler.java @@ -69,8 +69,8 @@ private static Map fixDvOrdinalOrDvScale(Object rmObject, Archet int symbolIndex = socParent.getMemberIndex("symbol"); if (valueIndex != -1 && symbolIndex != -1) { for (CPrimitiveTuple tuple : socParent.getTuples()) { - if ((ordered instanceof DvOrdinal && tuple.getMembers().get(symbolIndex).getConstraint().get(0).equals(((DvOrdinal) ordered).getSymbol().getDefiningCode().getCodeString())) || - ordered instanceof DvScale && tuple.getMembers().get(symbolIndex).getConstraint().get(0).equals(((DvScale) ordered).getSymbol().getDefiningCode().getCodeString())) { + if ((ordered instanceof DvOrdinal && tuple.getMembers().get(symbolIndex).getConstraint().equals(((DvOrdinal) ordered).getSymbol().getDefiningCode().getCodeString())) || + ordered instanceof DvScale && tuple.getMembers().get(symbolIndex).getConstraint().equals(((DvScale) ordered).getSymbol().getDefiningCode().getCodeString())) { List> valueConstraint = (List>) tuple.getMembers().get(valueIndex).getConstraint(); if(valueConstraint.size() == 1) { Interval interval = valueConstraint.get(0); 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 da52929ab..05e734771 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 @@ -42,7 +42,8 @@ public void validate(CTerminologyCode cTerminologyCode) { //validate CTerminology codes int archetypeSpecializationDepth = archetype.specializationDepth(); - for(String constraint:cTerminologyCode.getConstraint()) { + String constraint = cTerminologyCode.getConstraint(); + if(constraint != null) { if(AOMUtils.isValueSetCode(constraint)) { int codeSpecializationDepth = AOMUtils.getSpecializationDepthFromCode(constraint); if(codeSpecializationDepth > archetypeSpecializationDepth) { 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 d61053c5a..de6d2e71a 100644 --- a/tools/src/main/java/com/nedap/archie/creation/ExampleJsonInstanceGenerator.java +++ b/tools/src/main/java/com/nedap/archie/creation/ExampleJsonInstanceGenerator.java @@ -447,7 +447,7 @@ protected Object generateTerminologyCode(CTerminologyCode child) { terminologyId.put("value", "local"); String termString = "term"; ArchetypeTerminology terminology = archetype.getTerminology(child); - if(child.getConstraint().isEmpty()) { + if(child.getConstraint() == null) { codeString = "term code"; CAttribute attribute = child.getParent(); CComplexObject parent = (CComplexObject) attribute.getParent(); @@ -456,7 +456,7 @@ protected Object generateTerminologyCode(CTerminologyCode child) { return potentialResult; } } else { - String constraint = child.getConstraint().get(0); + String constraint = child.getConstraint(); if(constraint.startsWith("ac")) { ValueSet valueSet = terminology.getValueSets().get(constraint); diff --git a/tools/src/main/java/com/nedap/archie/diff/UnconstrainedIntervalRemover.java b/tools/src/main/java/com/nedap/archie/diff/UnconstrainedIntervalRemover.java index 0052ddd70..ec8fa25ea 100644 --- a/tools/src/main/java/com/nedap/archie/diff/UnconstrainedIntervalRemover.java +++ b/tools/src/main/java/com/nedap/archie/diff/UnconstrainedIntervalRemover.java @@ -1,6 +1,7 @@ package com.nedap.archie.diff; import com.nedap.archie.aom.*; +import com.nedap.archie.aom.primitives.COrdered; import com.nedap.archie.base.Interval; import java.util.ArrayList; @@ -29,9 +30,11 @@ public static void removeUnconstrainedIntervals(CAttribute cAttribute) { for(CObject cObject:cAttribute.getChildren()) { if(cObject instanceof CComplexObject) { removeUnconstrainedIntervals((CComplexObject) cObject); - } else if (cObject instanceof CPrimitiveObject) { - CPrimitiveObject cPrimitiveObject = (CPrimitiveObject) cObject; - List constraint = cPrimitiveObject.getConstraint(); + } else if (cObject instanceof COrdered) { + // COrdered is used explicitly rather than CPrimitiveObject + getConstraintAsList(), + // because the list is mutated in-place and getConstraintAsList() does not guarantee a mutable list. + COrdered cOrdered = (COrdered) cObject; + List constraint = cOrdered.getConstraint(); List toRemove = new ArrayList<>(); for(Object i:constraint) { if(i instanceof Interval) { @@ -43,7 +46,7 @@ public static void removeUnconstrainedIntervals(CAttribute cAttribute) { } constraint.removeAll(toRemove); if(constraint.isEmpty()) { - cObjectsToRemove.add(cPrimitiveObject); + cObjectsToRemove.add(cOrdered); } } } diff --git a/tools/src/main/java/com/nedap/archie/rmobjectvalidator/PrimitiveObjectConstraintHelper.java b/tools/src/main/java/com/nedap/archie/rmobjectvalidator/PrimitiveObjectConstraintHelper.java index be0aa493c..74544c959 100644 --- a/tools/src/main/java/com/nedap/archie/rmobjectvalidator/PrimitiveObjectConstraintHelper.java +++ b/tools/src/main/java/com/nedap/archie/rmobjectvalidator/PrimitiveObjectConstraintHelper.java @@ -45,10 +45,10 @@ boolean isValidValue(CPrimitiveObject cPrimitiveObject } private boolean isValidValue_inner(CPrimitiveObject cPrimitiveObject, ValueType value) { - if(cPrimitiveObject.getConstraint().isEmpty()) { + if(cPrimitiveObject.getConstraintAsList().isEmpty()) { return true; } - for(Object constraint:cPrimitiveObject.getConstraint()) { + for(Object constraint:cPrimitiveObject.getConstraintAsList()) { if(Objects.equals(constraint, value)) { return true; } @@ -116,7 +116,7 @@ private boolean isValidValue(CTemporal cTemporal, T value) { } private boolean isValidValue(CTerminologyCode terminologyCode, TerminologyCode value) { - if(terminologyCode.getConstraint().isEmpty()) { + if(terminologyCode.getConstraint() == null) { return true; } if(terminologyCode.isConstraintRequired()) { diff --git a/tools/src/main/java/com/nedap/archie/rmobjectvalidator/RmPrimitiveObjectValidator.java b/tools/src/main/java/com/nedap/archie/rmobjectvalidator/RmPrimitiveObjectValidator.java index 8734aa227..0ebae8a99 100644 --- a/tools/src/main/java/com/nedap/archie/rmobjectvalidator/RmPrimitiveObjectValidator.java +++ b/tools/src/main/java/com/nedap/archie/rmobjectvalidator/RmPrimitiveObjectValidator.java @@ -41,7 +41,7 @@ List validate_inner(Object rmObject, String pathSoFar } private RMObjectValidationMessage createValidationMessage(Object value, String pathSoFar, CPrimitiveObject cobject) { - List constraint = cobject.getConstraint(); + List constraint = cobject.getConstraintAsList(); String message; if(constraint.size() == 1) { diff --git a/tools/src/main/java/com/nedap/archie/rmobjectvalidator/validations/RMPrimitiveObjectValidation.java b/tools/src/main/java/com/nedap/archie/rmobjectvalidator/validations/RMPrimitiveObjectValidation.java index 31b907d91..0e925668a 100644 --- a/tools/src/main/java/com/nedap/archie/rmobjectvalidator/validations/RMPrimitiveObjectValidation.java +++ b/tools/src/main/java/com/nedap/archie/rmobjectvalidator/validations/RMPrimitiveObjectValidation.java @@ -52,7 +52,7 @@ static List validate_inner(ModelInfoLookup lookup, Ob } private static RMObjectValidationMessage createValidationMessage(Object value, String pathSoFar, CPrimitiveObject cobject) { - List constraint = cobject.getConstraint(); + List constraint = cobject.getConstraintAsList(); String message; if(constraint.size() == 1) { diff --git a/tools/src/main/java/com/nedap/archie/rules/evaluation/FixableAssertionsChecker.java b/tools/src/main/java/com/nedap/archie/rules/evaluation/FixableAssertionsChecker.java index 368260f83..4af6e8027 100644 --- a/tools/src/main/java/com/nedap/archie/rules/evaluation/FixableAssertionsChecker.java +++ b/tools/src/main/java/com/nedap/archie/rules/evaluation/FixableAssertionsChecker.java @@ -127,7 +127,7 @@ private void handleMatches(AssertionResult assertionResult, int index, BinaryOpe if(rightOperand instanceof Constraint) { Constraint c = (Constraint) rightOperand; CPrimitiveObject object = c.getItem(); - List constraints = object.getConstraint(); + List constraints = object.getConstraintAsList(); if(constraints.size() != 1) { return; } 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 8ef00be52..f85a12cca 100644 --- a/tools/src/test/java/com/nedap/archie/adl14/ADL14ExternalTerminologyConversionTest.java +++ b/tools/src/test/java/com/nedap/archie/adl14/ADL14ExternalTerminologyConversionTest.java @@ -26,7 +26,7 @@ void terminologyBindingsConverted() throws IOException, ADLParseException { 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); + String atCode = termCodeConstraint.getConstraint(); Assertions.assertTrue(AOMUtils.isValueCode(atCode), "code must be a value, not a value set"); Assertions.assertEquals("Mass", converted.getTerminology().getTermDefinition("en", atCode).getText()); Assertions.assertEquals("Mass", converted.getTerminology().getTermDefinition("en", atCode).getDescription()); @@ -50,7 +50,7 @@ void twoTermbindingsInOneConstraint() throws Exception { Archetype converted = result.getConversionResults().get(0).getArchetype(); CTerminologyCode termCodeConstraint = converted.itemAtPath("/items/value/defining_code[1]"); - String acCode = termCodeConstraint.getConstraint().get(0); + String acCode = termCodeConstraint.getConstraint(); Assertions.assertTrue(AOMUtils.isValueSetCode(acCode), "the code should have been converted to a value set"); List atCodes = termCodeConstraint.getValueSetExpanded(); Assertions.assertEquals(2, atCodes.size(), atCodes.toString()); diff --git a/tools/src/test/java/com/nedap/archie/adlparser/DefinitionTest.java b/tools/src/test/java/com/nedap/archie/adlparser/DefinitionTest.java index 75299c45f..bd90a4e68 100644 --- a/tools/src/test/java/com/nedap/archie/adlparser/DefinitionTest.java +++ b/tools/src/test/java/com/nedap/archie/adlparser/DefinitionTest.java @@ -45,8 +45,7 @@ public void definition() throws Exception { CTerminologyCode code = (CTerminologyCode) categoryDefinition.getAttribute("defining_code").getChildren().get(0); assertNull(code.getAssumedValue()); - assertEquals(1, code.getConstraint().size()); - assertEquals("at17", code.getConstraint().get(0)); + assertEquals("at17", code.getConstraint()); } @Test 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 1f7789620..1b4bb98c0 100644 --- a/tools/src/test/java/com/nedap/archie/aom/TerminologyCodeConstraintsTest.java +++ b/tools/src/test/java/com/nedap/archie/aom/TerminologyCodeConstraintsTest.java @@ -68,7 +68,7 @@ public void noConstraint() { public void terminologyIdConstraint() { CTerminologyCode code = new CTerminologyCode(); code.setParent(new DummyRulesPrimitiveObjectParent(archetype)); - code.addConstraint("ac12"); + code.setConstraint("ac12"); assertTrue(code.isValidValue(TerminologyCode.createFromString("[ac12::at23]"))); assertTrue(code.isValidValue(TerminologyCode.createFromString("[ac12::at24]"))); assertFalse(code.isValidValue(TerminologyCode.createFromString("[ac12::at25]"))); @@ -79,7 +79,7 @@ public void terminologyIdConstraint() { public void externalTerminology() { CTerminologyCode code = new CTerminologyCode(); code.setParent(new DummyRulesPrimitiveObjectParent(archetype)); - code.addConstraint("ac12"); + code.setConstraint("ac12"); ValidationConfiguration.setFailOnUnknownTerminologyId(false); assertTrue(code.isValidValue(TerminologyCode.createFromString("[snomedct::72489423]"))); @@ -94,7 +94,7 @@ public void externalTerminology() { public void openEHRTerminology() { CTerminologyCode code = new CTerminologyCode(); code.setParent(new DummyRulesPrimitiveObjectParent(archetype)); - code.addConstraint("at9000"); + code.setConstraint("at9000"); code.setConstraintStatus(ConstraintStatus.REQUIRED); DvCodedText text = new DvCodedText(); @@ -114,7 +114,7 @@ public void openEHRTerminology() { public void terminologyCodeConstraint() { CTerminologyCode code = new CTerminologyCode(); code.setParent(new DummyRulesPrimitiveObjectParent(archetype)); - code.addConstraint("at23"); + code.setConstraint("at23"); assertTrue(code.isValidValue(TerminologyCode.createFromString("[ac12::at23]"))); assertTrue(code.isValidValue(TerminologyCode.createFromString("[ac13::at23]"))); assertFalse(code.isValidValue(TerminologyCode.createFromString("[ac13::at24]"))); @@ -125,7 +125,7 @@ public void dvCodedText() { //DV_CODED_TEXT can be constrained by a C_TERMINOLOGY_CONSTRAINT, according to lots of DV_ORDINAL usage in the CKM CTerminologyCode code = new CTerminologyCode(); code.setParent(new DummyRulesPrimitiveObjectParent(archetype)); - code.addConstraint("at23"); + code.setConstraint("at23"); termCodeAssertions(code); } @@ -134,7 +134,7 @@ public void requiredBindingStrength() { //DV_CODED_TEXT can be constrained by a C_TERMINOLOGY_CONSTRAINT, according to lots of DV_ORDINAL usage in the CKM CTerminologyCode code = new CTerminologyCode(); code.setParent(new DummyRulesPrimitiveObjectParent(archetype)); - code.addConstraint("at23"); + code.setConstraint("at23"); code.setConstraintStatus(ConstraintStatus.REQUIRED); termCodeAssertions(code); } @@ -144,7 +144,7 @@ public void otherBindingStrength() { //DV_CODED_TEXT can be constrained by a C_TERMINOLOGY_CONSTRAINT, according to lots of DV_ORDINAL usage in the CKM CTerminologyCode code = new CTerminologyCode(); code.setParent(new DummyRulesPrimitiveObjectParent(archetype)); - code.addConstraint("at23"); + code.setConstraint("at23"); Set nonRequiredBindings = EnumSet.of(ConstraintStatus.EXTENSIBLE, ConstraintStatus.EXAMPLE, ConstraintStatus.PREFERRED); for(ConstraintStatus status:nonRequiredBindings) { code.setConstraintStatus(status); 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 930bd190a..2141d067e 100644 --- a/tools/src/test/java/com/nedap/archie/json/AOMJacksonTest.java +++ b/tools/src/test/java/com/nedap/archie/json/AOMJacksonTest.java @@ -276,17 +276,30 @@ public void cDurationPeriodDuration() throws Exception { @Test public void cTerminologyCode() throws Exception { CTerminologyCode cTermCode = new CTerminologyCode(); - cTermCode.setConstraint(Lists.newArrayList("ac23")); + cTermCode.setConstraint("ac23"); cTermCode.setConstraintStatus(ConstraintStatus.PREFERRED); ObjectMapper objectMapper = JacksonUtil.getObjectMapper(ArchieJacksonConfiguration.createStandardsCompliant()); String json = objectMapper.writeValueAsString(cTermCode); assertTrue(json.contains("\"constraint_status\" : \"preferred\"")); + assertTrue(json.contains("\"constraint\" : \"ac23\"")); CTerminologyCode parsedTermCode = objectMapper.readValue(json, CTerminologyCode.class); assertEquals(cTermCode.getConstraint(), parsedTermCode.getConstraint()); assertEquals(ConstraintStatus.PREFERRED, parsedTermCode.getConstraintStatus()); } + @Test + public void backwardsCompatibilityCTerminologyCodeConstraintTypeFromJsonTest() throws Exception { + String json = "{\n" + + " \"rm_type_name\" : \"terminology_code\",\n" + + " \"node_id\" : \"id9999\",\n" + + " \"constraint\" : [ \"ac23\" ]\n" + + "}"; + ObjectMapper objectMapper = JacksonUtil.getObjectMapper(ArchieJacksonConfiguration.createStandardsCompliant()); + CTerminologyCode parsedTermCode = objectMapper.readValue(json, CTerminologyCode.class); + assertEquals("ac23", parsedTermCode.getConstraint()); + } + @Test public void rmOverlay() throws Exception { Archetype archetype = TestUtil.parseFailOnErrors("/com/nedap/archie/flattener/openEHR-EHR-OBSERVATION.to_flatten_parent_with_overlay.v1.0.0.adls"); 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 e6a442e58..25b501c29 100644 --- a/tools/src/test/java/com/nedap/archie/rmobjectvalidator/TerminologyCodeConstraintsTest.java +++ b/tools/src/test/java/com/nedap/archie/rmobjectvalidator/TerminologyCodeConstraintsTest.java @@ -76,7 +76,7 @@ public void noConstraint() { public void terminologyIdConstraint() { CTerminologyCode code = new CTerminologyCode(); code.setParent(new DummyRulesPrimitiveObjectParent(archetype)); - code.addConstraint("ac12"); + code.setConstraint("ac12"); assertTrue(primitiveObjectConstraintHelper.isValidValue(code, TerminologyCode.createFromString("[ac12::at23]"))); assertTrue(primitiveObjectConstraintHelper.isValidValue(code, TerminologyCode.createFromString("[ac12::at24]"))); assertFalse(primitiveObjectConstraintHelper.isValidValue(code, TerminologyCode.createFromString("[ac12::at25]"))); @@ -87,7 +87,7 @@ public void terminologyIdConstraint() { public void externalTerminology() { CTerminologyCode code = new CTerminologyCode(); code.setParent(new DummyRulesPrimitiveObjectParent(archetype)); - code.addConstraint("ac12"); + code.setConstraint("ac12"); assertTrue(primitiveObjectConstraintHelper.isValidValue(code, TerminologyCode.createFromString("[snomedct::72489423]"))); assertTrue(primitiveObjectConstraintHelper.isValidValue(code, TerminologyCode.createFromString("[anything::atall]"))); @@ -101,7 +101,7 @@ public void externalTerminology() { public void openEHRTerminology() { CTerminologyCode code = new CTerminologyCode(); code.setParent(new DummyRulesPrimitiveObjectParent(archetype)); - code.addConstraint("at9000"); + code.setConstraint("at9000"); code.setConstraintStatus(ConstraintStatus.REQUIRED); DvCodedText text = new DvCodedText(); @@ -121,7 +121,7 @@ public void openEHRTerminology() { public void IANATerminology() { CTerminologyCode code = new CTerminologyCode(); code.setParent(new DummyRulesPrimitiveObjectParent(archetype)); - code.addConstraint("at9001"); + code.setConstraint("at9001"); code.setConstraintStatus(ConstraintStatus.REQUIRED); DvCodedText text = new DvCodedText(); @@ -141,7 +141,7 @@ public void IANATerminology() { public void terminologyCodeConstraint() { CTerminologyCode code = new CTerminologyCode(); code.setParent(new DummyRulesPrimitiveObjectParent(archetype)); - code.addConstraint("at23"); + code.setConstraint("at23"); assertTrue(primitiveObjectConstraintHelper.isValidValue(code, TerminologyCode.createFromString("[ac12::at23]"))); assertTrue(primitiveObjectConstraintHelper.isValidValue(code, TerminologyCode.createFromString("[ac13::at23]"))); assertFalse(primitiveObjectConstraintHelper.isValidValue(code, TerminologyCode.createFromString("[ac13::at24]"))); @@ -152,7 +152,7 @@ public void dvCodedText() { //DV_CODED_TEXT can be constrained by a C_TERMINOLOGY_CONSTRAINT, according to lots of DV_ORDINAL usage in the CKM CTerminologyCode code = new CTerminologyCode(); code.setParent(new DummyRulesPrimitiveObjectParent(archetype)); - code.addConstraint("at23"); + code.setConstraint("at23"); termCodeAssertions(code); } @@ -161,7 +161,7 @@ public void requiredBindingStrength() { //DV_CODED_TEXT can be constrained by a C_TERMINOLOGY_CONSTRAINT, according to lots of DV_ORDINAL usage in the CKM CTerminologyCode code = new CTerminologyCode(); code.setParent(new DummyRulesPrimitiveObjectParent(archetype)); - code.addConstraint("at23"); + code.setConstraint("at23"); code.setConstraintStatus(ConstraintStatus.REQUIRED); termCodeAssertions(code); } @@ -171,7 +171,7 @@ public void otherBindingStrength() { //DV_CODED_TEXT can be constrained by a C_TERMINOLOGY_CONSTRAINT, according to lots of DV_ORDINAL usage in the CKM CTerminologyCode code = new CTerminologyCode(); code.setParent(new DummyRulesPrimitiveObjectParent(archetype)); - code.addConstraint("at23"); + code.setConstraint("at23"); Set nonRequiredBindings = EnumSet.of(ConstraintStatus.EXTENSIBLE, ConstraintStatus.EXAMPLE, ConstraintStatus.PREFERRED); for(ConstraintStatus status:nonRequiredBindings) { code.setConstraintStatus(status); 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 6b2bc0f83..c07700dcc 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 @@ -43,7 +43,7 @@ public void basic() throws Exception { CAttribute defining_code = archetype.itemAtPath("/category[id10]/defining_code"); CTerminologyCode termCode = (CTerminologyCode) defining_code.getChildren().get(0); - assertThat(termCode.getConstraint(), hasItem("at17")); + assertEquals("at17", termCode.getConstraint()); assertThat(archetype.getDescription().getDetails().get("en").getKeywords(), hasItems("ADL", "test")); assertThat(archetype.getTerminology().getTermBinding("openehr", "at17"), equalTo(URI.create("http://openehr.org/id/433"))); 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 635bcaec9..1a719eaf4 100644 --- a/tools/src/test/java/com/nedap/archie/xml/JAXBAOMTest.java +++ b/tools/src/test/java/com/nedap/archie/xml/JAXBAOMTest.java @@ -71,7 +71,7 @@ public void serializeCDuration() throws Exception { public void testCTerminologyCode() throws Exception { CTerminologyCode cTerminologyCode = new CTerminologyCode(); - cTerminologyCode.setConstraint(Lists.newArrayList("ac23")); + cTerminologyCode.setConstraint("ac23"); cTerminologyCode.setConstraintStatus(ConstraintStatus.PREFERRED); valueAttribute.addChild(cTerminologyCode); StringWriter writer = new StringWriter(); @@ -81,6 +81,7 @@ public void testCTerminologyCode() throws Exception { String xml = writer.toString(); assertThat(xml, xml.contains("preferred")); + assertThat(xml, xml.contains("ac23")); Unmarshaller unmarshaller = JAXBUtil.getArchieJAXBContext().createUnmarshaller(); Archetype unmarshalled = (Archetype) unmarshaller.unmarshal(new StringReader(xml));