All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.nedap.archie.flattener.OperationalTemplateCreator Maven / Gradle / Ivy

Go to download

tools that operate on the archie reference models and archetype object model

There is a newer version: 3.12.0
Show newest version
package com.nedap.archie.flattener;

import com.nedap.archie.aom.*;
import com.nedap.archie.aom.terminology.ArchetypeTerm;
import com.nedap.archie.aom.terminology.ArchetypeTerminology;
import com.nedap.archie.aom.terminology.ValueSet;
import com.nedap.archie.aom.utils.AOMUtils;
import com.nedap.archie.query.ComplexObjectProxyReplacement;

import java.util.*;

/**
 * Creates operational templates. Not to be used externally, use the Flattener with the right parameters to
 * create operational templates
 */
class OperationalTemplateCreator {

    private final Flattener flattener;

    OperationalTemplateCreator(Flattener flattener) {
        this.flattener = flattener;
    }

    public static OperationalTemplate createOperationalTemplate(Archetype archetype) {
        Archetype clone = archetype.clone(); //clone so we do not overwrite the parent archetype. never
        OperationalTemplate result = new OperationalTemplate();
        result.setArchetypeId((ArchetypeHRID) archetype.getArchetypeId().clone());
        result.setDefinition(clone.getDefinition());
        result.setDifferential(false);

        result.setRmRelease(clone.getRmRelease());
        result.setAdlVersion(clone.getAdlVersion());
        result.setTerminology(clone.getTerminology());
        result.setGenerated(true);
        result.setOtherMetaData(clone.getOtherMetaData());
        result.setRules(clone.getRules());
        result.setBuildUid(clone.getBuildUid());
        result.setDescription(clone.getDescription());
        result.setOriginalLanguage(clone.getOriginalLanguage());
        result.setTranslations(clone.getTranslations());
        result.setAnnotations(clone.getAnnotations());
        result.setRmOverlay(clone.getRmOverlay());

        return result;
    }

    public static void overrideArchetypeId(Archetype result, Archetype override) {
        result.setArchetypeId(override.getArchetypeId());
        result.setParentArchetypeId(override.getParentArchetypeId());
    }

    public void fillSlots(OperationalTemplate archetype) { //should this be OperationalTemplate?
        //TODO: closing archetype slots should be moved to AFTER including other archetypes
        closeArchetypeSlots(archetype);
        fillArchetypeRoots(archetype);
        fillComplexObjectProxies(archetype);
    }

    static void expandValueSets(OperationalTemplate operationalTemplate) {
        List terminologies = Arrays.asList(operationalTemplate.getTerminology());
       // terminologies.addAll(operationalTemplate.getComponentTerminologies().values());
        for(ArchetypeTerminology terminology:terminologies) {
            for(ValueSet valueSet:terminology.getValueSets().values()) {
                valueSet.setMembers(AOMUtils.getExpandedValueSetMembers(terminology.getValueSets(), valueSet));
            }
        }
    }

    /** Zero occurrences and existence constraint processing when creating OPT templates. Removes attributes */
    public void removeZeroOccurrencesConstraints(Archetype archetype) {
        Stack workList = new Stack<>();
        workList.push(archetype.getDefinition());
        while (!workList.isEmpty()) {
            CObject object = workList.pop();
            List attributesToRemove = new ArrayList<>();
            for (CAttribute attribute : object.getAttributes()) {
                if (attribute.getExistence() != null && attribute.getExistence().getUpper() == 0 && !attribute.getExistence().isUpperUnbounded()) {
                    attributesToRemove.add(attribute);
                } else {
                    List objectsToRemove = new ArrayList<>();
                    for (CObject child : attribute.getChildren()) {
                        if (!child.isAllowed()) {
                            objectsToRemove.add(child);
                        }
                        workList.push(child);
                    }
                    attribute.getChildren().removeAll(objectsToRemove);
                }

            }
            object.getAttributes().removeAll(attributesToRemove);
        }
    }

    /** Zero occurrences and existence constraint processing when creating OPT templates. Removes attributes */
    public void fillEmptyOccurrences(Archetype archetype) {
        Stack workList = new Stack<>();
        workList.push(archetype.getDefinition());
        while (!workList.isEmpty()) {
            CObject object = workList.pop();
            if( (object instanceof CComplexObject || object instanceof ArchetypeSlot || object instanceof CComplexObjectProxy)
                    && object.getOccurrences() == null) {
                object.setOccurrences(object.effectiveOccurrences(flattener.getMetaModels()::referenceModelPropMultiplicity));
            }
            for (CAttribute attribute : object.getAttributes()) {

                for (CObject child : attribute.getChildren()) {
                    workList.push(child);
                }
            }
        }
    }


    private void closeArchetypeSlots(OperationalTemplate archetype) {
        if(!getConfig().isCloseArchetypeSlots()) {
            return;
        }
        Stack workList = new Stack<>();
        workList.push(archetype.getDefinition());
        while(!workList.isEmpty()) {
            CObject object = workList.pop();
            for(CAttribute attribute:object.getAttributes()) {
                List toRemove = new ArrayList<>();
                for(CObject child:attribute.getChildren()) {
                    if(child instanceof ArchetypeSlot) { //use_archetype
                        if(((ArchetypeSlot) child).isClosed()) {
                            toRemove.add(child);
                        }
                    }
                    workList.push(child);
                }
                attribute.getChildren().removeAll(toRemove);
            }
        }
    }

    private void fillArchetypeRoots(OperationalTemplate result) {
        if(!getConfig().isFillArchetypeRoots()) {
            return;
        }
        Stack workList = new Stack<>();
        workList.push(result.getDefinition());
        while(!workList.isEmpty()) {
            CObject object = workList.pop();
            for(CAttribute attribute:object.getAttributes()) {
                for(CObject child:attribute.getChildren()) {
                    if(child instanceof CArchetypeRoot) { //use_archetype
                        fillArchetypeRoot((CArchetypeRoot) child, result);
                    }
                    workList.push(child);
                }
            }
        }
    }

    private void fillComplexObjectProxies(OperationalTemplate result) {
        if(!getConfig().isReplaceUseNode()) {
            return;
        }
        Stack workList = new Stack<>();
        workList.push(result.getDefinition());
        List replacements = new ArrayList<>();
        while(!workList.isEmpty()) {
            CObject object = workList.pop();
            for(CAttribute attribute:object.getAttributes()) {
                for(CObject child:attribute.getChildren()) {
                    if(child instanceof CComplexObjectProxy) { //use_node
                        ComplexObjectProxyReplacement possibleReplacement =
                                ComplexObjectProxyReplacement.getComplexObjectProxyReplacement((CComplexObjectProxy) child);
                        if(possibleReplacement != null) {
                            replacements.add(possibleReplacement);
                        } else {
                            throw new RuntimeException("cannot find target in CComplexObjectProxy");
                        }

                    }
                    workList.push(child);
                }
            }
        }
        for(ComplexObjectProxyReplacement replacement:replacements) {
            replacement.replace();
        }
    }

    /**
     * Only fillArchetypeRoot if this is not done yet
     */
    private void fillArchetypeRoot(CArchetypeRoot root, OperationalTemplate result) {
        if(flattener.getCreateOperationalTemplate() && ( root.getAttributes() == null || root.getAttributes().isEmpty()) ) {
            String archetypeRef = root.getArchetypeRef();
            String newArchetypeRef = archetypeRef;
            OverridingArchetypeRepository repository = flattener.getRepository();

            Archetype archetype = repository.getArchetype(archetypeRef);
            if(archetype instanceof TemplateOverlay){
                //we want to be able to check which archetype this is in the UI. If it's an overlay, that means retrieving the non-operational template
                //which is a hassle.
                //That's a problem. Is this the way to fix is?
                newArchetypeRef = archetype.getParentArchetypeId();
            }
            if (archetype == null) {
                if(getConfig().isFailOnMissingUsedArchetype()) {
                    throw new IllegalArgumentException("Archetype with reference :" + archetypeRef + " not found.");
                } else {
                    //just skip, as a form of graceful degradation.
                    return;
                }
            }
            archetype = flattener.getNewFlattener().flatten(archetype);

            //
            CComplexObject rootToFill = root;
            if(flattener.isUseComplexObjectForArchetypeSlotReplacement()) {
                rootToFill = archetype.getDefinition();
                root.getParent().replaceChild(root.getNodeId(), rootToFill);
            } else {
                rootToFill.setAttributes(archetype.getDefinition().getAttributes());
                rootToFill.setAttributeTuples(archetype.getDefinition().getAttributeTuples());
                rootToFill.setDefaultValue(archetype.getDefinition().getDefaultValue());
            }
            String newNodeId = archetype.getArchetypeId().getFullId();

            ArchetypeTerminology terminology = archetype.getTerminology();

            //The node id will be replaced from "id1" to something like "openEHR-EHR-COMPOSITION.template_overlay.v1.0.0
            //so store it in the terminology as well
            Map> termDefinitions = terminology.getTermDefinitions();

            for(String language: termDefinitions.keySet()) {
                Map translations = termDefinitions.get(language);
                translations.put(newNodeId, TerminologyFlattener.getTerm(terminology.getTermDefinitions(), language, archetype.getDefinition().getNodeId()));
            }

            //rootToFill.setNodeId(newNodeId);
            if(!flattener.isUseComplexObjectForArchetypeSlotReplacement()) {
                root.setArchetypeRef(newNodeId);
            }

            //todo: should we filter this?
            if(archetype instanceof OperationalTemplate) {
                OperationalTemplate template = (OperationalTemplate) archetype;
                //add all the component terminologies, otherwise we lose translation
                for(String subarchetypeId:template.getComponentTerminologies().keySet()) {
                    result.addComponentTerminology(subarchetypeId, template.getComponentTerminologies().get(subarchetypeId));
                }
            }

            result.addComponentTerminology(newNodeId, terminology);

            String prefix = archetype.getArchetypeId().getConceptId() + "_";
            flattener.getRulesFlattener().combineRules(archetype, root.getArchetype(), prefix, prefix, rootToFill.getPath(), false);
            flattener.getAnnotationsAndOverlaysFlattener().addAnnotationsWithPathPrefix(rootToFill.getPath(), archetype, result);
            flattener.getAnnotationsAndOverlaysFlattener().addVisibilityWithPathPrefix(rootToFill.getPath(), archetype, result);
            //todo: do we have to put something in the terminology extracts?
            //templateResult.addTerminologyExtract(child.getNodeId(), archetype.getTerminology().);
        }

    }

    private FlattenerConfiguration getConfig() {
        return flattener.getConfiguration();
    }




}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy