Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Opt 1.4 parser and converter #261

Open
wants to merge 38 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
22b3727
Fix CVEs by updating guava and jakarta json module
jelmerterwal Dec 24, 2020
4597cd3
First parts of an OPT14 parser
pieterbos Jan 3, 2021
fd0cd10
Parse domain specific types, add conversion config to archie-utils
pieterbos Jan 4, 2021
15f1f5e
Add conversion to 2.0 (well, partially, for some reason)
pieterbos Jan 4, 2021
cacd7bb
Set empty opt14 nodeids to null, to fix conversion
pieterbos Jan 4, 2021
9f9e132
One more step in converting opt 1.4
pieterbos Jan 4, 2021
014568e
More fixes
pieterbos Jan 5, 2021
d98df44
Merge branch 'master' into opt_parser
pieterbos Jul 14, 2021
72d26a3
Implement better node id specializer, make conversion actually work
pieterbos Jul 19, 2021
9256e36
Add validation to test, add ArchetypeTermFixer and make first convers…
pieterbos Jul 19, 2021
6810201
Fix javadoc error
pieterbos Jul 19, 2021
4a4fe87
Add more specialization cases, add occurences matches {0} or closed w…
pieterbos Jul 20, 2021
4ee2552
Convert most of the description fields
pieterbos Jul 20, 2021
9e4475c
Opt 1.4 conversion: partial untested default value support
pieterbos Jul 20, 2021
b36bf77
Add fully untested primitive default value converter
pieterbos Jul 20, 2021
76d1262
Switch to OPT xsd that is actually in use
pieterbos Jul 23, 2021
93fe353
Revert nearly all custom bindings for now - they don't work
pieterbos Jul 23, 2021
76e710c
First parse the entire OPT1.4 in OPT2, then convert to Template later…
pieterbos Jul 26, 2021
56e0584
Add the beginning of the TCONSTRAINT conversion, plus a test class
pieterbos Jul 26, 2021
5c77124
First default value conversion steps
pieterbos Jul 26, 2021
1ebda81
Convert more datavalue-types, some refactors
pieterbos Jul 27, 2021
d3ab70d
Add rather big test case - contains some archetype mismatches still
pieterbos Jul 27, 2021
47446cf
Convert annotations and occurrences in <constraints>
pieterbos Jul 30, 2021
2f2b327
Convert component ontologies
pieterbos Jul 30, 2021
0c4a359
Handle OPERATIONALTEMPLATE.ontology
pieterbos Jul 30, 2021
9c441b5
Convert constraint bindings and constraint definitions
pieterbos Jul 30, 2021
7e43777
Add vital signs OPT test
pieterbos Aug 16, 2021
58c9fae
Allow previous conversion log to be passed, refactor tests a bit
pieterbos Aug 16, 2021
70a35fd
Fix compile
pieterbos Aug 16, 2021
2becdc7
Fix archetype id rm model parsing
pieterbos Aug 17, 2021
48a0f1c
Add comment to why the no longer used DefaultValueConverter is still …
pieterbos Aug 19, 2021
3d69f92
Merge branch 'master' into opt_parser
pieterbos Sep 15, 2021
3b5805a
Convert <view> into rm_overlay + visibility, fix tests
pieterbos Sep 15, 2021
9ee2fbf
Support and name/value='' queries, refactor RM Path queries
pieterbos Sep 15, 2021
9745f57
Add combined name + archetype ref lookup to AOM Path queries - still …
pieterbos Sep 15, 2021
2b0dedd
Add converter for annotations/rm visibility paths in OPT. TODO: call,…
pieterbos Sep 17, 2021
792f3c9
OPT1.4: Add new test, support more CPrimitives conversion, support mo…
pieterbos Sep 21, 2021
3b1ca91
Fix rm overlay conversion, improve serialization in test
pieterbos Sep 21, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -453,7 +453,8 @@ The following features are experimental. This means its working or API will like
Starting from version 0.7, Archie can import ADL 1.4 files, and convert them to ADL 2. To do so, do the following:

```java
ADL14ConversionConfiguration conversionConfiguration = new ADL14ConversionConfiguration();
//this is the default configuration. You can implement your own if you want to
ADL14ConversionConfiguration conversionConfiguration = OpenEHRADL14ConversionConfiguration.getConfig();
ADL14Converter converter = new ADL14Converter(BuiltinReferenceModels.getMetaModels(), conversionConfiguration);

List<Archetype> archetypes = new ArrayList<>();
Expand Down Expand Up @@ -498,7 +499,7 @@ The conversion log can be serialized to a file for storage using Jackson, so it

### Conversion Configuration

You may have noticed an instance of `ADL14ConversionConfiguration` in the previous example. In this configuration the mapping from term codes as used in ADL 1.4 to term URIs as used in ADL 2 can be specified. See the `ConversionConfigForTest.java` file for an example on how this works, and how this can be serialized to a file, and the file `/tools/src/test/java/com/nedap/archie/adl14/configuration.json` for an example of a simple serialized configuration that contains sane defaults for snomed, loinc and openehr URIs.
You may have noticed an instance of `ADL14ConversionConfiguration` in the previous example. In this configuration the mapping from term codes as used in ADL 1.4 to term URIs as used in ADL 2 can be specified. The archie-utils package provides a default configuration in the class `OpenEHRADL14ConversionConfiguration`. It is possible to supply your own, see the default implementation on how this works, and how this can be serialized to a file, and the file `/archie-utils/src/main/resources/adl14conversionconfiguration.json` for an example of a simple serialized configuration that contains sane defaults for snomed, loinc and openehr URIs.

If you leave the configuration empty, the converter will fall back to a default URI conversion.

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@ public class ADL14ConversionConfiguration {
*/
private boolean applyDiff = true;

/** If true, allow empty node ids where specialisations occur. for OPT conversion */
private boolean allowEmptyNodeIdsForSpecializations = false;


/**
* ADL 1.4 contains no rm release version, 2 does. So one needs to be added. Set to the desired rm_release. Defaults to 1.1.0
Expand Down Expand Up @@ -64,6 +67,14 @@ public void setApplyDiff(boolean applyDiff) {
this.applyDiff = applyDiff;
}

public boolean isAllowEmptyNodeIdsForSpecializations() {
return allowEmptyNodeIdsForSpecializations;
}

public void setAllowEmptyNodeIdsForSpecializations(boolean allowEmptyNodeIdsForSpecializations) {
this.allowEmptyNodeIdsForSpecializations = allowEmptyNodeIdsForSpecializations;
}

public String getRmRelease() {
return rmRelease;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@ public class ADL14DescriptionConverter {

public void convert(Archetype archetype) {
ResourceDescription description = archetype.getDescription();
if(description == null) {
return;
}
description.setLicence(description.getOtherDetails().remove("licence"));
description.setOriginalNamespace(description.getOtherDetails().remove("original_namespace"));
description.setOriginalPublisher(description.getOtherDetails().remove("original_publisher"));
Expand Down
42 changes: 32 additions & 10 deletions aom/src/main/java/com/nedap/archie/adl14/ADL14NodeIDConverter.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,9 @@
import com.nedap.archie.adl14.log.ConvertedCodeResult;
import com.nedap.archie.adl14.log.CreatedCode;
import com.nedap.archie.adl14.log.ReasonForCodeCreation;
import com.nedap.archie.aom.Archetype;
import com.nedap.archie.aom.ArchetypeHRID;
import com.nedap.archie.aom.ArchetypeSlot;
import com.nedap.archie.aom.CArchetypeRoot;
import com.nedap.archie.aom.CAttribute;
import com.nedap.archie.aom.CComplexObject;
import com.nedap.archie.aom.CComplexObjectProxy;
import com.nedap.archie.aom.CObject;
import com.nedap.archie.aom.CPrimitiveObject;
import com.nedap.archie.aom.*;
import com.nedap.archie.aom.primitives.CString;
import com.nedap.archie.aom.rmoverlay.RmOverlay;
import com.nedap.archie.aom.terminology.ArchetypeTerm;
import com.nedap.archie.aom.terminology.ValueSet;
import com.nedap.archie.aom.utils.AOMUtils;
Expand Down Expand Up @@ -102,10 +95,40 @@ public ADL2ConversionLog convert() {
generateMissingNodeIds(archetype.getDefinition());

convertTermDefinitions(archetype, convertedCodes);
convertAnnotations(archetype);
convertRmOverlay(archetype);
previousConversionApplier.removeCreatedUnusedTermCodesAndValueSets();
return new ADL2ConversionLog(/*convertedCodes*/ null, createdCodes, createdValueSets);
}

private void convertAnnotations(Archetype archetype) {
ResourceAnnotations converted = new ResourceAnnotations();
converted.setDocumentation(new LinkedHashMap<>());
if(archetype.getAnnotations() != null && archetype.getAnnotations().getDocumentation() != null) {
for(String language:archetype.getAnnotations().getDocumentation().keySet()) {
Map<String, Map<String, String>> convertedLanguageMap = new LinkedHashMap<>();
converted.getDocumentation().put(language, convertedLanguageMap);
Map<String, Map<String, String>> documentationMap = archetype.getAnnotations().getDocumentation().get(language);
for(String path:documentationMap.keySet()) {
convertedLanguageMap.put(convertPath(path), documentationMap.get(path));
}
}
}
archetype.setAnnotations(converted);
}

private void convertRmOverlay(Archetype archetype) {
RmOverlay convertedOverlay = new RmOverlay();
convertedOverlay.setRmVisibility(new LinkedHashMap<>());
if(archetype.getRmOverlay() != null && archetype.getRmOverlay().getRmVisibility() != null) {
for(String path:archetype.getRmOverlay().getRmVisibility().keySet()) {
convertedOverlay.getRmVisibility().put(convertPath(path), archetype.getRmOverlay().getRmVisibility().get(path));
}
}
archetype.setRmOverlay(convertedOverlay);
}


private void correctItemsCardinality(CObject cObject) {
for(CAttribute attribute:cObject.getAttributes()) {
if(attribute.getRmAttributeName().equalsIgnoreCase("items") && cObject.getRmTypeName().equalsIgnoreCase("CLUSTER") && attribute.getCardinality() != null) {
Expand Down Expand Up @@ -203,7 +226,6 @@ private void convertTermBindings(Archetype archetype) {
}

private void generateMissingNodeIds(CObject cObject) {

if(!(cObject instanceof CPrimitiveObject) && cObject.getNodeId() == null) {
String path = cObject.getPath();
if(archetype.getParentArchetypeId() != null && flatParentArchetype != null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,21 @@ private void convertCTerminologyCode(CTerminologyCode cTerminologyCode) {
URI uri = new ADL14ConversionUtil(converter.getConversionConfiguration()).convertToUri(termCode);
Map<String, URI> 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 if (cTerminologyCode.getConstraint().size() == 2) {
//still one code.
try {
termCode = TerminologyCode.createFromString(cTerminologyCode.getConstraint().get(0), null, cTerminologyCode.getConstraint().get(1));
//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<String, URI> 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));
Expand Down Expand Up @@ -197,6 +212,9 @@ private void convertCTerminologyCode(CTerminologyCode cTerminologyCode) {
}

private Map<String, URI> findOrCreateTermBindings(TerminologyCode termCode) {
if(termCode.getTerminologyId() == null) {
throw new IllegalArgumentException("terminology id cannot be null!");
}
Map<String, URI> termBindings = archetype.getTerminology().getTermBindings().get(termCode.getTerminologyId());

if(termBindings == null) {
Expand Down
Loading