com.nedap.archie.diff.ConstraintDifferentiator Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of tools Show documentation
Show all versions of tools Show documentation
tools that operate on the archie reference models and archetype object model
package com.nedap.archie.diff;
import com.nedap.archie.adlparser.modelconstraints.ModelConstraintImposer;
import com.nedap.archie.aom.*;
import com.nedap.archie.aom.utils.AOMUtils;
import com.nedap.archie.base.Cardinality;
import com.nedap.archie.base.MultiplicityInterval;
import com.nedap.archie.query.ComplexObjectProxyReplacement;
import javax.annotation.Nullable;
import java.util.ArrayList;
import java.util.List;
public class ConstraintDifferentiator {
private final Archetype flatParent;
private final ModelConstraintImposer constraintImposer;
ConstraintDifferentiator(ModelConstraintImposer constraintImposer, Archetype flatParent) {
this.flatParent = flatParent;
this.constraintImposer = constraintImposer;
}
public void removeUnspecializedConstraints(Archetype result, Archetype flatParent) {
removeUnspecializedDefinition(result.getDefinition(), flatParent.getDefinition());
}
// remove all attribute constraints (cardinality, existence) that are default
public void removeUnspecializedDefinition(CObject cObject, @Nullable CObject cObjectInParent) {
if(cObject instanceof CComplexObject) {
CComplexObject cComplexObject = (CComplexObject) cObject;
removeUnspecializedAttributeTuples(cObjectInParent, cComplexObject);
removeUnspecializedAttributes(cComplexObject, cObjectInParent);
removeUnspecializedOccurrences(cObject, cObjectInParent);
}
}
public void removeUnspecializedAttributes(CComplexObject cComplexObject, @Nullable CObject cObjectInParent) {
if(cObjectInParent instanceof CComplexObjectProxy) {
ComplexObjectProxyReplacement replacement = ComplexObjectProxyReplacement.getComplexObjectProxyReplacement((CComplexObjectProxy) cObjectInParent);
cObjectInParent = replacement.getReplacement();
}
List attributesToRemove = new ArrayList<>();
for(CAttribute attribute:cComplexObject.getAttributes()) {
//since it is flat, we can ignore differential paths here
if(attribute.getDifferentialPath() != null) {
throw new IllegalArgumentException("cannot handle differential paths in the differentiator - supply flattened archetype please");
}
if(attribute.getSocParent() != null) {
//part of a tuple. processed by tuples already
} else {
CAttribute attributeInParent = cObjectInParent == null ? null : cObjectInParent.getAttribute(attribute.getRmAttributeName());
removeUnspecializedCObjects(attribute, attributeInParent);
removeUnspecializedCardinality(attribute, attributeInParent);
removeUnspecializedExistence(attribute, attributeInParent);
removeDefaultCardinalityAndExistence(cComplexObject, attribute, attributeInParent);
if(shouldRemoveAttribute(attribute, attributeInParent)) {
attributesToRemove.add(attribute);
}
}
}
for(CAttribute attribute:attributesToRemove) {
cComplexObject.removeAttribute(attribute);
}
}
private void removeUnspecializedExistence(CAttribute attribute, CAttribute attributeInParent) {
if(attribute.getExistence() == null || attributeInParent == null || attributeInParent.getExistence() == null) {
return;
}
if(attribute.getExistence().equals(attributeInParent.getExistence())) {
attribute.setExistence(null);
}
}
public void removeUnspecializedCardinality(CAttribute attribute, CAttribute attributeInParent) {
if(attribute.getCardinality() == null || attributeInParent == null || attributeInParent.getCardinality() == null) {
return;
}
if(attribute.getCardinality().equals(attributeInParent.getCardinality())) {
attribute.setCardinality(null);
}
}
public void removeUnspecializedCObjects(CAttribute attribute, CAttribute attributeInParent) {
SiblingOrder anchor = null;
List cObjectsToRemove = new ArrayList<>();
for (CObject childCObject : attribute.getChildren()) {
if(childCObject.getSiblingOrder() != null) {
anchor = childCObject.getSiblingOrder();
}
@Nullable
CObject childCObjectInParent = findCObject(attributeInParent, childCObject);
removeUnspecializedDefinition(childCObject, childCObjectInParent);
removeUnspecializedOccurrences(childCObject, childCObjectInParent);
if(shouldRemoveUnspecializedCObject(childCObject, childCObjectInParent, anchor)) {
cObjectsToRemove.add(childCObject);
}
}
for(CObject toRemove:cObjectsToRemove) {
toRemove.getParent().removeChild(toRemove);
}
}
public void removeUnspecializedAttributeTuples(@Nullable CObject cObjectInParent, CComplexObject cComplexObject) {
List attributeTuplesToRemove = new ArrayList<>();
for (CAttributeTuple tuple : cComplexObject.getAttributeTuples()) {
if (shouldRemoveUnspecializedTuple(tuple, (CComplexObject) cObjectInParent)) {
attributeTuplesToRemove.add(tuple);
}
}
for (CAttributeTuple tuple : attributeTuplesToRemove) {
cComplexObject.removeAttributeTuple(tuple.getMemberNames());
}
}
private boolean shouldRemoveUnspecializedTuple(CAttributeTuple tuple, CComplexObject cObjectInParent) {
if(cObjectInParent == null) {
return false;
}
int indexOfMatchingAttributeTuple = cObjectInParent.getIndexOfMatchingAttributeTuple(tuple.getMemberNames());
if(indexOfMatchingAttributeTuple < 0) {
//it does not exist in parent, so keep it in diff
return false;
}
CAttributeTuple tupleInParent = cObjectInParent.getAttributeTuples().get(indexOfMatchingAttributeTuple);
if(tuple.getTuples().size() != tupleInParent.getTuples().size()) {
return false; //different tuples. keep in diff.
}
for(int i = 0; i < tuple.getTuples().size(); i++) {
CPrimitiveTuple primitiveTuple = tuple.getTuples().get(i);
CPrimitiveTuple primitiveTupleInParent = tupleInParent.getTuples().get(i);
for(int j = 0; j < primitiveTuple.getMembers().size(); j++) {
CPrimitiveObject, ?> member = primitiveTuple.getMember(j);
CPrimitiveObject, ?> memberInParent = primitiveTupleInParent.getMember(j);
if(!PrimitiveObjectEqualsChecker.isEqual(member, memberInParent)) {
return false; //at least one difference, keep
}
}
}
//exactly the same tuples. can be removed
return true;
}
private boolean shouldRemoveAttribute(CAttribute attribute, CAttribute attributeInParent) {
return attributeInParent != null
&& (attribute.getChildren().isEmpty()
&& attribute.getCardinality() == null
&& attribute.getExistence() == null);
}
private boolean shouldRemoveUnspecializedCObject(CObject childCObject, CObject childCObjectInParent, SiblingOrder anchor) {
if(anchor != null) {
//once a sibling order has been set, all elements after that should remain or it will mess up the anchoring
return false;
}
//since all occurrences and child objects have been removed if possible, if it has any left, keep this here
if(childCObject.getOccurrences() != null
|| childCObjectInParent == null
|| childCObject.getAttributes().size() > 0
|| childCObject.getSiblingOrder() != null) {
return false;
}
if(childCObject instanceof ArchetypeSlot && childCObjectInParent instanceof ArchetypeSlot) {
ArchetypeSlot slot = (ArchetypeSlot) childCObject;
ArchetypeSlot parentSlot = (ArchetypeSlot) childCObjectInParent;
if(slot.isClosed() != parentSlot.isClosed()) {
return false;
}
}
if(childCObject instanceof CArchetypeRoot) {
if(childCObjectInParent instanceof ArchetypeSlot) {
return false;
} else if(childCObjectInParent instanceof CArchetypeRoot) {
if (!((CArchetypeRoot) childCObject).getArchetypeRef().equals(((CArchetypeRoot) childCObjectInParent).getArchetypeRef())) {
return false;
}
}
}
if(childCObject instanceof CPrimitiveObject) {
if(PrimitiveObjectEqualsChecker.isEqual((CPrimitiveObject, ?>) childCObject, (CPrimitiveObject, ?>) childCObjectInParent)) {
return true;
}
} else {
//no children, no occurrences, child object is in parent. check specialization id
if(childCObject.specialisationDepth() == childCObjectInParent.specialisationDepth()) {
return true;
}
return false;
}
return false;
}
private void removeUnspecializedOccurrences(CObject cObject, CObject cObjectInParent) {
if(cObject.getOccurrences() == null || cObjectInParent == null || cObjectInParent.getOccurrences() == null) {
return;
}
if(cObject.getOccurrences().equals(cObjectInParent.getOccurrences())) {
cObject.setOccurrences(null);
}
}
private CObject findCObject(CAttribute attributeInParent, CObject cObjectInChild) {
if (attributeInParent == null) {
return null;
}
if(cObjectInChild instanceof CPrimitiveObject) {
int indexOfChildWithMatchingRmTypeName = attributeInParent.getIndexOfChildWithMatchingRmTypeName(cObjectInChild.getRmTypeName());
if(indexOfChildWithMatchingRmTypeName > -1) {
return attributeInParent.getChildren().get(indexOfChildWithMatchingRmTypeName);
}
return null;
} else {
String codeAtParentLevel = AOMUtils.codeAtLevel(cObjectInChild.getNodeId(), flatParent.specializationDepth());
return attributeInParent.getChild(codeAtParentLevel);
}
}
/**
* Remove the default cardinality and existence, if they are the same as in the reference model
*/
private void removeDefaultCardinalityAndExistence(CObject cObject, CAttribute attribute, CAttribute attributeInParent) {
CAttribute defaultAttribute = constraintImposer.getDefaultAttribute(cObject.getRmTypeName(), attribute.getRmAttributeName());
if(defaultAttribute != null) {
//if it is null, it will be caught by the validator because the property does not exist
if(attributeInParent != null && attributeInParent.getCardinality() != null) {
//parent cardinality set, so even if it is default, do not remove cardinality because it would fall back to potentially not default parent cardinality.
//It is removed by removeUnspecializedExistence instead
} else if (attribute.getCardinality() != null && defaultAttribute.getCardinality() != null) {
Cardinality cardinality = attribute.getCardinality();
Cardinality defaultCardinality = defaultAttribute.getCardinality();
if (cardinality.getInterval().equals(defaultCardinality.getInterval()) && cardinality.isOrdered() == defaultCardinality.isOrdered() && cardinality.isUnique() == defaultCardinality.isUnique()) {
attribute.setCardinality(null);
}
}
if(attributeInParent != null && attributeInParent.getExistence() != null) {
//parent existence set, so even if it is default, do not remove existence because it would fall back to potentially not default parent existence.
//It is removed by removeUnspecializedExistence instead
} else if (attribute.getExistence() != null && defaultAttribute.getExistence() != null) {
MultiplicityInterval existence = attribute.getExistence();
MultiplicityInterval defaultExistence = defaultAttribute.getExistence();
if(existence.equals(defaultExistence)) {
attribute.setExistence(null);
}
}
}
}
}